LCOV - differential code coverage report
Current view: top level - src/backend/nodes - queryjumblefuncs.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 86.6 % 134 116 18 116 4 32
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 8 8 8 1
Baseline: 16@8cea358b128 Branches: 83.9 % 353 296 14 4 39 11 12 273
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 86.6 % 134 116 18 116
Function coverage date bins:
(240..) days: 100.0 % 8 8 8
Branch coverage date bins:
(240..) days: 83.9 % 353 296 14 4 39 11 12 273

 Age         Owner                    Branch data    TLA  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-2024, 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 "common/hashfn.h"
                                 36                 :                : #include "miscadmin.h"
                                 37                 :                : #include "nodes/queryjumble.h"
                                 38                 :                : #include "parser/scansup.h"
                                 39                 :                : 
                                 40                 :                : #define JUMBLE_SIZE             1024    /* query serialization buffer size */
                                 41                 :                : 
                                 42                 :                : /* GUC parameters */
                                 43                 :                : int         compute_query_id = COMPUTE_QUERY_ID_AUTO;
                                 44                 :                : 
                                 45                 :                : /*
                                 46                 :                :  * True when compute_query_id is ON or AUTO, and a module requests them.
                                 47                 :                :  *
                                 48                 :                :  * Note that IsQueryIdEnabled() should be used instead of checking
                                 49                 :                :  * query_id_enabled or compute_query_id directly when we want to know
                                 50                 :                :  * whether query identifiers are computed in the core or not.
                                 51                 :                :  */
                                 52                 :                : bool        query_id_enabled = false;
                                 53                 :                : 
                                 54                 :                : static void AppendJumble(JumbleState *jstate,
                                 55                 :                :                          const unsigned char *item, Size size);
                                 56                 :                : static void RecordConstLocation(JumbleState *jstate, int location);
                                 57                 :                : static void _jumbleNode(JumbleState *jstate, Node *node);
                                 58                 :                : static void _jumbleA_Const(JumbleState *jstate, Node *node);
                                 59                 :                : static void _jumbleList(JumbleState *jstate, Node *node);
                                 60                 :                : static void _jumbleRangeTblEntry(JumbleState *jstate, Node *node);
                                 61                 :                : 
                                 62                 :                : /*
                                 63                 :                :  * Given a possibly multi-statement source string, confine our attention to the
                                 64                 :                :  * relevant part of the string.
                                 65                 :                :  */
                                 66                 :                : const char *
 1103 bruce@momjian.us           67                 :CBC       75958 : CleanQuerytext(const char *query, int *location, int *len)
                                 68                 :                : {
 1068 tgl@sss.pgh.pa.us          69                 :          75958 :     int         query_location = *location;
                                 70                 :          75958 :     int         query_len = *len;
                                 71                 :                : 
                                 72                 :                :     /* First apply starting offset, unless it's -1 (unknown). */
 1103 bruce@momjian.us           73         [ +  + ]:          75958 :     if (query_location >= 0)
                                 74                 :                :     {
                                 75         [ -  + ]:          75774 :         Assert(query_location <= strlen(query));
                                 76                 :          75774 :         query += query_location;
                                 77                 :                :         /* Length of 0 (or -1) means "rest of string" */
                                 78         [ +  + ]:          75774 :         if (query_len <= 0)
                                 79                 :           4521 :             query_len = strlen(query);
                                 80                 :                :         else
                                 81         [ -  + ]:          71253 :             Assert(query_len <= strlen(query));
                                 82                 :                :     }
                                 83                 :                :     else
                                 84                 :                :     {
                                 85                 :                :         /* If query location is unknown, distrust query_len as well */
                                 86                 :            184 :         query_location = 0;
                                 87                 :            184 :         query_len = strlen(query);
                                 88                 :                :     }
                                 89                 :                : 
                                 90                 :                :     /*
                                 91                 :                :      * Discard leading and trailing whitespace, too.  Use scanner_isspace()
                                 92                 :                :      * not libc's isspace(), because we want to match the lexer's behavior.
                                 93                 :                :      */
                                 94   [ +  -  +  + ]:          76216 :     while (query_len > 0 && scanner_isspace(query[0]))
                                 95                 :            258 :         query++, query_location++, query_len--;
                                 96   [ +  -  +  + ]:          76411 :     while (query_len > 0 && scanner_isspace(query[query_len - 1]))
                                 97                 :            453 :         query_len--;
                                 98                 :                : 
                                 99                 :          75958 :     *location = query_location;
                                100                 :          75958 :     *len = query_len;
                                101                 :                : 
                                102                 :          75958 :     return query;
                                103                 :                : }
                                104                 :                : 
                                105                 :                : JumbleState *
  291 michael@paquier.xyz       106                 :          66001 : JumbleQuery(Query *query)
                                107                 :                : {
 1103 bruce@momjian.us          108                 :          66001 :     JumbleState *jstate = NULL;
                                109                 :                : 
 1065 alvherre@alvh.no-ip.      110         [ -  + ]:          66001 :     Assert(IsQueryIdEnabled());
                                111                 :                : 
  439 michael@paquier.xyz       112                 :          66001 :     jstate = (JumbleState *) palloc(sizeof(JumbleState));
                                113                 :                : 
                                114                 :                :     /* Set up workspace for query jumbling */
                                115                 :          66001 :     jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
                                116                 :          66001 :     jstate->jumble_len = 0;
                                117                 :          66001 :     jstate->clocations_buf_size = 32;
                                118                 :          66001 :     jstate->clocations = (LocationLen *)
                                119                 :          66001 :         palloc(jstate->clocations_buf_size * sizeof(LocationLen));
                                120                 :          66001 :     jstate->clocations_count = 0;
                                121                 :          66001 :     jstate->highest_extern_param_id = 0;
                                122                 :                : 
                                123                 :                :     /* Compute query ID and mark the Query node with it */
                                124                 :          66001 :     _jumbleNode(jstate, (Node *) query);
                                125                 :          66001 :     query->queryId = DatumGetUInt64(hash_any_extended(jstate->jumble,
                                126                 :          66001 :                                                       jstate->jumble_len,
                                127                 :                :                                                       0));
                                128                 :                : 
                                129                 :                :     /*
                                130                 :                :      * If we are unlucky enough to get a hash of zero, use 1 instead for
                                131                 :                :      * normal statements and 2 for utility queries.
                                132                 :                :      */
                                133         [ -  + ]:          66001 :     if (query->queryId == UINT64CONST(0))
                                134                 :                :     {
  439 michael@paquier.xyz       135         [ #  # ]:UBC           0 :         if (query->utilityStmt)
                                136                 :              0 :             query->queryId = UINT64CONST(2);
                                137                 :                :         else
 1103 bruce@momjian.us          138                 :              0 :             query->queryId = UINT64CONST(1);
                                139                 :                :     }
                                140                 :                : 
 1103 bruce@momjian.us          141                 :CBC       66001 :     return jstate;
                                142                 :                : }
                                143                 :                : 
                                144                 :                : /*
                                145                 :                :  * Enables query identifier computation.
                                146                 :                :  *
                                147                 :                :  * Third-party plugins can use this function to inform core that they require
                                148                 :                :  * a query identifier to be computed.
                                149                 :                :  */
                                150                 :                : void
 1065 alvherre@alvh.no-ip.      151                 :              6 : EnableQueryId(void)
                                152                 :                : {
                                153         [ +  - ]:              6 :     if (compute_query_id != COMPUTE_QUERY_ID_OFF)
                                154                 :              6 :         query_id_enabled = true;
                                155                 :              6 : }
                                156                 :                : 
                                157                 :                : /*
                                158                 :                :  * AppendJumble: Append a value that is substantive in a given query to
                                159                 :                :  * the current jumble.
                                160                 :                :  */
                                161                 :                : static void
 1103 bruce@momjian.us          162                 :        3352698 : AppendJumble(JumbleState *jstate, const unsigned char *item, Size size)
                                163                 :                : {
                                164                 :        3352698 :     unsigned char *jumble = jstate->jumble;
                                165                 :        3352698 :     Size        jumble_len = jstate->jumble_len;
                                166                 :                : 
                                167                 :                :     /*
                                168                 :                :      * Whenever the jumble buffer is full, we hash the current contents and
                                169                 :                :      * reset the buffer to contain just that hash value, thus relying on the
                                170                 :                :      * hash to summarize everything so far.
                                171                 :                :      */
                                172         [ +  + ]:        6706283 :     while (size > 0)
                                173                 :                :     {
                                174                 :                :         Size        part_size;
                                175                 :                : 
                                176         [ +  + ]:        3353585 :         if (jumble_len >= JUMBLE_SIZE)
                                177                 :                :         {
                                178                 :                :             uint64      start_hash;
                                179                 :                : 
                                180                 :           1093 :             start_hash = DatumGetUInt64(hash_any_extended(jumble,
                                181                 :                :                                                           JUMBLE_SIZE, 0));
                                182                 :           1093 :             memcpy(jumble, &start_hash, sizeof(start_hash));
                                183                 :           1093 :             jumble_len = sizeof(start_hash);
                                184                 :                :         }
                                185                 :        3353585 :         part_size = Min(size, JUMBLE_SIZE - jumble_len);
                                186                 :        3353585 :         memcpy(jumble + jumble_len, item, part_size);
                                187                 :        3353585 :         jumble_len += part_size;
                                188                 :        3353585 :         item += part_size;
                                189                 :        3353585 :         size -= part_size;
                                190                 :                :     }
                                191                 :        3352698 :     jstate->jumble_len = jumble_len;
                                192                 :        3352698 : }
                                193                 :                : 
                                194                 :                : /*
                                195                 :                :  * Record location of constant within query string of query tree
                                196                 :                :  * that is currently being walked.
                                197                 :                :  */
                                198                 :                : static void
  439 michael@paquier.xyz       199                 :          99113 : RecordConstLocation(JumbleState *jstate, int location)
                                200                 :                : {
                                201                 :                :     /* -1 indicates unknown or undefined location */
                                202         [ +  + ]:          99113 :     if (location >= 0)
                                203                 :                :     {
                                204                 :                :         /* enlarge array if needed */
                                205         [ +  + ]:          93257 :         if (jstate->clocations_count >= jstate->clocations_buf_size)
                                206                 :                :         {
                                207                 :             57 :             jstate->clocations_buf_size *= 2;
                                208                 :             57 :             jstate->clocations = (LocationLen *)
                                209                 :             57 :                 repalloc(jstate->clocations,
                                210                 :             57 :                          jstate->clocations_buf_size *
                                211                 :                :                          sizeof(LocationLen));
                                212                 :                :         }
                                213                 :          93257 :         jstate->clocations[jstate->clocations_count].location = location;
                                214                 :                :         /* initialize lengths to -1 to simplify third-party module usage */
                                215                 :          93257 :         jstate->clocations[jstate->clocations_count].length = -1;
                                216                 :          93257 :         jstate->clocations_count++;
                                217                 :                :     }
 1103 bruce@momjian.us          218                 :          99113 : }
                                219                 :                : 
                                220                 :                : #define JUMBLE_NODE(item) \
                                221                 :                :     _jumbleNode(jstate, (Node *) expr->item)
                                222                 :                : #define JUMBLE_LOCATION(location) \
                                223                 :                :     RecordConstLocation(jstate, expr->location)
                                224                 :                : #define JUMBLE_FIELD(item) \
                                225                 :                :     AppendJumble(jstate, (const unsigned char *) &(expr->item), sizeof(expr->item))
                                226                 :                : #define JUMBLE_FIELD_SINGLE(item) \
                                227                 :                :     AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
                                228                 :                : #define JUMBLE_STRING(str) \
                                229                 :                : do { \
                                230                 :                :     if (expr->str) \
                                231                 :                :         AppendJumble(jstate, (const unsigned char *) (expr->str), strlen(expr->str) + 1); \
                                232                 :                : } while(0)
                                233                 :                : 
                                234                 :                : #include "queryjumblefuncs.funcs.c"
                                235                 :                : 
                                236                 :                : static void
  439 michael@paquier.xyz       237                 :        3124393 : _jumbleNode(JumbleState *jstate, Node *node)
                                238                 :                : {
                                239                 :        3124393 :     Node       *expr = node;
                                240                 :                : 
                                241         [ +  + ]:        3124393 :     if (expr == NULL)
 1103 bruce@momjian.us          242                 :        1873727 :         return;
                                243                 :                : 
                                244                 :                :     /* Guard against stack overflow due to overly complex expressions */
                                245                 :        1250666 :     check_stack_depth();
                                246                 :                : 
                                247                 :                :     /*
                                248                 :                :      * We always emit the node's NodeTag, then any additional fields that are
                                249                 :                :      * considered significant, and then we recurse to any child nodes.
                                250                 :                :      */
  439 michael@paquier.xyz       251                 :        1250666 :     JUMBLE_FIELD(type);
                                252                 :                : 
                                253   [ +  +  +  +  :        1250666 :     switch (nodeTag(expr))
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     -  -  -  +  +  
                                     +  +  -  +  +  
                                     -  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  -  
                                     +  +  +  -  +  
                                     +  -  +  +  +  
                                     +  +  +  +  -  
                                     -  +  +  +  +  
                                     +  +  +  +  +  
                                     +  -  -  -  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  -  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  -  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  -  +  
                                     +  +  -  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                     +  -  -  +  +  
                                        +  +  -  +  
                                                 - ]
                                254                 :                :     {
                                255                 :                : #include "queryjumblefuncs.switch.c"
                                256                 :                : 
                                257                 :         307090 :         case T_List:
                                258                 :                :         case T_IntList:
                                259                 :                :         case T_OidList:
                                260                 :                :         case T_XidList:
                                261                 :         307090 :             _jumbleList(jstate, expr);
 1103 bruce@momjian.us          262                 :         307090 :             break;
                                263                 :                : 
  439 michael@paquier.xyz       264                 :UBC           0 :         default:
                                265                 :                :             /* Only a warning, since we can stumble along anyway */
                                266         [ #  # ]:              0 :             elog(WARNING, "unrecognized node type: %d",
                                267                 :                :                  (int) nodeTag(expr));
 1103 bruce@momjian.us          268                 :              0 :             break;
                                269                 :                :     }
                                270                 :                : 
                                271                 :                :     /* Special cases to handle outside the automated code */
  439 michael@paquier.xyz       272         [ +  + ]:CBC     1250666 :     switch (nodeTag(expr))
                                273                 :                :     {
 1103 bruce@momjian.us          274                 :           5229 :         case T_Param:
                                275                 :                :             {
                                276                 :           5229 :                 Param      *p = (Param *) node;
                                277                 :                : 
                                278                 :                :                 /*
                                279                 :                :                  * Update the highest Param id seen, in order to start
                                280                 :                :                  * normalization correctly.
                                281                 :                :                  */
                                282         [ +  + ]:           5229 :                 if (p->paramkind == PARAM_EXTERN &&
                                283         [ +  + ]:           4856 :                     p->paramid > jstate->highest_extern_param_id)
                                284                 :           4269 :                     jstate->highest_extern_param_id = p->paramid;
                                285                 :                :             }
                                286                 :           5229 :             break;
  439 michael@paquier.xyz       287                 :        1245437 :         default:
 1103 bruce@momjian.us          288                 :        1245437 :             break;
                                289                 :                :     }
                                290                 :                : }
                                291                 :                : 
                                292                 :                : static void
  439 michael@paquier.xyz       293                 :         307090 : _jumbleList(JumbleState *jstate, Node *node)
                                294                 :                : {
                                295                 :         307090 :     List       *expr = (List *) node;
                                296                 :                :     ListCell   *l;
                                297                 :                : 
                                298   [ +  +  -  -  :         307090 :     switch (expr->type)
                                                 - ]
                                299                 :                :     {
                                300                 :         306704 :         case T_List:
                                301   [ +  -  +  +  :         844046 :             foreach(l, expr)
                                              +  + ]
                                302                 :         537342 :                 _jumbleNode(jstate, lfirst(l));
 1103 bruce@momjian.us          303                 :         306704 :             break;
  439 michael@paquier.xyz       304                 :            386 :         case T_IntList:
                                305   [ +  -  +  +  :            865 :             foreach(l, expr)
                                              +  + ]
                                306                 :            479 :                 JUMBLE_FIELD_SINGLE(lfirst_int(l));
 1103 bruce@momjian.us          307                 :            386 :             break;
  439 michael@paquier.xyz       308                 :UBC           0 :         case T_OidList:
                                309   [ #  #  #  #  :              0 :             foreach(l, expr)
                                              #  # ]
                                310                 :              0 :                 JUMBLE_FIELD_SINGLE(lfirst_oid(l));
 1103 bruce@momjian.us          311                 :              0 :             break;
  439 michael@paquier.xyz       312                 :              0 :         case T_XidList:
                                313   [ #  #  #  #  :              0 :             foreach(l, expr)
                                              #  # ]
                                314                 :              0 :                 JUMBLE_FIELD_SINGLE(lfirst_xid(l));
 1103 bruce@momjian.us          315                 :              0 :             break;
  439 michael@paquier.xyz       316                 :              0 :         default:
                                317         [ #  # ]:              0 :             elog(ERROR, "unrecognized list node type: %d",
                                318                 :                :                  (int) expr->type);
                                319                 :                :             return;
                                320                 :                :     }
                                321                 :                : }
                                322                 :                : 
                                323                 :                : static void
  432 michael@paquier.xyz       324                 :CBC        8229 : _jumbleA_Const(JumbleState *jstate, Node *node)
                                325                 :                : {
                                326                 :           8229 :     A_Const    *expr = (A_Const *) node;
                                327                 :                : 
                                328                 :           8229 :     JUMBLE_FIELD(isnull);
                                329         [ +  + ]:           8229 :     if (!expr->isnull)
                                330                 :                :     {
                                331                 :           8158 :         JUMBLE_FIELD(val.node.type);
                                332   [ +  +  +  +  :           8158 :         switch (nodeTag(&expr->val))
                                              +  - ]
                                333                 :                :         {
                                334                 :           3841 :             case T_Integer:
                                335                 :           3841 :                 JUMBLE_FIELD(val.ival.ival);
                                336                 :           3841 :                 break;
                                337                 :             42 :             case T_Float:
                                338         [ +  - ]:             42 :                 JUMBLE_STRING(val.fval.fval);
                                339                 :             42 :                 break;
                                340                 :            112 :             case T_Boolean:
                                341                 :            112 :                 JUMBLE_FIELD(val.boolval.boolval);
                                342                 :            112 :                 break;
                                343                 :           4161 :             case T_String:
                                344         [ +  - ]:           4161 :                 JUMBLE_STRING(val.sval.sval);
                                345                 :           4161 :                 break;
                                346                 :              2 :             case T_BitString:
                                347         [ +  - ]:              2 :                 JUMBLE_STRING(val.bsval.bsval);
                                348                 :              2 :                 break;
  432 michael@paquier.xyz       349                 :UBC           0 :             default:
                                350         [ #  # ]:              0 :                 elog(ERROR, "unrecognized node type: %d",
                                351                 :                :                      (int) nodeTag(&expr->val));
                                352                 :                :                 break;
                                353                 :                :         }
                                354                 :                :     }
  432 michael@paquier.xyz       355                 :CBC        8229 : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622