OSDN Git Service

Call standrad_ProcessUtility when no hook is set
[pghintplan/pg_hint_plan.git] / pg_stat_statements.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_stat_statements.c
4  * 
5  * Part of pg_stat_statements.c in PostgreSQL 9.6.
6  *
7  * Copyright (c) 2008-2016, PostgreSQL Global Development Group
8  *
9  *-------------------------------------------------------------------------
10  */
11 #include "postgres.h"
12
13 #include "access/hash.h"
14 #include "parser/scanner.h"
15
16 static void AppendJumble(pgssJumbleState *jstate,
17                          const unsigned char *item, Size size);
18 static void JumbleQuery(pgssJumbleState *jstate, Query *query);
19 static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
20 static void JumbleExpr(pgssJumbleState *jstate, Node *node);
21 static void RecordConstLocation(pgssJumbleState *jstate, int location);
22 static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query);
23 static int      comp_location(const void *a, const void *b);
24
25 /*
26  * AppendJumble: Append a value that is substantive in a given query to
27  * the current jumble.
28  */
29 static void
30 AppendJumble(pgssJumbleState *jstate, const unsigned char *item, Size size)
31 {
32         unsigned char *jumble = jstate->jumble;
33         Size            jumble_len = jstate->jumble_len;
34
35         /*
36          * Whenever the jumble buffer is full, we hash the current contents and
37          * reset the buffer to contain just that hash value, thus relying on the
38          * hash to summarize everything so far.
39          */
40         while (size > 0)
41         {
42                 Size            part_size;
43
44                 if (jumble_len >= JUMBLE_SIZE)
45                 {
46                         uint32          start_hash = hash_any(jumble, JUMBLE_SIZE);
47
48                         memcpy(jumble, &start_hash, sizeof(start_hash));
49                         jumble_len = sizeof(start_hash);
50                 }
51                 part_size = Min(size, JUMBLE_SIZE - jumble_len);
52                 memcpy(jumble + jumble_len, item, part_size);
53                 jumble_len += part_size;
54                 item += part_size;
55                 size -= part_size;
56         }
57         jstate->jumble_len = jumble_len;
58 }
59
60 /*
61  * Wrappers around AppendJumble to encapsulate details of serialization
62  * of individual local variable elements.
63  */
64 #define APP_JUMB(item) \
65         AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
66 #define APP_JUMB_STRING(str) \
67         AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)
68
69 /*
70  * JumbleQuery: Selectively serialize the query tree, appending significant
71  * data to the "query jumble" while ignoring nonsignificant data.
72  *
73  * Rule of thumb for what to include is that we should ignore anything not
74  * semantically significant (such as alias names) as well as anything that can
75  * be deduced from child nodes (else we'd just be double-hashing that piece
76  * of information).
77  */
78 static void
79 JumbleQuery(pgssJumbleState *jstate, Query *query)
80 {
81         Assert(IsA(query, Query));
82         Assert(query->utilityStmt == NULL);
83
84         APP_JUMB(query->commandType);
85         /* resultRelation is usually predictable from commandType */
86         JumbleExpr(jstate, (Node *) query->cteList);
87         JumbleRangeTable(jstate, query->rtable);
88         JumbleExpr(jstate, (Node *) query->jointree);
89         JumbleExpr(jstate, (Node *) query->targetList);
90         JumbleExpr(jstate, (Node *) query->onConflict);
91         JumbleExpr(jstate, (Node *) query->returningList);
92         JumbleExpr(jstate, (Node *) query->groupClause);
93         JumbleExpr(jstate, (Node *) query->groupingSets);
94         JumbleExpr(jstate, query->havingQual);
95         JumbleExpr(jstate, (Node *) query->windowClause);
96         JumbleExpr(jstate, (Node *) query->distinctClause);
97         JumbleExpr(jstate, (Node *) query->sortClause);
98         JumbleExpr(jstate, query->limitOffset);
99         JumbleExpr(jstate, query->limitCount);
100         /* we ignore rowMarks */
101         JumbleExpr(jstate, query->setOperations);
102 }
103
104 /*
105  * Jumble a range table
106  */
107 static void
108 JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
109 {
110         ListCell   *lc;
111
112         foreach(lc, rtable)
113         {
114                 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
115
116                 Assert(IsA(rte, RangeTblEntry));
117                 APP_JUMB(rte->rtekind);
118                 switch (rte->rtekind)
119                 {
120                         case RTE_RELATION:
121                                 APP_JUMB(rte->relid);
122                                 JumbleExpr(jstate, (Node *) rte->tablesample);
123                                 break;
124                         case RTE_SUBQUERY:
125                                 JumbleQuery(jstate, rte->subquery);
126                                 break;
127                         case RTE_JOIN:
128                                 APP_JUMB(rte->jointype);
129                                 break;
130                         case RTE_FUNCTION:
131                                 JumbleExpr(jstate, (Node *) rte->functions);
132                                 break;
133                         case RTE_VALUES:
134                                 JumbleExpr(jstate, (Node *) rte->values_lists);
135                                 break;
136                         case RTE_CTE:
137
138                                 /*
139                                  * Depending on the CTE name here isn't ideal, but it's the
140                                  * only info we have to identify the referenced WITH item.
141                                  */
142                                 APP_JUMB_STRING(rte->ctename);
143                                 APP_JUMB(rte->ctelevelsup);
144                                 break;
145                         default:
146                                 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
147                                 break;
148                 }
149         }
150 }
151
152 /*
153  * Jumble an expression tree
154  *
155  * In general this function should handle all the same node types that
156  * expression_tree_walker() does, and therefore it's coded to be as parallel
157  * to that function as possible.  However, since we are only invoked on
158  * queries immediately post-parse-analysis, we need not handle node types
159  * that only appear in planning.
160  *
161  * Note: the reason we don't simply use expression_tree_walker() is that the
162  * point of that function is to support tree walkers that don't care about
163  * most tree node types, but here we care about all types.  We should complain
164  * about any unrecognized node type.
165  */
166 static void
167 JumbleExpr(pgssJumbleState *jstate, Node *node)
168 {
169         ListCell   *temp;
170
171         if (node == NULL)
172                 return;
173
174         /* Guard against stack overflow due to overly complex expressions */
175         check_stack_depth();
176
177         /*
178          * We always emit the node's NodeTag, then any additional fields that are
179          * considered significant, and then we recurse to any child nodes.
180          */
181         APP_JUMB(node->type);
182
183         switch (nodeTag(node))
184         {
185                 case T_Var:
186                         {
187                                 Var                *var = (Var *) node;
188
189                                 APP_JUMB(var->varno);
190                                 APP_JUMB(var->varattno);
191                                 APP_JUMB(var->varlevelsup);
192                         }
193                         break;
194                 case T_Const:
195                         {
196                                 Const      *c = (Const *) node;
197
198                                 /* We jumble only the constant's type, not its value */
199                                 APP_JUMB(c->consttype);
200                                 /* Also, record its parse location for query normalization */
201                                 RecordConstLocation(jstate, c->location);
202                         }
203                         break;
204                 case T_Param:
205                         {
206                                 Param      *p = (Param *) node;
207
208                                 APP_JUMB(p->paramkind);
209                                 APP_JUMB(p->paramid);
210                                 APP_JUMB(p->paramtype);
211                         }
212                         break;
213                 case T_Aggref:
214                         {
215                                 Aggref     *expr = (Aggref *) node;
216
217                                 APP_JUMB(expr->aggfnoid);
218                                 JumbleExpr(jstate, (Node *) expr->aggdirectargs);
219                                 JumbleExpr(jstate, (Node *) expr->args);
220                                 JumbleExpr(jstate, (Node *) expr->aggorder);
221                                 JumbleExpr(jstate, (Node *) expr->aggdistinct);
222                                 JumbleExpr(jstate, (Node *) expr->aggfilter);
223                         }
224                         break;
225                 case T_GroupingFunc:
226                         {
227                                 GroupingFunc *grpnode = (GroupingFunc *) node;
228
229                                 JumbleExpr(jstate, (Node *) grpnode->refs);
230                         }
231                         break;
232                 case T_WindowFunc:
233                         {
234                                 WindowFunc *expr = (WindowFunc *) node;
235
236                                 APP_JUMB(expr->winfnoid);
237                                 APP_JUMB(expr->winref);
238                                 JumbleExpr(jstate, (Node *) expr->args);
239                                 JumbleExpr(jstate, (Node *) expr->aggfilter);
240                         }
241                         break;
242                 case T_ArrayRef:
243                         {
244                                 ArrayRef   *aref = (ArrayRef *) node;
245
246                                 JumbleExpr(jstate, (Node *) aref->refupperindexpr);
247                                 JumbleExpr(jstate, (Node *) aref->reflowerindexpr);
248                                 JumbleExpr(jstate, (Node *) aref->refexpr);
249                                 JumbleExpr(jstate, (Node *) aref->refassgnexpr);
250                         }
251                         break;
252                 case T_FuncExpr:
253                         {
254                                 FuncExpr   *expr = (FuncExpr *) node;
255
256                                 APP_JUMB(expr->funcid);
257                                 JumbleExpr(jstate, (Node *) expr->args);
258                         }
259                         break;
260                 case T_NamedArgExpr:
261                         {
262                                 NamedArgExpr *nae = (NamedArgExpr *) node;
263
264                                 APP_JUMB(nae->argnumber);
265                                 JumbleExpr(jstate, (Node *) nae->arg);
266                         }
267                         break;
268                 case T_OpExpr:
269                 case T_DistinctExpr:    /* struct-equivalent to OpExpr */
270                 case T_NullIfExpr:              /* struct-equivalent to OpExpr */
271                         {
272                                 OpExpr     *expr = (OpExpr *) node;
273
274                                 APP_JUMB(expr->opno);
275                                 JumbleExpr(jstate, (Node *) expr->args);
276                         }
277                         break;
278                 case T_ScalarArrayOpExpr:
279                         {
280                                 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
281
282                                 APP_JUMB(expr->opno);
283                                 APP_JUMB(expr->useOr);
284                                 JumbleExpr(jstate, (Node *) expr->args);
285                         }
286                         break;
287                 case T_BoolExpr:
288                         {
289                                 BoolExpr   *expr = (BoolExpr *) node;
290
291                                 APP_JUMB(expr->boolop);
292                                 JumbleExpr(jstate, (Node *) expr->args);
293                         }
294                         break;
295                 case T_SubLink:
296                         {
297                                 SubLink    *sublink = (SubLink *) node;
298
299                                 APP_JUMB(sublink->subLinkType);
300                                 APP_JUMB(sublink->subLinkId);
301                                 JumbleExpr(jstate, (Node *) sublink->testexpr);
302                                 JumbleQuery(jstate, (Query *) sublink->subselect);
303                         }
304                         break;
305                 case T_FieldSelect:
306                         {
307                                 FieldSelect *fs = (FieldSelect *) node;
308
309                                 APP_JUMB(fs->fieldnum);
310                                 JumbleExpr(jstate, (Node *) fs->arg);
311                         }
312                         break;
313                 case T_FieldStore:
314                         {
315                                 FieldStore *fstore = (FieldStore *) node;
316
317                                 JumbleExpr(jstate, (Node *) fstore->arg);
318                                 JumbleExpr(jstate, (Node *) fstore->newvals);
319                         }
320                         break;
321                 case T_RelabelType:
322                         {
323                                 RelabelType *rt = (RelabelType *) node;
324
325                                 APP_JUMB(rt->resulttype);
326                                 JumbleExpr(jstate, (Node *) rt->arg);
327                         }
328                         break;
329                 case T_CoerceViaIO:
330                         {
331                                 CoerceViaIO *cio = (CoerceViaIO *) node;
332
333                                 APP_JUMB(cio->resulttype);
334                                 JumbleExpr(jstate, (Node *) cio->arg);
335                         }
336                         break;
337                 case T_ArrayCoerceExpr:
338                         {
339                                 ArrayCoerceExpr *acexpr = (ArrayCoerceExpr *) node;
340
341                                 APP_JUMB(acexpr->resulttype);
342                                 JumbleExpr(jstate, (Node *) acexpr->arg);
343                         }
344                         break;
345                 case T_ConvertRowtypeExpr:
346                         {
347                                 ConvertRowtypeExpr *crexpr = (ConvertRowtypeExpr *) node;
348
349                                 APP_JUMB(crexpr->resulttype);
350                                 JumbleExpr(jstate, (Node *) crexpr->arg);
351                         }
352                         break;
353                 case T_CollateExpr:
354                         {
355                                 CollateExpr *ce = (CollateExpr *) node;
356
357                                 APP_JUMB(ce->collOid);
358                                 JumbleExpr(jstate, (Node *) ce->arg);
359                         }
360                         break;
361                 case T_CaseExpr:
362                         {
363                                 CaseExpr   *caseexpr = (CaseExpr *) node;
364
365                                 JumbleExpr(jstate, (Node *) caseexpr->arg);
366                                 foreach(temp, caseexpr->args)
367                                 {
368                                         CaseWhen   *when = (CaseWhen *) lfirst(temp);
369
370                                         Assert(IsA(when, CaseWhen));
371                                         JumbleExpr(jstate, (Node *) when->expr);
372                                         JumbleExpr(jstate, (Node *) when->result);
373                                 }
374                                 JumbleExpr(jstate, (Node *) caseexpr->defresult);
375                         }
376                         break;
377                 case T_CaseTestExpr:
378                         {
379                                 CaseTestExpr *ct = (CaseTestExpr *) node;
380
381                                 APP_JUMB(ct->typeId);
382                         }
383                         break;
384                 case T_ArrayExpr:
385                         JumbleExpr(jstate, (Node *) ((ArrayExpr *) node)->elements);
386                         break;
387                 case T_RowExpr:
388                         JumbleExpr(jstate, (Node *) ((RowExpr *) node)->args);
389                         break;
390                 case T_RowCompareExpr:
391                         {
392                                 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
393
394                                 APP_JUMB(rcexpr->rctype);
395                                 JumbleExpr(jstate, (Node *) rcexpr->largs);
396                                 JumbleExpr(jstate, (Node *) rcexpr->rargs);
397                         }
398                         break;
399                 case T_CoalesceExpr:
400                         JumbleExpr(jstate, (Node *) ((CoalesceExpr *) node)->args);
401                         break;
402                 case T_MinMaxExpr:
403                         {
404                                 MinMaxExpr *mmexpr = (MinMaxExpr *) node;
405
406                                 APP_JUMB(mmexpr->op);
407                                 JumbleExpr(jstate, (Node *) mmexpr->args);
408                         }
409                         break;
410                 case T_XmlExpr:
411                         {
412                                 XmlExpr    *xexpr = (XmlExpr *) node;
413
414                                 APP_JUMB(xexpr->op);
415                                 JumbleExpr(jstate, (Node *) xexpr->named_args);
416                                 JumbleExpr(jstate, (Node *) xexpr->args);
417                         }
418                         break;
419                 case T_NullTest:
420                         {
421                                 NullTest   *nt = (NullTest *) node;
422
423                                 APP_JUMB(nt->nulltesttype);
424                                 JumbleExpr(jstate, (Node *) nt->arg);
425                         }
426                         break;
427                 case T_BooleanTest:
428                         {
429                                 BooleanTest *bt = (BooleanTest *) node;
430
431                                 APP_JUMB(bt->booltesttype);
432                                 JumbleExpr(jstate, (Node *) bt->arg);
433                         }
434                         break;
435                 case T_CoerceToDomain:
436                         {
437                                 CoerceToDomain *cd = (CoerceToDomain *) node;
438
439                                 APP_JUMB(cd->resulttype);
440                                 JumbleExpr(jstate, (Node *) cd->arg);
441                         }
442                         break;
443                 case T_CoerceToDomainValue:
444                         {
445                                 CoerceToDomainValue *cdv = (CoerceToDomainValue *) node;
446
447                                 APP_JUMB(cdv->typeId);
448                         }
449                         break;
450                 case T_SetToDefault:
451                         {
452                                 SetToDefault *sd = (SetToDefault *) node;
453
454                                 APP_JUMB(sd->typeId);
455                         }
456                         break;
457                 case T_CurrentOfExpr:
458                         {
459                                 CurrentOfExpr *ce = (CurrentOfExpr *) node;
460
461                                 APP_JUMB(ce->cvarno);
462                                 if (ce->cursor_name)
463                                         APP_JUMB_STRING(ce->cursor_name);
464                                 APP_JUMB(ce->cursor_param);
465                         }
466                         break;
467                 case T_InferenceElem:
468                         {
469                                 InferenceElem *ie = (InferenceElem *) node;
470
471                                 APP_JUMB(ie->infercollid);
472                                 APP_JUMB(ie->inferopclass);
473                                 JumbleExpr(jstate, ie->expr);
474                         }
475                         break;
476                 case T_TargetEntry:
477                         {
478                                 TargetEntry *tle = (TargetEntry *) node;
479
480                                 APP_JUMB(tle->resno);
481                                 APP_JUMB(tle->ressortgroupref);
482                                 JumbleExpr(jstate, (Node *) tle->expr);
483                         }
484                         break;
485                 case T_RangeTblRef:
486                         {
487                                 RangeTblRef *rtr = (RangeTblRef *) node;
488
489                                 APP_JUMB(rtr->rtindex);
490                         }
491                         break;
492                 case T_JoinExpr:
493                         {
494                                 JoinExpr   *join = (JoinExpr *) node;
495
496                                 APP_JUMB(join->jointype);
497                                 APP_JUMB(join->isNatural);
498                                 APP_JUMB(join->rtindex);
499                                 JumbleExpr(jstate, join->larg);
500                                 JumbleExpr(jstate, join->rarg);
501                                 JumbleExpr(jstate, join->quals);
502                         }
503                         break;
504                 case T_FromExpr:
505                         {
506                                 FromExpr   *from = (FromExpr *) node;
507
508                                 JumbleExpr(jstate, (Node *) from->fromlist);
509                                 JumbleExpr(jstate, from->quals);
510                         }
511                         break;
512                 case T_OnConflictExpr:
513                         {
514                                 OnConflictExpr *conf = (OnConflictExpr *) node;
515
516                                 APP_JUMB(conf->action);
517                                 JumbleExpr(jstate, (Node *) conf->arbiterElems);
518                                 JumbleExpr(jstate, conf->arbiterWhere);
519                                 JumbleExpr(jstate, (Node *) conf->onConflictSet);
520                                 JumbleExpr(jstate, conf->onConflictWhere);
521                                 APP_JUMB(conf->constraint);
522                                 APP_JUMB(conf->exclRelIndex);
523                                 JumbleExpr(jstate, (Node *) conf->exclRelTlist);
524                         }
525                         break;
526                 case T_List:
527                         foreach(temp, (List *) node)
528                         {
529                                 JumbleExpr(jstate, (Node *) lfirst(temp));
530                         }
531                         break;
532                 case T_IntList:
533                         foreach(temp, (List *) node)
534                         {
535                                 APP_JUMB(lfirst_int(temp));
536                         }
537                         break;
538                 case T_SortGroupClause:
539                         {
540                                 SortGroupClause *sgc = (SortGroupClause *) node;
541
542                                 APP_JUMB(sgc->tleSortGroupRef);
543                                 APP_JUMB(sgc->eqop);
544                                 APP_JUMB(sgc->sortop);
545                                 APP_JUMB(sgc->nulls_first);
546                         }
547                         break;
548                 case T_GroupingSet:
549                         {
550                                 GroupingSet *gsnode = (GroupingSet *) node;
551
552                                 JumbleExpr(jstate, (Node *) gsnode->content);
553                         }
554                         break;
555                 case T_WindowClause:
556                         {
557                                 WindowClause *wc = (WindowClause *) node;
558
559                                 APP_JUMB(wc->winref);
560                                 APP_JUMB(wc->frameOptions);
561                                 JumbleExpr(jstate, (Node *) wc->partitionClause);
562                                 JumbleExpr(jstate, (Node *) wc->orderClause);
563                                 JumbleExpr(jstate, wc->startOffset);
564                                 JumbleExpr(jstate, wc->endOffset);
565                         }
566                         break;
567                 case T_CommonTableExpr:
568                         {
569                                 CommonTableExpr *cte = (CommonTableExpr *) node;
570
571                                 /* we store the string name because RTE_CTE RTEs need it */
572                                 APP_JUMB_STRING(cte->ctename);
573                                 JumbleQuery(jstate, (Query *) cte->ctequery);
574                         }
575                         break;
576                 case T_SetOperationStmt:
577                         {
578                                 SetOperationStmt *setop = (SetOperationStmt *) node;
579
580                                 APP_JUMB(setop->op);
581                                 APP_JUMB(setop->all);
582                                 JumbleExpr(jstate, setop->larg);
583                                 JumbleExpr(jstate, setop->rarg);
584                         }
585                         break;
586                 case T_RangeTblFunction:
587                         {
588                                 RangeTblFunction *rtfunc = (RangeTblFunction *) node;
589
590                                 JumbleExpr(jstate, rtfunc->funcexpr);
591                         }
592                         break;
593                 case T_TableSampleClause:
594                         {
595                                 TableSampleClause *tsc = (TableSampleClause *) node;
596
597                                 APP_JUMB(tsc->tsmhandler);
598                                 JumbleExpr(jstate, (Node *) tsc->args);
599                                 JumbleExpr(jstate, (Node *) tsc->repeatable);
600                         }
601                         break;
602                 default:
603                         /* Only a warning, since we can stumble along anyway */
604                         elog(WARNING, "unrecognized node type: %d",
605                                  (int) nodeTag(node));
606                         break;
607         }
608 }
609
610 /*
611  * Record location of constant within query string of query tree
612  * that is currently being walked.
613  */
614 static void
615 RecordConstLocation(pgssJumbleState *jstate, int location)
616 {
617         /* -1 indicates unknown or undefined location */
618         if (location >= 0)
619         {
620                 /* enlarge array if needed */
621                 if (jstate->clocations_count >= jstate->clocations_buf_size)
622                 {
623                         jstate->clocations_buf_size *= 2;
624                         jstate->clocations = (pgssLocationLen *)
625                                 repalloc(jstate->clocations,
626                                                  jstate->clocations_buf_size *
627                                                  sizeof(pgssLocationLen));
628                 }
629                 jstate->clocations[jstate->clocations_count].location = location;
630                 /* initialize lengths to -1 to simplify fill_in_constant_lengths */
631                 jstate->clocations[jstate->clocations_count].length = -1;
632                 jstate->clocations_count++;
633         }
634 }
635
636 /*
637  * Generate a normalized version of the query string that will be used to
638  * represent all similar queries.
639  *
640  * Note that the normalized representation may well vary depending on
641  * just which "equivalent" query is used to create the hashtable entry.
642  * We assume this is OK.
643  *
644  * *query_len_p contains the input string length, and is updated with
645  * the result string length (which cannot be longer) on exit.
646  *
647  * Returns a palloc'd string.
648  */
649 static char *
650 generate_normalized_query(pgssJumbleState *jstate, const char *query,
651                                                   int *query_len_p, int encoding)
652 {
653         char       *norm_query;
654         int                     query_len = *query_len_p;
655         int                     i,
656                                 len_to_wrt,             /* Length (in bytes) to write */
657                                 quer_loc = 0,   /* Source query byte location */
658                                 n_quer_loc = 0, /* Normalized query byte location */
659                                 last_off = 0,   /* Offset from start for previous tok */
660                                 last_tok_len = 0;               /* Length (in bytes) of that tok */
661
662         /*
663          * Get constants' lengths (core system only gives us locations).  Note
664          * this also ensures the items are sorted by location.
665          */
666         fill_in_constant_lengths(jstate, query);
667
668         /* Allocate result buffer */
669         norm_query = palloc(query_len + 1);
670
671         for (i = 0; i < jstate->clocations_count; i++)
672         {
673                 int                     off,            /* Offset from start for cur tok */
674                                         tok_len;        /* Length (in bytes) of that tok */
675
676                 off = jstate->clocations[i].location;
677                 tok_len = jstate->clocations[i].length;
678
679                 if (tok_len < 0)
680                         continue;                       /* ignore any duplicates */
681
682                 /* Copy next chunk (what precedes the next constant) */
683                 len_to_wrt = off - last_off;
684                 len_to_wrt -= last_tok_len;
685
686                 Assert(len_to_wrt >= 0);
687                 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
688                 n_quer_loc += len_to_wrt;
689
690                 /* And insert a '?' in place of the constant token */
691                 norm_query[n_quer_loc++] = '?';
692
693                 quer_loc = off + tok_len;
694                 last_off = off;
695                 last_tok_len = tok_len;
696         }
697
698         /*
699          * We've copied up until the last ignorable constant.  Copy over the
700          * remaining bytes of the original query string.
701          */
702         len_to_wrt = query_len - quer_loc;
703
704         Assert(len_to_wrt >= 0);
705         memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
706         n_quer_loc += len_to_wrt;
707
708         Assert(n_quer_loc <= query_len);
709         norm_query[n_quer_loc] = '\0';
710
711         *query_len_p = n_quer_loc;
712         return norm_query;
713 }
714
715 /*
716  * Given a valid SQL string and an array of constant-location records,
717  * fill in the textual lengths of those constants.
718  *
719  * The constants may use any allowed constant syntax, such as float literals,
720  * bit-strings, single-quoted strings and dollar-quoted strings.  This is
721  * accomplished by using the public API for the core scanner.
722  *
723  * It is the caller's job to ensure that the string is a valid SQL statement
724  * with constants at the indicated locations.  Since in practice the string
725  * has already been parsed, and the locations that the caller provides will
726  * have originated from within the authoritative parser, this should not be
727  * a problem.
728  *
729  * Duplicate constant pointers are possible, and will have their lengths
730  * marked as '-1', so that they are later ignored.  (Actually, we assume the
731  * lengths were initialized as -1 to start with, and don't change them here.)
732  *
733  * N.B. There is an assumption that a '-' character at a Const location begins
734  * a negative numeric constant.  This precludes there ever being another
735  * reason for a constant to start with a '-'.
736  */
737 static void
738 fill_in_constant_lengths(pgssJumbleState *jstate, const char *query)
739 {
740         pgssLocationLen *locs;
741         core_yyscan_t yyscanner;
742         core_yy_extra_type yyextra;
743         core_YYSTYPE yylval;
744         YYLTYPE         yylloc;
745         int                     last_loc = -1;
746         int                     i;
747
748         /*
749          * Sort the records by location so that we can process them in order while
750          * scanning the query text.
751          */
752         if (jstate->clocations_count > 1)
753                 qsort(jstate->clocations, jstate->clocations_count,
754                           sizeof(pgssLocationLen), comp_location);
755         locs = jstate->clocations;
756
757         /* initialize the flex scanner --- should match raw_parser() */
758         yyscanner = scanner_init(query,
759                                                          &yyextra,
760                                                          ScanKeywords,
761                                                          NumScanKeywords);
762
763         /* we don't want to re-emit any escape string warnings */
764         yyextra.escape_string_warning = false;
765
766         /* Search for each constant, in sequence */
767         for (i = 0; i < jstate->clocations_count; i++)
768         {
769                 int                     loc = locs[i].location;
770                 int                     tok;
771
772                 Assert(loc >= 0);
773
774                 if (loc <= last_loc)
775                         continue;                       /* Duplicate constant, ignore */
776
777                 /* Lex tokens until we find the desired constant */
778                 for (;;)
779                 {
780                         tok = core_yylex(&yylval, &yylloc, yyscanner);
781
782                         /* We should not hit end-of-string, but if we do, behave sanely */
783                         if (tok == 0)
784                                 break;                  /* out of inner for-loop */
785
786                         /*
787                          * We should find the token position exactly, but if we somehow
788                          * run past it, work with that.
789                          */
790                         if (yylloc >= loc)
791                         {
792                                 if (query[loc] == '-')
793                                 {
794                                         /*
795                                          * It's a negative value - this is the one and only case
796                                          * where we replace more than a single token.
797                                          *
798                                          * Do not compensate for the core system's special-case
799                                          * adjustment of location to that of the leading '-'
800                                          * operator in the event of a negative constant.  It is
801                                          * also useful for our purposes to start from the minus
802                                          * symbol.  In this way, queries like "select * from foo
803                                          * where bar = 1" and "select * from foo where bar = -2"
804                                          * will have identical normalized query strings.
805                                          */
806                                         tok = core_yylex(&yylval, &yylloc, yyscanner);
807                                         if (tok == 0)
808                                                 break;  /* out of inner for-loop */
809                                 }
810
811                                 /*
812                                  * We now rely on the assumption that flex has placed a zero
813                                  * byte after the text of the current token in scanbuf.
814                                  */
815                                 locs[i].length = strlen(yyextra.scanbuf + loc);
816                                 break;                  /* out of inner for-loop */
817                         }
818                 }
819
820                 /* If we hit end-of-string, give up, leaving remaining lengths -1 */
821                 if (tok == 0)
822                         break;
823
824                 last_loc = loc;
825         }
826
827         scanner_finish(yyscanner);
828 }
829
830 /*
831  * comp_location: comparator for qsorting pgssLocationLen structs by location
832  */
833 static int
834 comp_location(const void *a, const void *b)
835 {
836         int                     l = ((const pgssLocationLen *) a)->location;
837         int                     r = ((const pgssLocationLen *) b)->location;
838
839         if (l < r)
840                 return -1;
841         else if (l > r)
842                 return +1;
843         else
844                 return 0;
845 }