Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * queryjumblefuncs.c
4 : * Query normalization and fingerprinting.
5 : *
6 : * Normalization is a process whereby similar queries, typically differing only
7 : * in their constants (though the exact rules are somewhat more subtle than
8 : * that) are recognized as equivalent, and are tracked as a single entry. This
9 : * is particularly useful for non-prepared queries.
10 : *
11 : * Normalization is implemented by fingerprinting queries, selectively
12 : * serializing those fields of each query tree's nodes that are judged to be
13 : * essential to the query. This is referred to as a query jumble. This is
14 : * distinct from a regular serialization in that various extraneous
15 : * information is ignored as irrelevant or not essential to the query, such
16 : * as the collations of Vars and, most notably, the values of constants.
17 : *
18 : * This jumble is acquired at the end of parse analysis of each query, and
19 : * a 64-bit hash of it is stored into the query's Query.queryId field.
20 : * The server then copies this value around, making it available in plan
21 : * tree(s) generated from the query. The executor can then use this value
22 : * to blame query costs on the proper queryId.
23 : *
24 : * Arrays of two or more constants and PARAM_EXTERN parameters are "squashed"
25 : * and contribute only once to the jumble. This has the effect that queries
26 : * that differ only on the length of such lists have the same queryId.
27 : *
28 : *
29 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
30 : * Portions Copyright (c) 1994, Regents of the University of California
31 : *
32 : *
33 : * IDENTIFICATION
34 : * src/backend/nodes/queryjumblefuncs.c
35 : *
36 : *-------------------------------------------------------------------------
37 : */
38 : #include "postgres.h"
39 :
40 : #include "access/transam.h"
41 : #include "catalog/pg_proc.h"
42 : #include "common/hashfn.h"
43 : #include "miscadmin.h"
44 : #include "nodes/nodeFuncs.h"
45 : #include "nodes/queryjumble.h"
46 : #include "utils/lsyscache.h"
47 : #include "parser/scansup.h"
48 :
49 : #define JUMBLE_SIZE 1024 /* query serialization buffer size */
50 :
51 : /* GUC parameters */
52 : int compute_query_id = COMPUTE_QUERY_ID_AUTO;
53 :
54 : /*
55 : * True when compute_query_id is ON or AUTO, and a module requests them.
56 : *
57 : * Note that IsQueryIdEnabled() should be used instead of checking
58 : * query_id_enabled or compute_query_id directly when we want to know
59 : * whether query identifiers are computed in the core or not.
60 : */
61 : bool query_id_enabled = false;
62 :
63 : static JumbleState *InitJumble(void);
64 : static int64 DoJumble(JumbleState *jstate, Node *node);
65 : static void AppendJumble(JumbleState *jstate,
66 : const unsigned char *value, Size size);
67 : static void FlushPendingNulls(JumbleState *jstate);
68 : static void RecordConstLocation(JumbleState *jstate,
69 : bool extern_param,
70 : int location, int len);
71 : static void _jumbleNode(JumbleState *jstate, Node *node);
72 : static void _jumbleList(JumbleState *jstate, Node *node);
73 : static void _jumbleElements(JumbleState *jstate, List *elements, Node *node);
74 : static void _jumbleParam(JumbleState *jstate, Node *node);
75 : static void _jumbleA_Const(JumbleState *jstate, Node *node);
76 : static void _jumbleVariableSetStmt(JumbleState *jstate, Node *node);
77 : static void _jumbleRangeTblEntry_eref(JumbleState *jstate,
78 : RangeTblEntry *rte,
79 : Alias *expr);
80 :
81 : /*
82 : * Given a possibly multi-statement source string, confine our attention to the
83 : * relevant part of the string.
84 : */
85 : const char *
86 191272 : CleanQuerytext(const char *query, int *location, int *len)
87 : {
88 191272 : int query_location = *location;
89 191272 : int query_len = *len;
90 :
91 : /* First apply starting offset, unless it's -1 (unknown). */
92 191272 : if (query_location >= 0)
93 : {
94 : Assert(query_location <= strlen(query));
95 190898 : query += query_location;
96 : /* Length of 0 (or -1) means "rest of string" */
97 190898 : if (query_len <= 0)
98 31812 : query_len = strlen(query);
99 : else
100 : Assert(query_len <= strlen(query));
101 : }
102 : else
103 : {
104 : /* If query location is unknown, distrust query_len as well */
105 374 : query_location = 0;
106 374 : query_len = strlen(query);
107 : }
108 :
109 : /*
110 : * Discard leading and trailing whitespace, too. Use scanner_isspace()
111 : * not libc's isspace(), because we want to match the lexer's behavior.
112 : *
113 : * Note: the parser now strips leading comments and whitespace from the
114 : * reported stmt_location, so this first loop will only iterate in the
115 : * unusual case that the location didn't propagate to here. But the
116 : * statement length will extend to the end-of-string or terminating
117 : * semicolon, so the second loop often does something useful.
118 : */
119 191274 : while (query_len > 0 && scanner_isspace(query[0]))
120 2 : query++, query_location++, query_len--;
121 192624 : while (query_len > 0 && scanner_isspace(query[query_len - 1]))
122 1352 : query_len--;
123 :
124 191272 : *location = query_location;
125 191272 : *len = query_len;
126 :
127 191272 : return query;
128 : }
129 :
130 : /*
131 : * JumbleQuery
132 : * Recursively process the given Query producing a 64-bit hash value by
133 : * hashing the relevant fields and record that value in the Query's queryId
134 : * field. Return the JumbleState object used for jumbling the query.
135 : */
136 : JumbleState *
137 154624 : JumbleQuery(Query *query)
138 : {
139 : JumbleState *jstate;
140 :
141 : Assert(IsQueryIdEnabled());
142 :
143 154624 : jstate = InitJumble();
144 :
145 154624 : query->queryId = DoJumble(jstate, (Node *) query);
146 :
147 : /*
148 : * If we are unlucky enough to get a hash of zero, use 1 instead for
149 : * normal statements and 2 for utility queries.
150 : */
151 154624 : if (query->queryId == INT64CONST(0))
152 : {
153 0 : if (query->utilityStmt)
154 0 : query->queryId = INT64CONST(2);
155 : else
156 0 : query->queryId = INT64CONST(1);
157 : }
158 :
159 154624 : return jstate;
160 : }
161 :
162 : /*
163 : * Enables query identifier computation.
164 : *
165 : * Third-party plugins can use this function to inform core that they require
166 : * a query identifier to be computed.
167 : */
168 : void
169 14 : EnableQueryId(void)
170 : {
171 14 : if (compute_query_id != COMPUTE_QUERY_ID_OFF)
172 14 : query_id_enabled = true;
173 14 : }
174 :
175 : /*
176 : * InitJumble
177 : * Allocate a JumbleState object and make it ready to jumble.
178 : */
179 : static JumbleState *
180 154624 : InitJumble(void)
181 : {
182 : JumbleState *jstate;
183 :
184 154624 : jstate = (JumbleState *) palloc(sizeof(JumbleState));
185 :
186 : /* Set up workspace for query jumbling */
187 154624 : jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
188 154624 : jstate->jumble_len = 0;
189 154624 : jstate->clocations_buf_size = 32;
190 154624 : jstate->clocations = (LocationLen *) palloc(jstate->clocations_buf_size *
191 : sizeof(LocationLen));
192 154624 : jstate->clocations_count = 0;
193 154624 : jstate->highest_extern_param_id = 0;
194 154624 : jstate->pending_nulls = 0;
195 154624 : jstate->has_squashed_lists = false;
196 : #ifdef USE_ASSERT_CHECKING
197 : jstate->total_jumble_len = 0;
198 : #endif
199 :
200 154624 : return jstate;
201 : }
202 :
203 : /*
204 : * DoJumble
205 : * Jumble the given Node using the given JumbleState and return the resulting
206 : * jumble hash.
207 : */
208 : static int64
209 154624 : DoJumble(JumbleState *jstate, Node *node)
210 : {
211 : /* Jumble the given node */
212 154624 : _jumbleNode(jstate, node);
213 :
214 : /* Flush any pending NULLs before doing the final hash */
215 154624 : if (jstate->pending_nulls > 0)
216 153166 : FlushPendingNulls(jstate);
217 :
218 : /* Squashed list found, reset highest_extern_param_id */
219 154624 : if (jstate->has_squashed_lists)
220 2870 : jstate->highest_extern_param_id = 0;
221 :
222 : /* Process the jumble buffer and produce the hash value */
223 154624 : return DatumGetInt64(hash_any_extended(jstate->jumble,
224 154624 : jstate->jumble_len,
225 : 0));
226 : }
227 :
228 : /*
229 : * AppendJumbleInternal: Internal function for appending to the jumble buffer
230 : *
231 : * Note: Callers must ensure that size > 0.
232 : */
233 : static pg_attribute_always_inline void
234 10963842 : AppendJumbleInternal(JumbleState *jstate, const unsigned char *item,
235 : Size size)
236 : {
237 10963842 : unsigned char *jumble = jstate->jumble;
238 10963842 : Size jumble_len = jstate->jumble_len;
239 :
240 : /* Ensure the caller didn't mess up */
241 : Assert(size > 0);
242 :
243 : /*
244 : * Fast path for when there's enough space left in the buffer. This is
245 : * worthwhile as means the memcpy can be inlined into very efficient code
246 : * when 'size' is a compile-time constant.
247 : */
248 10963842 : if (likely(size <= JUMBLE_SIZE - jumble_len))
249 : {
250 10957726 : memcpy(jumble + jumble_len, item, size);
251 10957726 : jstate->jumble_len += size;
252 :
253 : #ifdef USE_ASSERT_CHECKING
254 : jstate->total_jumble_len += size;
255 : #endif
256 :
257 10957726 : return;
258 : }
259 :
260 : /*
261 : * Whenever the jumble buffer is full, we hash the current contents and
262 : * reset the buffer to contain just that hash value, thus relying on the
263 : * hash to summarize everything so far.
264 : */
265 : do
266 : {
267 : Size part_size;
268 :
269 10796 : if (unlikely(jumble_len >= JUMBLE_SIZE))
270 : {
271 : int64 start_hash;
272 :
273 6314 : start_hash = DatumGetInt64(hash_any_extended(jumble,
274 : JUMBLE_SIZE, 0));
275 6314 : memcpy(jumble, &start_hash, sizeof(start_hash));
276 6314 : jumble_len = sizeof(start_hash);
277 : }
278 10796 : part_size = Min(size, JUMBLE_SIZE - jumble_len);
279 10796 : memcpy(jumble + jumble_len, item, part_size);
280 10796 : jumble_len += part_size;
281 10796 : item += part_size;
282 10796 : size -= part_size;
283 :
284 : #ifdef USE_ASSERT_CHECKING
285 : jstate->total_jumble_len += part_size;
286 : #endif
287 10796 : } while (size > 0);
288 :
289 6116 : jstate->jumble_len = jumble_len;
290 : }
291 :
292 : /*
293 : * AppendJumble
294 : * Add 'size' bytes of the given jumble 'value' to the jumble state
295 : */
296 : static pg_noinline void
297 375274 : AppendJumble(JumbleState *jstate, const unsigned char *value, Size size)
298 : {
299 375274 : if (jstate->pending_nulls > 0)
300 55842 : FlushPendingNulls(jstate);
301 :
302 375274 : AppendJumbleInternal(jstate, value, size);
303 375274 : }
304 :
305 : /*
306 : * AppendJumbleNull
307 : * For jumbling NULL pointers
308 : */
309 : static pg_attribute_always_inline void
310 4966950 : AppendJumbleNull(JumbleState *jstate)
311 : {
312 4966950 : jstate->pending_nulls++;
313 4966950 : }
314 :
315 : /*
316 : * AppendJumble8
317 : * Add the first byte from the given 'value' pointer to the jumble state
318 : */
319 : static pg_noinline void
320 1025244 : AppendJumble8(JumbleState *jstate, const unsigned char *value)
321 : {
322 1025244 : if (jstate->pending_nulls > 0)
323 411160 : FlushPendingNulls(jstate);
324 :
325 1025244 : AppendJumbleInternal(jstate, value, 1);
326 1025244 : }
327 :
328 : /*
329 : * AppendJumble16
330 : * Add the first 2 bytes from the given 'value' pointer to the jumble
331 : * state.
332 : */
333 : static pg_noinline void
334 812144 : AppendJumble16(JumbleState *jstate, const unsigned char *value)
335 : {
336 812144 : if (jstate->pending_nulls > 0)
337 37104 : FlushPendingNulls(jstate);
338 :
339 812144 : AppendJumbleInternal(jstate, value, 2);
340 812144 : }
341 :
342 : /*
343 : * AppendJumble32
344 : * Add the first 4 bytes from the given 'value' pointer to the jumble
345 : * state.
346 : */
347 : static pg_noinline void
348 6941632 : AppendJumble32(JumbleState *jstate, const unsigned char *value)
349 : {
350 6941632 : if (jstate->pending_nulls > 0)
351 1151186 : FlushPendingNulls(jstate);
352 :
353 6941632 : AppendJumbleInternal(jstate, value, 4);
354 6941632 : }
355 :
356 : /*
357 : * AppendJumble64
358 : * Add the first 8 bytes from the given 'value' pointer to the jumble
359 : * state.
360 : */
361 : static pg_noinline void
362 1090 : AppendJumble64(JumbleState *jstate, const unsigned char *value)
363 : {
364 1090 : if (jstate->pending_nulls > 0)
365 0 : FlushPendingNulls(jstate);
366 :
367 1090 : AppendJumbleInternal(jstate, value, 8);
368 1090 : }
369 :
370 : /*
371 : * FlushPendingNulls
372 : * Incorporate the pending_nulls value into the jumble buffer.
373 : *
374 : * Note: Callers must ensure that there's at least 1 pending NULL.
375 : */
376 : static pg_attribute_always_inline void
377 1808458 : FlushPendingNulls(JumbleState *jstate)
378 : {
379 : Assert(jstate->pending_nulls > 0);
380 :
381 1808458 : AppendJumbleInternal(jstate,
382 1808458 : (const unsigned char *) &jstate->pending_nulls, 4);
383 1808458 : jstate->pending_nulls = 0;
384 1808458 : }
385 :
386 :
387 : /*
388 : * Record the location of some kind of constant within a query string.
389 : * These are not only bare constants but also expressions that ultimately
390 : * constitute a constant, such as those inside casts and simple function
391 : * calls; if extern_param, then it corresponds to a PARAM_EXTERN Param.
392 : *
393 : * If length is -1, it indicates a single such constant element. If
394 : * it's a positive integer, it indicates the length of a squashable
395 : * list of them.
396 : */
397 : static void
398 245994 : RecordConstLocation(JumbleState *jstate, bool extern_param, int location, int len)
399 : {
400 : /* -1 indicates unknown or undefined location */
401 245994 : if (location >= 0)
402 : {
403 : /* enlarge array if needed */
404 232848 : if (jstate->clocations_count >= jstate->clocations_buf_size)
405 : {
406 118 : jstate->clocations_buf_size *= 2;
407 118 : jstate->clocations = (LocationLen *)
408 118 : repalloc(jstate->clocations,
409 118 : jstate->clocations_buf_size *
410 : sizeof(LocationLen));
411 : }
412 232848 : jstate->clocations[jstate->clocations_count].location = location;
413 :
414 : /*
415 : * Lengths are either positive integers (indicating a squashable
416 : * list), or -1.
417 : */
418 : Assert(len > -1 || len == -1);
419 232848 : jstate->clocations[jstate->clocations_count].length = len;
420 232848 : jstate->clocations[jstate->clocations_count].squashed = (len > -1);
421 232848 : jstate->clocations[jstate->clocations_count].extern_param = extern_param;
422 232848 : jstate->clocations_count++;
423 : }
424 245994 : }
425 :
426 : /*
427 : * Subroutine for _jumbleElements: Verify a few simple cases where we can
428 : * deduce that the expression is a constant:
429 : *
430 : * - See through any wrapping RelabelType and CoerceViaIO layers.
431 : * - If it's a FuncExpr, check that the function is a builtin
432 : * cast and its arguments are Const.
433 : * - Otherwise test if the expression is a simple Const or a
434 : * PARAM_EXTERN param.
435 : */
436 : static bool
437 12796 : IsSquashableConstant(Node *element)
438 : {
439 582 : restart:
440 13378 : switch (nodeTag(element))
441 : {
442 442 : case T_RelabelType:
443 : /* Unwrap RelabelType */
444 442 : element = (Node *) ((RelabelType *) element)->arg;
445 442 : goto restart;
446 :
447 140 : case T_CoerceViaIO:
448 : /* Unwrap CoerceViaIO */
449 140 : element = (Node *) ((CoerceViaIO *) element)->arg;
450 140 : goto restart;
451 :
452 11830 : case T_Const:
453 11830 : return true;
454 :
455 146 : case T_Param:
456 146 : return castNode(Param, element)->paramkind == PARAM_EXTERN;
457 :
458 612 : case T_FuncExpr:
459 : {
460 612 : FuncExpr *func = (FuncExpr *) element;
461 : ListCell *temp;
462 :
463 612 : if (func->funcformat != COERCE_IMPLICIT_CAST &&
464 380 : func->funcformat != COERCE_EXPLICIT_CAST)
465 254 : return false;
466 :
467 358 : if (func->funcid > FirstGenbkiObjectId)
468 0 : return false;
469 :
470 : /*
471 : * We can check function arguments recursively, being careful
472 : * about recursing too deep. At each recursion level it's
473 : * enough to test the stack on the first element. (Note that
474 : * I wasn't able to hit this without bloating the stack
475 : * artificially in this function: the parser errors out before
476 : * stack size becomes a problem here.)
477 : */
478 710 : foreach(temp, func->args)
479 : {
480 358 : Node *arg = lfirst(temp);
481 :
482 358 : if (!IsA(arg, Const))
483 : {
484 28 : if (foreach_current_index(temp) == 0 &&
485 14 : stack_is_too_deep())
486 6 : return false;
487 14 : else if (!IsSquashableConstant(arg))
488 6 : return false;
489 : }
490 : }
491 :
492 352 : return true;
493 : }
494 :
495 208 : default:
496 208 : return false;
497 : }
498 : }
499 :
500 : /*
501 : * Subroutine for _jumbleElements: Verify whether the provided list
502 : * can be squashed, meaning it contains only constant expressions.
503 : *
504 : * Return value indicates if squashing is possible.
505 : *
506 : * Note that this function searches only for explicit Const nodes with
507 : * possibly very simple decorations on top and PARAM_EXTERN parameters,
508 : * and does not try to simplify expressions.
509 : */
510 : static bool
511 4822 : IsSquashableConstantList(List *elements)
512 : {
513 : ListCell *temp;
514 :
515 : /* If the list is too short, we don't try to squash it. */
516 4822 : if (list_length(elements) < 2)
517 440 : return false;
518 :
519 16702 : foreach(temp, elements)
520 : {
521 12782 : if (!IsSquashableConstant(lfirst(temp)))
522 462 : return false;
523 : }
524 :
525 3920 : return true;
526 : }
527 :
528 : #define JUMBLE_NODE(item) \
529 : _jumbleNode(jstate, (Node *) expr->item)
530 : #define JUMBLE_ELEMENTS(list, node) \
531 : _jumbleElements(jstate, (List *) expr->list, node)
532 : #define JUMBLE_LOCATION(location) \
533 : RecordConstLocation(jstate, false, expr->location, -1)
534 : #define JUMBLE_FIELD(item) \
535 : do { \
536 : if (sizeof(expr->item) == 8) \
537 : AppendJumble64(jstate, (const unsigned char *) &(expr->item)); \
538 : else if (sizeof(expr->item) == 4) \
539 : AppendJumble32(jstate, (const unsigned char *) &(expr->item)); \
540 : else if (sizeof(expr->item) == 2) \
541 : AppendJumble16(jstate, (const unsigned char *) &(expr->item)); \
542 : else if (sizeof(expr->item) == 1) \
543 : AppendJumble8(jstate, (const unsigned char *) &(expr->item)); \
544 : else \
545 : AppendJumble(jstate, (const unsigned char *) &(expr->item), sizeof(expr->item)); \
546 : } while (0)
547 : #define JUMBLE_STRING(str) \
548 : do { \
549 : if (expr->str) \
550 : AppendJumble(jstate, (const unsigned char *) (expr->str), strlen(expr->str) + 1); \
551 : else \
552 : AppendJumbleNull(jstate); \
553 : } while(0)
554 : /* Function name used for the node field attribute custom_query_jumble. */
555 : #define JUMBLE_CUSTOM(nodetype, item) \
556 : _jumble##nodetype##_##item(jstate, expr, expr->item)
557 :
558 : #include "queryjumblefuncs.funcs.c"
559 :
560 : static void
561 7621152 : _jumbleNode(JumbleState *jstate, Node *node)
562 : {
563 7621152 : Node *expr = node;
564 : #ifdef USE_ASSERT_CHECKING
565 : Size prev_jumble_len = jstate->total_jumble_len;
566 : #endif
567 :
568 7621152 : if (expr == NULL)
569 : {
570 4483610 : AppendJumbleNull(jstate);
571 4483610 : return;
572 : }
573 :
574 : /* Guard against stack overflow due to overly complex expressions */
575 3137542 : check_stack_depth();
576 :
577 : /*
578 : * We always emit the node's NodeTag, then any additional fields that are
579 : * considered significant, and then we recurse to any child nodes.
580 : */
581 3137542 : JUMBLE_FIELD(type);
582 :
583 3137542 : switch (nodeTag(expr))
584 : {
585 : #include "queryjumblefuncs.switch.c"
586 :
587 751920 : case T_List:
588 : case T_IntList:
589 : case T_OidList:
590 : case T_XidList:
591 751920 : _jumbleList(jstate, expr);
592 751920 : break;
593 :
594 0 : default:
595 : /* Only a warning, since we can stumble along anyway */
596 0 : elog(WARNING, "unrecognized node type: %d",
597 : (int) nodeTag(expr));
598 0 : break;
599 : }
600 :
601 : /* Ensure we added something to the jumble buffer */
602 : Assert(jstate->total_jumble_len > prev_jumble_len);
603 : }
604 :
605 : static void
606 751920 : _jumbleList(JumbleState *jstate, Node *node)
607 : {
608 751920 : List *expr = (List *) node;
609 : ListCell *l;
610 :
611 751920 : switch (expr->type)
612 : {
613 750972 : case T_List:
614 2108128 : foreach(l, expr)
615 1357156 : _jumbleNode(jstate, lfirst(l));
616 750972 : break;
617 948 : case T_IntList:
618 2112 : foreach(l, expr)
619 1164 : AppendJumble32(jstate, (const unsigned char *) &lfirst_int(l));
620 948 : break;
621 0 : case T_OidList:
622 0 : foreach(l, expr)
623 0 : AppendJumble32(jstate, (const unsigned char *) &lfirst_oid(l));
624 0 : break;
625 0 : case T_XidList:
626 0 : foreach(l, expr)
627 0 : AppendJumble32(jstate, (const unsigned char *) &lfirst_xid(l));
628 0 : break;
629 0 : default:
630 0 : elog(ERROR, "unrecognized list node type: %d",
631 : (int) expr->type);
632 : return;
633 : }
634 : }
635 :
636 : /*
637 : * We try to jumble lists of expressions as one individual item regardless
638 : * of how many elements are in the list. This is know as squashing, which
639 : * results in different queries jumbling to the same query_id, if the only
640 : * difference is the number of elements in the list.
641 : *
642 : * We allow constants and PARAM_EXTERN parameters to be squashed. To normalize
643 : * such queries, we use the start and end locations of the list of elements in
644 : * a list.
645 : */
646 : static void
647 4822 : _jumbleElements(JumbleState *jstate, List *elements, Node *node)
648 : {
649 4822 : bool normalize_list = false;
650 :
651 4822 : if (IsSquashableConstantList(elements))
652 : {
653 3920 : if (IsA(node, ArrayExpr))
654 : {
655 3920 : ArrayExpr *aexpr = (ArrayExpr *) node;
656 :
657 3920 : if (aexpr->list_start > 0 && aexpr->list_end > 0)
658 : {
659 3840 : RecordConstLocation(jstate,
660 : false,
661 3840 : aexpr->list_start + 1,
662 3840 : (aexpr->list_end - aexpr->list_start) - 1);
663 3840 : normalize_list = true;
664 3840 : jstate->has_squashed_lists = true;
665 : }
666 : }
667 : }
668 :
669 4822 : if (!normalize_list)
670 : {
671 982 : _jumbleNode(jstate, (Node *) elements);
672 : }
673 4822 : }
674 :
675 : /*
676 : * We store the highest param ID of extern params. This can later be used
677 : * to start the numbering of the placeholder for squashed lists.
678 : */
679 : static void
680 10714 : _jumbleParam(JumbleState *jstate, Node *node)
681 : {
682 10714 : Param *expr = (Param *) node;
683 :
684 10714 : JUMBLE_FIELD(paramkind);
685 10714 : JUMBLE_FIELD(paramid);
686 10714 : JUMBLE_FIELD(paramtype);
687 : /* paramtypmode and paramcollid are ignored */
688 :
689 10714 : if (expr->paramkind == PARAM_EXTERN)
690 : {
691 : /*
692 : * At this point, only external parameter locations outside of
693 : * squashable lists will be recorded.
694 : */
695 9004 : RecordConstLocation(jstate, true, expr->location, -1);
696 :
697 : /*
698 : * Update the highest Param id seen, in order to start normalization
699 : * correctly.
700 : *
701 : * Note: This value is reset at the end of jumbling if there exists a
702 : * squashable list. See the comment in the definition of JumbleState.
703 : */
704 9004 : if (expr->paramid > jstate->highest_extern_param_id)
705 7674 : jstate->highest_extern_param_id = expr->paramid;
706 : }
707 10714 : }
708 :
709 : static void
710 16912 : _jumbleA_Const(JumbleState *jstate, Node *node)
711 : {
712 16912 : A_Const *expr = (A_Const *) node;
713 :
714 16912 : JUMBLE_FIELD(isnull);
715 16912 : if (!expr->isnull)
716 : {
717 16740 : JUMBLE_FIELD(val.node.type);
718 16740 : switch (nodeTag(&expr->val))
719 : {
720 7616 : case T_Integer:
721 7616 : JUMBLE_FIELD(val.ival.ival);
722 7616 : break;
723 58 : case T_Float:
724 58 : JUMBLE_STRING(val.fval.fval);
725 58 : break;
726 250 : case T_Boolean:
727 250 : JUMBLE_FIELD(val.boolval.boolval);
728 250 : break;
729 8812 : case T_String:
730 8812 : JUMBLE_STRING(val.sval.sval);
731 8812 : break;
732 4 : case T_BitString:
733 4 : JUMBLE_STRING(val.bsval.bsval);
734 4 : break;
735 0 : default:
736 0 : elog(ERROR, "unrecognized node type: %d",
737 : (int) nodeTag(&expr->val));
738 : break;
739 : }
740 : }
741 16912 : }
742 :
743 : static void
744 5122 : _jumbleVariableSetStmt(JumbleState *jstate, Node *node)
745 : {
746 5122 : VariableSetStmt *expr = (VariableSetStmt *) node;
747 :
748 5122 : JUMBLE_FIELD(kind);
749 5122 : JUMBLE_STRING(name);
750 :
751 : /*
752 : * Account for the list of arguments in query jumbling only if told by the
753 : * parser.
754 : */
755 5122 : if (expr->jumble_args)
756 120 : JUMBLE_NODE(args);
757 5122 : JUMBLE_FIELD(is_local);
758 5122 : JUMBLE_LOCATION(location);
759 5122 : }
760 :
761 : /*
762 : * Custom query jumble function for RangeTblEntry.eref.
763 : */
764 : static void
765 157274 : _jumbleRangeTblEntry_eref(JumbleState *jstate,
766 : RangeTblEntry *rte,
767 : Alias *expr)
768 : {
769 157274 : JUMBLE_FIELD(type);
770 :
771 : /*
772 : * This includes only the table name, the list of column names is ignored.
773 : */
774 157274 : JUMBLE_STRING(aliasname);
775 157274 : }
|