LCOV - code coverage report
Current view: top level - src/backend/nodes - queryjumblefuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 204 224 91.1 %
Date: 2025-04-01 15:15:16 Functions: 22 22 100.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.14