1 /*-------------------------------------------------------------------------
5 * Part of pg_stat_statements.c in PostgreSQL 10.
7 * Copyright (c) 2008-2020, PostgreSQL Global Development Group
9 *-------------------------------------------------------------------------
15 #include "access/hash.h"
16 #include "parser/scanner.h"
18 static void AppendJumble(pgssJumbleState *jstate,
19 const unsigned char *item, Size size);
20 static void JumbleQuery(pgssJumbleState *jstate, Query *query);
21 static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
22 static void JumbleExpr(pgssJumbleState *jstate, Node *node);
23 static void RecordConstLocation(pgssJumbleState *jstate, int location);
24 static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
25 int query_loc, int *query_len_p, int encoding);
26 static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
28 static int comp_location(const void *a, const void *b);
31 * AppendJumble: Append a value that is substantive in a given query to
35 AppendJumble(pgssJumbleState *jstate, const unsigned char *item, Size size)
37 unsigned char *jumble = jstate->jumble;
38 Size jumble_len = jstate->jumble_len;
41 * Whenever the jumble buffer is full, we hash the current contents and
42 * reset the buffer to contain just that hash value, thus relying on the
43 * hash to summarize everything so far.
49 if (jumble_len >= JUMBLE_SIZE)
53 start_hash = DatumGetUInt64(hash_any_extended(jumble,
55 memcpy(jumble, &start_hash, sizeof(start_hash));
56 jumble_len = sizeof(start_hash);
58 part_size = Min(size, JUMBLE_SIZE - jumble_len);
59 memcpy(jumble + jumble_len, item, part_size);
60 jumble_len += part_size;
64 jstate->jumble_len = jumble_len;
68 * Wrappers around AppendJumble to encapsulate details of serialization
69 * of individual local variable elements.
71 #define APP_JUMB(item) \
72 AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
73 #define APP_JUMB_STRING(str) \
74 AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)
77 * JumbleQuery: Selectively serialize the query tree, appending significant
78 * data to the "query jumble" while ignoring nonsignificant data.
80 * Rule of thumb for what to include is that we should ignore anything not
81 * semantically significant (such as alias names) as well as anything that can
82 * be deduced from child nodes (else we'd just be double-hashing that piece
86 JumbleQuery(pgssJumbleState *jstate, Query *query)
88 Assert(IsA(query, Query));
89 Assert(query->utilityStmt == NULL);
91 APP_JUMB(query->commandType);
92 /* resultRelation is usually predictable from commandType */
93 JumbleExpr(jstate, (Node *) query->cteList);
94 JumbleRangeTable(jstate, query->rtable);
95 JumbleExpr(jstate, (Node *) query->jointree);
96 JumbleExpr(jstate, (Node *) query->targetList);
97 JumbleExpr(jstate, (Node *) query->onConflict);
98 JumbleExpr(jstate, (Node *) query->returningList);
99 JumbleExpr(jstate, (Node *) query->groupClause);
100 JumbleExpr(jstate, (Node *) query->groupingSets);
101 JumbleExpr(jstate, query->havingQual);
102 JumbleExpr(jstate, (Node *) query->windowClause);
103 JumbleExpr(jstate, (Node *) query->distinctClause);
104 JumbleExpr(jstate, (Node *) query->sortClause);
105 JumbleExpr(jstate, query->limitOffset);
106 JumbleExpr(jstate, query->limitCount);
107 /* we ignore rowMarks */
108 JumbleExpr(jstate, query->setOperations);
112 * Jumble a range table
115 JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
121 RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
123 APP_JUMB(rte->rtekind);
124 switch (rte->rtekind)
127 APP_JUMB(rte->relid);
128 JumbleExpr(jstate, (Node *) rte->tablesample);
131 JumbleQuery(jstate, rte->subquery);
134 APP_JUMB(rte->jointype);
137 JumbleExpr(jstate, (Node *) rte->functions);
140 JumbleExpr(jstate, (Node *) rte->tablefunc);
143 JumbleExpr(jstate, (Node *) rte->values_lists);
148 * Depending on the CTE name here isn't ideal, but it's the
149 * only info we have to identify the referenced WITH item.
151 APP_JUMB_STRING(rte->ctename);
152 APP_JUMB(rte->ctelevelsup);
154 case RTE_NAMEDTUPLESTORE:
155 APP_JUMB_STRING(rte->enrname);
160 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
167 * Jumble an expression tree
169 * In general this function should handle all the same node types that
170 * expression_tree_walker() does, and therefore it's coded to be as parallel
171 * to that function as possible. However, since we are only invoked on
172 * queries immediately post-parse-analysis, we need not handle node types
173 * that only appear in planning.
175 * Note: the reason we don't simply use expression_tree_walker() is that the
176 * point of that function is to support tree walkers that don't care about
177 * most tree node types, but here we care about all types. We should complain
178 * about any unrecognized node type.
181 JumbleExpr(pgssJumbleState *jstate, Node *node)
188 /* Guard against stack overflow due to overly complex expressions */
192 * We always emit the node's NodeTag, then any additional fields that are
193 * considered significant, and then we recurse to any child nodes.
195 APP_JUMB(node->type);
197 switch (nodeTag(node))
201 Var *var = (Var *) node;
203 APP_JUMB(var->varno);
204 APP_JUMB(var->varattno);
205 APP_JUMB(var->varlevelsup);
210 Const *c = (Const *) node;
212 /* We jumble only the constant's type, not its value */
213 APP_JUMB(c->consttype);
214 /* Also, record its parse location for query normalization */
215 RecordConstLocation(jstate, c->location);
220 Param *p = (Param *) node;
222 APP_JUMB(p->paramkind);
223 APP_JUMB(p->paramid);
224 APP_JUMB(p->paramtype);
225 /* Also, track the highest external Param id */
226 if (p->paramkind == PARAM_EXTERN &&
227 p->paramid > jstate->highest_extern_param_id)
228 jstate->highest_extern_param_id = p->paramid;
233 Aggref *expr = (Aggref *) node;
235 APP_JUMB(expr->aggfnoid);
236 JumbleExpr(jstate, (Node *) expr->aggdirectargs);
237 JumbleExpr(jstate, (Node *) expr->args);
238 JumbleExpr(jstate, (Node *) expr->aggorder);
239 JumbleExpr(jstate, (Node *) expr->aggdistinct);
240 JumbleExpr(jstate, (Node *) expr->aggfilter);
245 GroupingFunc *grpnode = (GroupingFunc *) node;
247 JumbleExpr(jstate, (Node *) grpnode->refs);
252 WindowFunc *expr = (WindowFunc *) node;
254 APP_JUMB(expr->winfnoid);
255 APP_JUMB(expr->winref);
256 JumbleExpr(jstate, (Node *) expr->args);
257 JumbleExpr(jstate, (Node *) expr->aggfilter);
260 case T_SubscriptingRef:
262 SubscriptingRef *sbsref = (SubscriptingRef *) node;
264 JumbleExpr(jstate, (Node *) sbsref->refupperindexpr);
265 JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
266 JumbleExpr(jstate, (Node *) sbsref->refexpr);
267 JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
272 FuncExpr *expr = (FuncExpr *) node;
274 APP_JUMB(expr->funcid);
275 JumbleExpr(jstate, (Node *) expr->args);
280 NamedArgExpr *nae = (NamedArgExpr *) node;
282 APP_JUMB(nae->argnumber);
283 JumbleExpr(jstate, (Node *) nae->arg);
287 case T_DistinctExpr: /* struct-equivalent to OpExpr */
288 case T_NullIfExpr: /* struct-equivalent to OpExpr */
290 OpExpr *expr = (OpExpr *) node;
292 APP_JUMB(expr->opno);
293 JumbleExpr(jstate, (Node *) expr->args);
296 case T_ScalarArrayOpExpr:
298 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
300 APP_JUMB(expr->opno);
301 APP_JUMB(expr->useOr);
302 JumbleExpr(jstate, (Node *) expr->args);
307 BoolExpr *expr = (BoolExpr *) node;
309 APP_JUMB(expr->boolop);
310 JumbleExpr(jstate, (Node *) expr->args);
315 SubLink *sublink = (SubLink *) node;
317 APP_JUMB(sublink->subLinkType);
318 APP_JUMB(sublink->subLinkId);
319 JumbleExpr(jstate, (Node *) sublink->testexpr);
320 JumbleQuery(jstate, castNode(Query, sublink->subselect));
325 FieldSelect *fs = (FieldSelect *) node;
327 APP_JUMB(fs->fieldnum);
328 JumbleExpr(jstate, (Node *) fs->arg);
333 FieldStore *fstore = (FieldStore *) node;
335 JumbleExpr(jstate, (Node *) fstore->arg);
336 JumbleExpr(jstate, (Node *) fstore->newvals);
341 RelabelType *rt = (RelabelType *) node;
343 APP_JUMB(rt->resulttype);
344 JumbleExpr(jstate, (Node *) rt->arg);
349 CoerceViaIO *cio = (CoerceViaIO *) node;
351 APP_JUMB(cio->resulttype);
352 JumbleExpr(jstate, (Node *) cio->arg);
355 case T_ArrayCoerceExpr:
357 ArrayCoerceExpr *acexpr = (ArrayCoerceExpr *) node;
359 APP_JUMB(acexpr->resulttype);
360 JumbleExpr(jstate, (Node *) acexpr->arg);
361 JumbleExpr(jstate, (Node *) acexpr->elemexpr);
364 case T_ConvertRowtypeExpr:
366 ConvertRowtypeExpr *crexpr = (ConvertRowtypeExpr *) node;
368 APP_JUMB(crexpr->resulttype);
369 JumbleExpr(jstate, (Node *) crexpr->arg);
374 CollateExpr *ce = (CollateExpr *) node;
376 APP_JUMB(ce->collOid);
377 JumbleExpr(jstate, (Node *) ce->arg);
382 CaseExpr *caseexpr = (CaseExpr *) node;
384 JumbleExpr(jstate, (Node *) caseexpr->arg);
385 foreach(temp, caseexpr->args)
387 CaseWhen *when = lfirst_node(CaseWhen, temp);
389 JumbleExpr(jstate, (Node *) when->expr);
390 JumbleExpr(jstate, (Node *) when->result);
392 JumbleExpr(jstate, (Node *) caseexpr->defresult);
397 CaseTestExpr *ct = (CaseTestExpr *) node;
399 APP_JUMB(ct->typeId);
403 JumbleExpr(jstate, (Node *) ((ArrayExpr *) node)->elements);
406 JumbleExpr(jstate, (Node *) ((RowExpr *) node)->args);
408 case T_RowCompareExpr:
410 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
412 APP_JUMB(rcexpr->rctype);
413 JumbleExpr(jstate, (Node *) rcexpr->largs);
414 JumbleExpr(jstate, (Node *) rcexpr->rargs);
418 JumbleExpr(jstate, (Node *) ((CoalesceExpr *) node)->args);
422 MinMaxExpr *mmexpr = (MinMaxExpr *) node;
424 APP_JUMB(mmexpr->op);
425 JumbleExpr(jstate, (Node *) mmexpr->args);
428 case T_SQLValueFunction:
430 SQLValueFunction *svf = (SQLValueFunction *) node;
433 /* type is fully determined by op */
434 APP_JUMB(svf->typmod);
439 XmlExpr *xexpr = (XmlExpr *) node;
442 JumbleExpr(jstate, (Node *) xexpr->named_args);
443 JumbleExpr(jstate, (Node *) xexpr->args);
448 NullTest *nt = (NullTest *) node;
450 APP_JUMB(nt->nulltesttype);
451 JumbleExpr(jstate, (Node *) nt->arg);
456 BooleanTest *bt = (BooleanTest *) node;
458 APP_JUMB(bt->booltesttype);
459 JumbleExpr(jstate, (Node *) bt->arg);
462 case T_CoerceToDomain:
464 CoerceToDomain *cd = (CoerceToDomain *) node;
466 APP_JUMB(cd->resulttype);
467 JumbleExpr(jstate, (Node *) cd->arg);
470 case T_CoerceToDomainValue:
472 CoerceToDomainValue *cdv = (CoerceToDomainValue *) node;
474 APP_JUMB(cdv->typeId);
479 SetToDefault *sd = (SetToDefault *) node;
481 APP_JUMB(sd->typeId);
484 case T_CurrentOfExpr:
486 CurrentOfExpr *ce = (CurrentOfExpr *) node;
488 APP_JUMB(ce->cvarno);
490 APP_JUMB_STRING(ce->cursor_name);
491 APP_JUMB(ce->cursor_param);
494 case T_NextValueExpr:
496 NextValueExpr *nve = (NextValueExpr *) node;
498 APP_JUMB(nve->seqid);
499 APP_JUMB(nve->typeId);
502 case T_InferenceElem:
504 InferenceElem *ie = (InferenceElem *) node;
506 APP_JUMB(ie->infercollid);
507 APP_JUMB(ie->inferopclass);
508 JumbleExpr(jstate, ie->expr);
513 TargetEntry *tle = (TargetEntry *) node;
515 APP_JUMB(tle->resno);
516 APP_JUMB(tle->ressortgroupref);
517 JumbleExpr(jstate, (Node *) tle->expr);
522 RangeTblRef *rtr = (RangeTblRef *) node;
524 APP_JUMB(rtr->rtindex);
529 JoinExpr *join = (JoinExpr *) node;
531 APP_JUMB(join->jointype);
532 APP_JUMB(join->isNatural);
533 APP_JUMB(join->rtindex);
534 JumbleExpr(jstate, join->larg);
535 JumbleExpr(jstate, join->rarg);
536 JumbleExpr(jstate, join->quals);
541 FromExpr *from = (FromExpr *) node;
543 JumbleExpr(jstate, (Node *) from->fromlist);
544 JumbleExpr(jstate, from->quals);
547 case T_OnConflictExpr:
549 OnConflictExpr *conf = (OnConflictExpr *) node;
551 APP_JUMB(conf->action);
552 JumbleExpr(jstate, (Node *) conf->arbiterElems);
553 JumbleExpr(jstate, conf->arbiterWhere);
554 JumbleExpr(jstate, (Node *) conf->onConflictSet);
555 JumbleExpr(jstate, conf->onConflictWhere);
556 APP_JUMB(conf->constraint);
557 APP_JUMB(conf->exclRelIndex);
558 JumbleExpr(jstate, (Node *) conf->exclRelTlist);
562 foreach(temp, (List *) node)
564 JumbleExpr(jstate, (Node *) lfirst(temp));
568 foreach(temp, (List *) node)
570 APP_JUMB(lfirst_int(temp));
573 case T_SortGroupClause:
575 SortGroupClause *sgc = (SortGroupClause *) node;
577 APP_JUMB(sgc->tleSortGroupRef);
579 APP_JUMB(sgc->sortop);
580 APP_JUMB(sgc->nulls_first);
585 GroupingSet *gsnode = (GroupingSet *) node;
587 JumbleExpr(jstate, (Node *) gsnode->content);
592 WindowClause *wc = (WindowClause *) node;
594 APP_JUMB(wc->winref);
595 APP_JUMB(wc->frameOptions);
596 JumbleExpr(jstate, (Node *) wc->partitionClause);
597 JumbleExpr(jstate, (Node *) wc->orderClause);
598 JumbleExpr(jstate, wc->startOffset);
599 JumbleExpr(jstate, wc->endOffset);
602 case T_CommonTableExpr:
604 CommonTableExpr *cte = (CommonTableExpr *) node;
606 /* we store the string name because RTE_CTE RTEs need it */
607 APP_JUMB_STRING(cte->ctename);
608 APP_JUMB(cte->ctematerialized);
609 JumbleQuery(jstate, castNode(Query, cte->ctequery));
612 case T_SetOperationStmt:
614 SetOperationStmt *setop = (SetOperationStmt *) node;
617 APP_JUMB(setop->all);
618 JumbleExpr(jstate, setop->larg);
619 JumbleExpr(jstate, setop->rarg);
622 case T_RangeTblFunction:
624 RangeTblFunction *rtfunc = (RangeTblFunction *) node;
626 JumbleExpr(jstate, rtfunc->funcexpr);
631 TableFunc *tablefunc = (TableFunc *) node;
633 JumbleExpr(jstate, tablefunc->docexpr);
634 JumbleExpr(jstate, tablefunc->rowexpr);
635 JumbleExpr(jstate, (Node *) tablefunc->colexprs);
638 case T_TableSampleClause:
640 TableSampleClause *tsc = (TableSampleClause *) node;
642 APP_JUMB(tsc->tsmhandler);
643 JumbleExpr(jstate, (Node *) tsc->args);
644 JumbleExpr(jstate, (Node *) tsc->repeatable);
648 /* Only a warning, since we can stumble along anyway */
649 elog(WARNING, "unrecognized node type: %d",
650 (int) nodeTag(node));
656 * Record location of constant within query string of query tree
657 * that is currently being walked.
660 RecordConstLocation(pgssJumbleState *jstate, int location)
662 /* -1 indicates unknown or undefined location */
665 /* enlarge array if needed */
666 if (jstate->clocations_count >= jstate->clocations_buf_size)
668 jstate->clocations_buf_size *= 2;
669 jstate->clocations = (pgssLocationLen *)
670 repalloc(jstate->clocations,
671 jstate->clocations_buf_size *
672 sizeof(pgssLocationLen));
674 jstate->clocations[jstate->clocations_count].location = location;
675 /* initialize lengths to -1 to simplify fill_in_constant_lengths */
676 jstate->clocations[jstate->clocations_count].length = -1;
677 jstate->clocations_count++;
682 * Generate a normalized version of the query string that will be used to
683 * represent all similar queries.
685 * Note that the normalized representation may well vary depending on
686 * just which "equivalent" query is used to create the hashtable entry.
687 * We assume this is OK.
689 * If query_loc > 0, then "query" has been advanced by that much compared to
690 * the original string start, so we need to translate the provided locations
691 * to compensate. (This lets us avoid re-scanning statements before the one
692 * of interest, so it's worth doing.)
694 * *query_len_p contains the input string length, and is updated with
695 * the result string length on exit. The resulting string might be longer
696 * or shorter depending on what happens with replacement of constants.
698 * Returns a palloc'd string.
701 generate_normalized_query(pgssJumbleState *jstate, const char *query,
702 int query_loc, int *query_len_p, int encoding)
705 int query_len = *query_len_p;
707 norm_query_buflen, /* Space allowed for norm_query */
708 len_to_wrt, /* Length (in bytes) to write */
709 quer_loc = 0, /* Source query byte location */
710 n_quer_loc = 0, /* Normalized query byte location */
711 last_off = 0, /* Offset from start for previous tok */
712 last_tok_len = 0; /* Length (in bytes) of that tok */
715 * Get constants' lengths (core system only gives us locations). Note
716 * this also ensures the items are sorted by location.
718 fill_in_constant_lengths(jstate, query, query_loc);
721 * Allow for $n symbols to be longer than the constants they replace.
722 * Constants must take at least one byte in text form, while a $n symbol
723 * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
724 * could refine that limit based on the max value of n for the current
725 * query, but it hardly seems worth any extra effort to do so.
727 norm_query_buflen = query_len + jstate->clocations_count * 10;
729 /* Allocate result buffer */
730 norm_query = palloc(norm_query_buflen + 1);
732 for (i = 0; i < jstate->clocations_count; i++)
734 int off, /* Offset from start for cur tok */
735 tok_len; /* Length (in bytes) of that tok */
737 off = jstate->clocations[i].location;
738 /* Adjust recorded location if we're dealing with partial string */
741 tok_len = jstate->clocations[i].length;
744 continue; /* ignore any duplicates */
746 /* Copy next chunk (what precedes the next constant) */
747 len_to_wrt = off - last_off;
748 len_to_wrt -= last_tok_len;
750 Assert(len_to_wrt >= 0);
751 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
752 n_quer_loc += len_to_wrt;
755 * PG_HINT_PLAN: DON'T TAKE IN a6f22e8356 so that the designed behavior
758 /* And insert a '?' in place of the constant token */
759 norm_query[n_quer_loc++] = '?';
761 quer_loc = off + tok_len;
763 last_tok_len = tok_len;
767 * We've copied up until the last ignorable constant. Copy over the
768 * remaining bytes of the original query string.
770 len_to_wrt = query_len - quer_loc;
772 Assert(len_to_wrt >= 0);
773 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
774 n_quer_loc += len_to_wrt;
776 Assert(n_quer_loc <= norm_query_buflen);
777 norm_query[n_quer_loc] = '\0';
779 *query_len_p = n_quer_loc;
784 * Given a valid SQL string and an array of constant-location records,
785 * fill in the textual lengths of those constants.
787 * The constants may use any allowed constant syntax, such as float literals,
788 * bit-strings, single-quoted strings and dollar-quoted strings. This is
789 * accomplished by using the public API for the core scanner.
791 * It is the caller's job to ensure that the string is a valid SQL statement
792 * with constants at the indicated locations. Since in practice the string
793 * has already been parsed, and the locations that the caller provides will
794 * have originated from within the authoritative parser, this should not be
797 * Duplicate constant pointers are possible, and will have their lengths
798 * marked as '-1', so that they are later ignored. (Actually, we assume the
799 * lengths were initialized as -1 to start with, and don't change them here.)
801 * If query_loc > 0, then "query" has been advanced by that much compared to
802 * the original string start, so we need to translate the provided locations
803 * to compensate. (This lets us avoid re-scanning statements before the one
804 * of interest, so it's worth doing.)
806 * N.B. There is an assumption that a '-' character at a Const location begins
807 * a negative numeric constant. This precludes there ever being another
808 * reason for a constant to start with a '-'.
811 fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
814 pgssLocationLen *locs;
815 core_yyscan_t yyscanner;
816 core_yy_extra_type yyextra;
823 * Sort the records by location so that we can process them in order while
824 * scanning the query text.
826 if (jstate->clocations_count > 1)
827 qsort(jstate->clocations, jstate->clocations_count,
828 sizeof(pgssLocationLen), comp_location);
829 locs = jstate->clocations;
831 /* initialize the flex scanner --- should match raw_parser() */
832 yyscanner = scanner_init(query,
837 /* we don't want to re-emit any escape string warnings */
838 yyextra.escape_string_warning = false;
840 /* Search for each constant, in sequence */
841 for (i = 0; i < jstate->clocations_count; i++)
843 int loc = locs[i].location;
846 /* Adjust recorded location if we're dealing with partial string */
852 continue; /* Duplicate constant, ignore */
854 /* Lex tokens until we find the desired constant */
857 tok = core_yylex(&yylval, &yylloc, yyscanner);
859 /* We should not hit end-of-string, but if we do, behave sanely */
861 break; /* out of inner for-loop */
864 * We should find the token position exactly, but if we somehow
865 * run past it, work with that.
869 if (query[loc] == '-')
872 * It's a negative value - this is the one and only case
873 * where we replace more than a single token.
875 * Do not compensate for the core system's special-case
876 * adjustment of location to that of the leading '-'
877 * operator in the event of a negative constant. It is
878 * also useful for our purposes to start from the minus
879 * symbol. In this way, queries like "select * from foo
880 * where bar = 1" and "select * from foo where bar = -2"
881 * will have identical normalized query strings.
883 tok = core_yylex(&yylval, &yylloc, yyscanner);
885 break; /* out of inner for-loop */
889 * We now rely on the assumption that flex has placed a zero
890 * byte after the text of the current token in scanbuf.
892 locs[i].length = strlen(yyextra.scanbuf + loc);
893 break; /* out of inner for-loop */
897 /* If we hit end-of-string, give up, leaving remaining lengths -1 */
904 scanner_finish(yyscanner);
908 * comp_location: comparator for qsorting pgssLocationLen structs by location
911 comp_location(const void *a, const void *b)
913 int l = ((const pgssLocationLen *) a)->location;
914 int r = ((const pgssLocationLen *) b)->location;