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 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
25 : * Portions Copyright (c) 1994, Regents of the University of California
26 : *
27 : *
28 : * IDENTIFICATION
29 : * src/backend/nodes/queryjumblefuncs.c
30 : *
31 : *-------------------------------------------------------------------------
32 : */
33 : #include "postgres.h"
34 :
35 : #include "access/transam.h"
36 : #include "catalog/pg_proc.h"
37 : #include "common/hashfn.h"
38 : #include "miscadmin.h"
39 : #include "nodes/nodeFuncs.h"
40 : #include "nodes/queryjumble.h"
41 : #include "utils/lsyscache.h"
42 : #include "parser/scansup.h"
43 :
44 : #define JUMBLE_SIZE 1024 /* query serialization buffer size */
45 :
46 : /* GUC parameters */
47 : int compute_query_id = COMPUTE_QUERY_ID_AUTO;
48 :
49 : /*
50 : * True when compute_query_id is ON or AUTO, and a module requests them.
51 : *
52 : * Note that IsQueryIdEnabled() should be used instead of checking
53 : * query_id_enabled or compute_query_id directly when we want to know
54 : * whether query identifiers are computed in the core or not.
55 : */
56 : bool query_id_enabled = false;
57 :
58 : static JumbleState *InitJumble(void);
59 : static uint64 DoJumble(JumbleState *jstate, Node *node);
60 : static void AppendJumble(JumbleState *jstate,
61 : const unsigned char *item, Size size);
62 : static void FlushPendingNulls(JumbleState *jstate);
63 : static void RecordConstLocation(JumbleState *jstate,
64 : int location, bool merged);
65 : static void _jumbleNode(JumbleState *jstate, Node *node);
66 : static void _jumbleElements(JumbleState *jstate, List *elements);
67 : static void _jumbleA_Const(JumbleState *jstate, Node *node);
68 : static void _jumbleList(JumbleState *jstate, Node *node);
69 : static void _jumbleVariableSetStmt(JumbleState *jstate, Node *node);
70 : static void _jumbleRangeTblEntry_eref(JumbleState *jstate,
71 : RangeTblEntry *rte,
72 : Alias *expr);
73 :
74 : /*
75 : * Given a possibly multi-statement source string, confine our attention to the
76 : * relevant part of the string.
77 : */
78 : const char *
79 186342 : CleanQuerytext(const char *query, int *location, int *len)
80 : {
81 186342 : int query_location = *location;
82 186342 : int query_len = *len;
83 :
84 : /* First apply starting offset, unless it's -1 (unknown). */
85 186342 : if (query_location >= 0)
86 : {
87 : Assert(query_location <= strlen(query));
88 185968 : query += query_location;
89 : /* Length of 0 (or -1) means "rest of string" */
90 185968 : if (query_len <= 0)
91 30534 : query_len = strlen(query);
92 : else
93 : Assert(query_len <= strlen(query));
94 : }
95 : else
96 : {
97 : /* If query location is unknown, distrust query_len as well */
98 374 : query_location = 0;
99 374 : query_len = strlen(query);
100 : }
101 :
102 : /*
103 : * Discard leading and trailing whitespace, too. Use scanner_isspace()
104 : * not libc's isspace(), because we want to match the lexer's behavior.
105 : *
106 : * Note: the parser now strips leading comments and whitespace from the
107 : * reported stmt_location, so this first loop will only iterate in the
108 : * unusual case that the location didn't propagate to here. But the
109 : * statement length will extend to the end-of-string or terminating
110 : * semicolon, so the second loop often does something useful.
111 : */
112 186364 : while (query_len > 0 && scanner_isspace(query[0]))
113 22 : query++, query_location++, query_len--;
114 187518 : while (query_len > 0 && scanner_isspace(query[query_len - 1]))
115 1176 : query_len--;
116 :
117 186342 : *location = query_location;
118 186342 : *len = query_len;
119 :
120 186342 : return query;
121 : }
122 :
123 : /*
124 : * JumbleQuery
125 : * Recursively process the given Query producing a 64-bit hash value by
126 : * hashing the relevant fields and record that value in the Query's queryId
127 : * field. Return the JumbleState object used for jumbling the query.
128 : */
129 : JumbleState *
130 154894 : JumbleQuery(Query *query)
131 : {
132 : JumbleState *jstate;
133 :
134 : Assert(IsQueryIdEnabled());
135 :
136 154894 : jstate = InitJumble();
137 :
138 154894 : query->queryId = DoJumble(jstate, (Node *) query);
139 :
140 : /*
141 : * If we are unlucky enough to get a hash of zero, use 1 instead for
142 : * normal statements and 2 for utility queries.
143 : */
144 154894 : if (query->queryId == UINT64CONST(0))
145 : {
146 0 : if (query->utilityStmt)
147 0 : query->queryId = UINT64CONST(2);
148 : else
149 0 : query->queryId = UINT64CONST(1);
150 : }
151 :
152 154894 : return jstate;
153 : }
154 :
155 : /*
156 : * Enables query identifier computation.
157 : *
158 : * Third-party plugins can use this function to inform core that they require
159 : * a query identifier to be computed.
160 : */
161 : void
162 14 : EnableQueryId(void)
163 : {
164 14 : if (compute_query_id != COMPUTE_QUERY_ID_OFF)
165 14 : query_id_enabled = true;
166 14 : }
167 :
168 : /*
169 : * InitJumble
170 : * Allocate a JumbleState object and make it ready to jumble.
171 : */
172 : static JumbleState *
173 154894 : InitJumble(void)
174 : {
175 : JumbleState *jstate;
176 :
177 154894 : jstate = (JumbleState *) palloc(sizeof(JumbleState));
178 :
179 : /* Set up workspace for query jumbling */
180 154894 : jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
181 154894 : jstate->jumble_len = 0;
182 154894 : jstate->clocations_buf_size = 32;
183 154894 : jstate->clocations = (LocationLen *) palloc(jstate->clocations_buf_size *
184 : sizeof(LocationLen));
185 154894 : jstate->clocations_count = 0;
186 154894 : jstate->highest_extern_param_id = 0;
187 154894 : jstate->pending_nulls = 0;
188 : #ifdef USE_ASSERT_CHECKING
189 : jstate->total_jumble_len = 0;
190 : #endif
191 :
192 154894 : return jstate;
193 : }
194 :
195 : /*
196 : * DoJumble
197 : * Jumble the given Node using the given JumbleState and return the resulting
198 : * jumble hash.
199 : */
200 : static uint64
201 154894 : DoJumble(JumbleState *jstate, Node *node)
202 : {
203 : /* Jumble the given node */
204 154894 : _jumbleNode(jstate, node);
205 :
206 : /* Flush any pending NULLs before doing the final hash */
207 154894 : if (jstate->pending_nulls > 0)
208 153454 : FlushPendingNulls(jstate);
209 :
210 : /* Process the jumble buffer and produce the hash value */
211 154894 : return DatumGetUInt64(hash_any_extended(jstate->jumble,
212 154894 : jstate->jumble_len,
213 : 0));
214 : }
215 :
216 : /*
217 : * AppendJumbleInternal: Internal function for appending to the jumble buffer
218 : *
219 : * Note: Callers must ensure that size > 0.
220 : */
221 : static pg_attribute_always_inline void
222 10627102 : AppendJumbleInternal(JumbleState *jstate, const unsigned char *item,
223 : Size size)
224 : {
225 10627102 : unsigned char *jumble = jstate->jumble;
226 10627102 : Size jumble_len = jstate->jumble_len;
227 :
228 : /* Ensure the caller didn't mess up */
229 : Assert(size > 0);
230 :
231 : /*
232 : * Fast path for when there's enough space left in the buffer. This is
233 : * worthwhile as means the memcpy can be inlined into very efficient code
234 : * when 'size' is a compile-time constant.
235 : */
236 10627102 : if (likely(size <= JUMBLE_SIZE - jumble_len))
237 : {
238 10621096 : memcpy(jumble + jumble_len, item, size);
239 10621096 : jstate->jumble_len += size;
240 :
241 : #ifdef USE_ASSERT_CHECKING
242 : jstate->total_jumble_len += size;
243 : #endif
244 :
245 10621096 : return;
246 : }
247 :
248 : /*
249 : * Whenever the jumble buffer is full, we hash the current contents and
250 : * reset the buffer to contain just that hash value, thus relying on the
251 : * hash to summarize everything so far.
252 : */
253 : do
254 : {
255 : Size part_size;
256 :
257 10602 : if (unlikely(jumble_len >= JUMBLE_SIZE))
258 : {
259 : uint64 start_hash;
260 :
261 6204 : start_hash = DatumGetUInt64(hash_any_extended(jumble,
262 : JUMBLE_SIZE, 0));
263 6204 : memcpy(jumble, &start_hash, sizeof(start_hash));
264 6204 : jumble_len = sizeof(start_hash);
265 : }
266 10602 : part_size = Min(size, JUMBLE_SIZE - jumble_len);
267 10602 : memcpy(jumble + jumble_len, item, part_size);
268 10602 : jumble_len += part_size;
269 10602 : item += part_size;
270 10602 : size -= part_size;
271 :
272 : #ifdef USE_ASSERT_CHECKING
273 : jstate->total_jumble_len += part_size;
274 : #endif
275 10602 : } while (size > 0);
276 :
277 6006 : jstate->jumble_len = jumble_len;
278 : }
279 :
280 : /*
281 : * AppendJumble
282 : * Add 'size' bytes of the given jumble 'value' to the jumble state
283 : */
284 : static pg_noinline void
285 369858 : AppendJumble(JumbleState *jstate, const unsigned char *value, Size size)
286 : {
287 369858 : if (jstate->pending_nulls > 0)
288 55188 : FlushPendingNulls(jstate);
289 :
290 369858 : AppendJumbleInternal(jstate, value, size);
291 369858 : }
292 :
293 : /*
294 : * AppendJumbleNull
295 : * For jumbling NULL pointers
296 : */
297 : static pg_attribute_always_inline void
298 4886184 : AppendJumbleNull(JumbleState *jstate)
299 : {
300 4886184 : jstate->pending_nulls++;
301 4886184 : }
302 :
303 : /*
304 : * AppendJumble8
305 : * Add the first byte from the given 'value' pointer to the jumble state
306 : */
307 : static pg_noinline void
308 1000954 : AppendJumble8(JumbleState *jstate, const unsigned char *value)
309 : {
310 1000954 : if (jstate->pending_nulls > 0)
311 401962 : FlushPendingNulls(jstate);
312 :
313 1000954 : AppendJumbleInternal(jstate, value, 1);
314 1000954 : }
315 :
316 : /*
317 : * AppendJumble16
318 : * Add the first 2 bytes from the given 'value' pointer to the jumble
319 : * state.
320 : */
321 : static pg_noinline void
322 784246 : AppendJumble16(JumbleState *jstate, const unsigned char *value)
323 : {
324 784246 : if (jstate->pending_nulls > 0)
325 39012 : FlushPendingNulls(jstate);
326 :
327 784246 : AppendJumbleInternal(jstate, value, 2);
328 784246 : }
329 :
330 : /*
331 : * AppendJumble32
332 : * Add the first 4 bytes from the given 'value' pointer to the jumble
333 : * state.
334 : */
335 : static pg_noinline void
336 6703260 : AppendJumble32(JumbleState *jstate, const unsigned char *value)
337 : {
338 6703260 : if (jstate->pending_nulls > 0)
339 1118078 : FlushPendingNulls(jstate);
340 :
341 6703260 : AppendJumbleInternal(jstate, value, 4);
342 6703260 : }
343 :
344 : /*
345 : * AppendJumble64
346 : * Add the first 8 bytes from the given 'value' pointer to the jumble
347 : * state.
348 : */
349 : static pg_noinline void
350 1090 : AppendJumble64(JumbleState *jstate, const unsigned char *value)
351 : {
352 1090 : if (jstate->pending_nulls > 0)
353 0 : FlushPendingNulls(jstate);
354 :
355 1090 : AppendJumbleInternal(jstate, value, 8);
356 1090 : }
357 :
358 : /*
359 : * FlushPendingNulls
360 : * Incorporate the pending_null value into the jumble buffer.
361 : *
362 : * Note: Callers must ensure that there's at least 1 pending NULL.
363 : */
364 : static pg_attribute_always_inline void
365 1767694 : FlushPendingNulls(JumbleState *jstate)
366 : {
367 : Assert(jstate->pending_nulls > 0);
368 :
369 1767694 : AppendJumbleInternal(jstate,
370 1767694 : (const unsigned char *) &jstate->pending_nulls, 4);
371 1767694 : jstate->pending_nulls = 0;
372 1767694 : }
373 :
374 :
375 : /*
376 : * Record location of constant within query string of query tree that is
377 : * currently being walked.
378 : *
379 : * 'squashed' signals that the constant represents the first or the last
380 : * element in a series of merged constants, and everything but the first/last
381 : * element contributes nothing to the jumble hash.
382 : */
383 : static void
384 229752 : RecordConstLocation(JumbleState *jstate, int location, bool squashed)
385 : {
386 : /* -1 indicates unknown or undefined location */
387 229752 : if (location >= 0)
388 : {
389 : /* enlarge array if needed */
390 216704 : if (jstate->clocations_count >= jstate->clocations_buf_size)
391 : {
392 118 : jstate->clocations_buf_size *= 2;
393 118 : jstate->clocations = (LocationLen *)
394 118 : repalloc(jstate->clocations,
395 118 : jstate->clocations_buf_size *
396 : sizeof(LocationLen));
397 : }
398 216704 : jstate->clocations[jstate->clocations_count].location = location;
399 : /* initialize lengths to -1 to simplify third-party module usage */
400 216704 : jstate->clocations[jstate->clocations_count].squashed = squashed;
401 216704 : jstate->clocations[jstate->clocations_count].length = -1;
402 216704 : jstate->clocations_count++;
403 : }
404 229752 : }
405 :
406 : /*
407 : * Subroutine for _jumbleElements: Verify a few simple cases where we can
408 : * deduce that the expression is a constant:
409 : *
410 : * - Ignore a possible wrapping RelabelType and CoerceViaIO.
411 : * - If it's a FuncExpr, check that the function is an implicit
412 : * cast and its arguments are Const.
413 : * - Otherwise test if the expression is a simple Const.
414 : */
415 : static bool
416 12098 : IsSquashableConst(Node *element)
417 : {
418 12098 : if (IsA(element, RelabelType))
419 386 : element = (Node *) ((RelabelType *) element)->arg;
420 :
421 12098 : if (IsA(element, CoerceViaIO))
422 68 : element = (Node *) ((CoerceViaIO *) element)->arg;
423 :
424 12098 : if (IsA(element, FuncExpr))
425 : {
426 568 : FuncExpr *func = (FuncExpr *) element;
427 : ListCell *temp;
428 :
429 568 : if (func->funcformat != COERCE_IMPLICIT_CAST &&
430 336 : func->funcformat != COERCE_EXPLICIT_CAST)
431 252 : return false;
432 :
433 316 : if (func->funcid > FirstGenbkiObjectId)
434 0 : return false;
435 :
436 626 : foreach(temp, func->args)
437 : {
438 316 : Node *arg = lfirst(temp);
439 :
440 316 : if (!IsA(arg, Const)) /* XXX we could recurse here instead */
441 6 : return false;
442 : }
443 :
444 310 : return true;
445 : }
446 :
447 11530 : if (!IsA(element, Const))
448 234 : return false;
449 :
450 11296 : return true;
451 : }
452 :
453 : /*
454 : * Subroutine for _jumbleElements: Verify whether the provided list
455 : * can be squashed, meaning it contains only constant expressions.
456 : *
457 : * Return value indicates if squashing is possible.
458 : *
459 : * Note that this function searches only for explicit Const nodes with
460 : * possibly very simple decorations on top, and does not try to simplify
461 : * expressions.
462 : */
463 : static bool
464 4656 : IsSquashableConstList(List *elements, Node **firstExpr, Node **lastExpr)
465 : {
466 : ListCell *temp;
467 :
468 : /*
469 : * If squashing is disabled, or the list is too short, we don't try to
470 : * squash it.
471 : */
472 4656 : if (list_length(elements) < 2)
473 438 : return false;
474 :
475 15824 : foreach(temp, elements)
476 : {
477 12098 : if (!IsSquashableConst(lfirst(temp)))
478 492 : return false;
479 : }
480 :
481 3726 : *firstExpr = linitial(elements);
482 3726 : *lastExpr = llast(elements);
483 :
484 3726 : return true;
485 : }
486 :
487 : #define JUMBLE_NODE(item) \
488 : _jumbleNode(jstate, (Node *) expr->item)
489 : #define JUMBLE_ELEMENTS(list) \
490 : _jumbleElements(jstate, (List *) expr->list)
491 : #define JUMBLE_LOCATION(location) \
492 : RecordConstLocation(jstate, expr->location, false)
493 : #define JUMBLE_FIELD(item) \
494 : do { \
495 : if (sizeof(expr->item) == 8) \
496 : AppendJumble64(jstate, (const unsigned char *) &(expr->item)); \
497 : else if (sizeof(expr->item) == 4) \
498 : AppendJumble32(jstate, (const unsigned char *) &(expr->item)); \
499 : else if (sizeof(expr->item) == 2) \
500 : AppendJumble16(jstate, (const unsigned char *) &(expr->item)); \
501 : else if (sizeof(expr->item) == 1) \
502 : AppendJumble8(jstate, (const unsigned char *) &(expr->item)); \
503 : else \
504 : AppendJumble(jstate, (const unsigned char *) &(expr->item), sizeof(expr->item)); \
505 : } while (0)
506 : #define JUMBLE_STRING(str) \
507 : do { \
508 : if (expr->str) \
509 : AppendJumble(jstate, (const unsigned char *) (expr->str), strlen(expr->str) + 1); \
510 : else \
511 : AppendJumbleNull(jstate); \
512 : } while(0)
513 : /* Function name used for the node field attribute custom_query_jumble. */
514 : #define JUMBLE_CUSTOM(nodetype, item) \
515 : _jumble##nodetype##_##item(jstate, expr, expr->item)
516 :
517 : #include "queryjumblefuncs.funcs.c"
518 :
519 : /*
520 : * We jumble lists of constant elements as one individual item regardless
521 : * of how many elements are in the list. This means different queries
522 : * jumble to the same query_id, if the only difference is the number of
523 : * elements in the list.
524 : */
525 : static void
526 4656 : _jumbleElements(JumbleState *jstate, List *elements)
527 : {
528 : Node *first,
529 : *last;
530 :
531 4656 : if (IsSquashableConstList(elements, &first, &last))
532 : {
533 : /*
534 : * If this list of elements is squashable, keep track of the location
535 : * of its first and last elements. When reading back the locations
536 : * array, we'll see two consecutive locations with ->squashed set to
537 : * true, indicating the location of initial and final elements of this
538 : * list.
539 : *
540 : * For the limited set of cases we support now (implicit coerce via
541 : * FuncExpr, Const) it's fine to use exprLocation of the 'last'
542 : * expression, but if more complex composite expressions are to be
543 : * supported (e.g., OpExpr or FuncExpr as an explicit call), more
544 : * sophisticated tracking will be needed.
545 : */
546 3726 : RecordConstLocation(jstate, exprLocation(first), true);
547 3726 : RecordConstLocation(jstate, exprLocation(last), true);
548 : }
549 : else
550 : {
551 930 : _jumbleNode(jstate, (Node *) elements);
552 : }
553 4656 : }
554 :
555 : static void
556 7450920 : _jumbleNode(JumbleState *jstate, Node *node)
557 : {
558 7450920 : Node *expr = node;
559 : #ifdef USE_ASSERT_CHECKING
560 : Size prev_jumble_len = jstate->total_jumble_len;
561 : #endif
562 :
563 7450920 : if (expr == NULL)
564 : {
565 4416694 : AppendJumbleNull(jstate);
566 4416694 : return;
567 : }
568 :
569 : /* Guard against stack overflow due to overly complex expressions */
570 3034226 : check_stack_depth();
571 :
572 : /*
573 : * We always emit the node's NodeTag, then any additional fields that are
574 : * considered significant, and then we recurse to any child nodes.
575 : */
576 3034226 : JUMBLE_FIELD(type);
577 :
578 3034226 : switch (nodeTag(expr))
579 : {
580 : #include "queryjumblefuncs.switch.c"
581 :
582 724854 : case T_List:
583 : case T_IntList:
584 : case T_OidList:
585 : case T_XidList:
586 724854 : _jumbleList(jstate, expr);
587 724854 : break;
588 :
589 0 : default:
590 : /* Only a warning, since we can stumble along anyway */
591 0 : elog(WARNING, "unrecognized node type: %d",
592 : (int) nodeTag(expr));
593 0 : break;
594 : }
595 :
596 : /* Special cases to handle outside the automated code */
597 3034226 : switch (nodeTag(expr))
598 : {
599 10558 : case T_Param:
600 : {
601 10558 : Param *p = (Param *) node;
602 :
603 : /*
604 : * Update the highest Param id seen, in order to start
605 : * normalization correctly.
606 : */
607 10558 : if (p->paramkind == PARAM_EXTERN &&
608 9778 : p->paramid > jstate->highest_extern_param_id)
609 8496 : jstate->highest_extern_param_id = p->paramid;
610 : }
611 10558 : break;
612 3023668 : default:
613 3023668 : break;
614 : }
615 :
616 : /* Ensure we added something to the jumble buffer */
617 : Assert(jstate->total_jumble_len > prev_jumble_len);
618 : }
619 :
620 : static void
621 724854 : _jumbleList(JumbleState *jstate, Node *node)
622 : {
623 724854 : List *expr = (List *) node;
624 : ListCell *l;
625 :
626 724854 : switch (expr->type)
627 : {
628 723912 : case T_List:
629 2032134 : foreach(l, expr)
630 1308222 : _jumbleNode(jstate, lfirst(l));
631 723912 : break;
632 942 : case T_IntList:
633 2100 : foreach(l, expr)
634 1158 : AppendJumble32(jstate, (const unsigned char *) &lfirst_int(l));
635 942 : break;
636 0 : case T_OidList:
637 0 : foreach(l, expr)
638 0 : AppendJumble32(jstate, (const unsigned char *) &lfirst_oid(l));
639 0 : break;
640 0 : case T_XidList:
641 0 : foreach(l, expr)
642 0 : AppendJumble32(jstate, (const unsigned char *) &lfirst_xid(l));
643 0 : break;
644 0 : default:
645 0 : elog(ERROR, "unrecognized list node type: %d",
646 : (int) expr->type);
647 : return;
648 : }
649 : }
650 :
651 : static void
652 18192 : _jumbleA_Const(JumbleState *jstate, Node *node)
653 : {
654 18192 : A_Const *expr = (A_Const *) node;
655 :
656 18192 : JUMBLE_FIELD(isnull);
657 18192 : if (!expr->isnull)
658 : {
659 18044 : JUMBLE_FIELD(val.node.type);
660 18044 : switch (nodeTag(&expr->val))
661 : {
662 7502 : case T_Integer:
663 7502 : JUMBLE_FIELD(val.ival.ival);
664 7502 : break;
665 42 : case T_Float:
666 42 : JUMBLE_STRING(val.fval.fval);
667 42 : break;
668 246 : case T_Boolean:
669 246 : JUMBLE_FIELD(val.boolval.boolval);
670 246 : break;
671 10250 : case T_String:
672 10250 : JUMBLE_STRING(val.sval.sval);
673 10250 : break;
674 4 : case T_BitString:
675 4 : JUMBLE_STRING(val.bsval.bsval);
676 4 : break;
677 0 : default:
678 0 : elog(ERROR, "unrecognized node type: %d",
679 : (int) nodeTag(&expr->val));
680 : break;
681 : }
682 148 : }
683 18192 : }
684 :
685 : static void
686 5064 : _jumbleVariableSetStmt(JumbleState *jstate, Node *node)
687 : {
688 5064 : VariableSetStmt *expr = (VariableSetStmt *) node;
689 :
690 5064 : JUMBLE_FIELD(kind);
691 5064 : JUMBLE_STRING(name);
692 :
693 : /*
694 : * Account for the list of arguments in query jumbling only if told by the
695 : * parser.
696 : */
697 5064 : if (expr->jumble_args)
698 120 : JUMBLE_NODE(args);
699 5064 : JUMBLE_FIELD(is_local);
700 5064 : JUMBLE_LOCATION(location);
701 5064 : }
702 :
703 : /*
704 : * Custom query jumble function for RangeTblEntry.eref.
705 : */
706 : static void
707 151456 : _jumbleRangeTblEntry_eref(JumbleState *jstate,
708 : RangeTblEntry *rte,
709 : Alias *expr)
710 : {
711 151456 : JUMBLE_FIELD(type);
712 :
713 : /*
714 : * This includes only the table name, the list of column names is ignored.
715 : */
716 151456 : JUMBLE_STRING(aliasname);
717 151456 : }
|