LCOV - differential code coverage report
Current view: top level - contrib/pg_plan_advice - pgpa_scanner.l (source / functions) Coverage Total Hit UNC GNC
Current: 0e5ff9b9b45a657aea12440478dc002e9b01f138 vs 0123ce131fca454009439dfa3b2266d1d40737d7 Lines: 86.5 % 89 77 12 77
Current Date: 2026-03-14 14:10:32 -0400 Functions: 71.4 % 7 5 2 5
Baseline: lcov-20260315-024220-baseline Branches: 75.0 % 36 27 9 27
Baseline Date: 2026-03-14 15:27:56 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 86.5 % 89 77 12 77
Function coverage date bins:
(1,7] days: 71.4 % 7 5 2 5
Branch coverage date bins:
(1,7] days: 75.0 % 36 27 9 27

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : %top{
                                  2                 :                : /*
                                  3                 :                :  * Scanner for plan advice
                                  4                 :                :  *
                                  5                 :                :  * Copyright (c) 2000-2026, PostgreSQL Global Development Group
                                  6                 :                :  *
                                  7                 :                :  * contrib/pg_plan_advice/pgpa_scanner.l
                                  8                 :                :  */
                                  9                 :                : #include "postgres.h"
                                 10                 :                : 
                                 11                 :                : #include "common/string.h"
                                 12                 :                : #include "nodes/miscnodes.h"
                                 13                 :                : #include "parser/scansup.h"
                                 14                 :                : 
                                 15                 :                : #include "pgpa_ast.h"
                                 16                 :                : #include "pgpa_parser.h"
                                 17                 :                : 
                                 18                 :                : /*
                                 19                 :                :  * Extra data that we pass around when during scanning.
                                 20                 :                :  *
                                 21                 :                :  * 'litbuf' is used to implement the <xd> exclusive state, which handles
                                 22                 :                :  * double-quoted identifiers.
                                 23                 :                :  */
                                 24                 :                : typedef struct pgpa_yy_extra_type
                                 25                 :                : {
                                 26                 :                :     StringInfoData  litbuf;
                                 27                 :                : } pgpa_yy_extra_type;
                                 28                 :                : 
                                 29                 :                : }
                                 30                 :                : 
                                 31                 :                : %{
                                 32                 :                : /* LCOV_EXCL_START */
                                 33                 :                : 
                                 34                 :                : #define YY_DECL \
                                 35                 :                :     extern int pgpa_yylex(union YYSTYPE *yylval_param, List **result, \
                                 36                 :                :                           char **parse_error_msg_p, yyscan_t yyscanner)
                                 37                 :                : 
                                 38                 :                : /* No reason to constrain amount of data slurped */
                                 39                 :                : #define YY_READ_BUF_SIZE 16777216
                                 40                 :                : 
                                 41                 :                : /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
                                 42                 :                : #undef fprintf
                                 43                 :                : #define fprintf(file, fmt, msg)  fprintf_to_ereport(fmt, msg)
                                 44                 :                : 
                                 45                 :                : static void
    3 rhaas@postgresql.org       46                 :UNC           0 : fprintf_to_ereport(const char *fmt, const char *msg)
                                 47                 :                : {
                                 48         [ #  # ]:              0 :     ereport(ERROR, (errmsg_internal("%s", msg)));
                                 49                 :                : }
                                 50                 :                : %}
                                 51                 :                : 
                                 52                 :                : %option reentrant
                                 53                 :                : %option bison-bridge
                                 54                 :                : %option 8bit
                                 55                 :                : %option never-interactive
                                 56                 :                : %option nodefault
                                 57                 :                : %option noinput
                                 58                 :                : %option nounput
                                 59                 :                : %option noyywrap
                                 60                 :                : %option noyyalloc
                                 61                 :                : %option noyyrealloc
                                 62                 :                : %option noyyfree
                                 63                 :                : %option warn
                                 64                 :                : %option prefix="pgpa_yy"
                                 65                 :                : %option extra-type="pgpa_yy_extra_type *"
                                 66                 :                : 
                                 67                 :                : /*
                                 68                 :                :  * What follows is a severely stripped-down version of the core scanner. We
                                 69                 :                :  * only care about recognizing identifiers with or without identifier quoting
                                 70                 :                :  * (i.e. double-quoting), decimal integers, and a small handful of other
                                 71                 :                :  * things. Keep these rules in sync with src/backend/parser/scan.l. As in that
                                 72                 :                :  * file, we use an exclusive state called 'xc' for C-style comments, and an
                                 73                 :                :  * exclusive state called 'xd' for double-quoted identifiers.
                                 74                 :                :  */
                                 75                 :                : %x xc
                                 76                 :                : %x xd
                                 77                 :                : 
                                 78                 :                : ident_start     [A-Za-z\200-\377_]
                                 79                 :                : ident_cont      [A-Za-z\200-\377_0-9\$]
                                 80                 :                : 
                                 81                 :                : identifier      {ident_start}{ident_cont}*
                                 82                 :                : 
                                 83                 :                : decdigit        [0-9]
                                 84                 :                : decinteger      {decdigit}(_?{decdigit})*
                                 85                 :                : 
                                 86                 :                : space           [ \t\n\r\f\v]
                                 87                 :                : whitespace      {space}+
                                 88                 :                : 
                                 89                 :                : dquote          \"
                                 90                 :                : xdstart         {dquote}
                                 91                 :                : xdstop          {dquote}
                                 92                 :                : xddouble        {dquote}{dquote}
                                 93                 :                : xdinside        [^"]+
                                 94                 :                : 
                                 95                 :                : xcstart         \/\*
                                 96                 :                : xcstop          \*+\/
                                 97                 :                : xcinside        [^*/]+
                                 98                 :                : 
                                 99                 :                : %%
                                100                 :                : 
                                101                 :                : {whitespace}    { /* ignore */ }
    3 rhaas@postgresql.org      102                 :GNC         183 : 
                                103                 :            675 : {identifier}    {
                                104                 :                :                     char   *str;
                                105                 :                :                     bool    fail;
                                106                 :                :                     pgpa_advice_tag_type    tag;
                                107                 :                : 
                                108                 :                :                     /*
                                109                 :                :                      * Unlike the core scanner, we don't truncate identifiers
                                110                 :                :                      * here. There is no obvious reason to do so.
                                111                 :                :                      */
                                112                 :            675 :                     str = downcase_identifier(yytext, yyleng, false, false);
                                113                 :            675 :                     yylval->str = str;
                                114                 :                : 
                                115                 :                :                     /*
                                116                 :                :                      * If it's not a tag, just return TOK_IDENT; else, return
                                117                 :                :                      * a token type based on how further parsing should
                                118                 :                :                      * proceed.
                                119                 :                :                      */
                                120                 :            675 :                     tag = pgpa_parse_advice_tag(str, &fail);
                                121         [ +  + ]:            675 :                     if (fail)
                                122                 :            418 :                         return TOK_IDENT;
                                123         [ +  + ]:            257 :                     else if (tag == PGPA_TAG_JOIN_ORDER)
                                124                 :             40 :                         return TOK_TAG_JOIN_ORDER;
                                125   [ +  +  +  + ]:            217 :                     else if (tag == PGPA_TAG_INDEX_SCAN ||
                                126                 :                :                              tag == PGPA_TAG_INDEX_ONLY_SCAN)
                                127                 :             38 :                         return TOK_TAG_INDEX;
                                128   [ +  +  +  + ]:            179 :                     else if (tag == PGPA_TAG_SEQ_SCAN ||
                                129         [ +  + ]:            121 :                              tag == PGPA_TAG_TID_SCAN ||
                                130         [ +  + ]:            115 :                              tag == PGPA_TAG_BITMAP_HEAP_SCAN ||
                                131                 :                :                              tag == PGPA_TAG_NO_GATHER)
                                132                 :             76 :                         return TOK_TAG_SIMPLE;
                                133                 :                :                     else
                                134                 :            103 :                         return TOK_TAG_GENERIC;
                                135                 :                :                 }
                                136                 :                : 
                                137                 :              9 : {decinteger}    {
                                138                 :                :                     char   *endptr;
                                139                 :                : 
                                140                 :              9 :                     errno = 0;
                                141                 :              9 :                     yylval->integer = strtoint(yytext, &endptr, 10);
                                142   [ +  -  -  + ]:              9 :                     if (*endptr != '\0' || errno == ERANGE)
    3 rhaas@postgresql.org      143                 :UNC           0 :                         pgpa_yyerror(result, parse_error_msg_p, yyscanner,
                                144                 :                :                                      "integer out of range");
    3 rhaas@postgresql.org      145                 :GNC           9 :                     return TOK_INTEGER;
                                146                 :                :                 }
                                147                 :                : 
                                148                 :             17 : {xcstart}       {
                                149                 :             17 :                     BEGIN(xc);
                                150                 :                :                 }
                                151                 :             17 : 
                                152                 :             20 : {xdstart}       {
                                153                 :             20 :                     BEGIN(xd);
                                154                 :             20 :                     resetStringInfo(&yyextra->litbuf);
                                155                 :                :                 }
                                156                 :             20 : 
                                157                 :            634 : .               { return yytext[0]; }
                                158                 :                : 
                                159                 :             15 : <xc>{xcstop}  {
                                160                 :             15 :                     BEGIN(INITIAL);
                                161                 :                :                 }
                                162                 :             15 : 
                                163                 :             10 : <xc>{xcinside}    {
                                164                 :                :                     /* discard multiple characters without slash or asterisk */
                                165                 :                :                 }
                                166                 :             10 : 
                                167                 :              4 : <xc>.         {
                                168                 :                :                     /*
                                169                 :                :                      * Discard any single character. flex prefers longer
                                170                 :                :                      * matches, so this rule will never be picked when we could
                                171                 :                :                      * have matched xcstop.
                                172                 :                :                      *
                                173                 :                :                      * NB: At present, we don't bother to support nested
                                174                 :                :                      * C-style comments here, but this logic could be extended
                                175                 :                :                      * if that restriction poses a problem.
                                176                 :                :                      */
                                177                 :                :                 }
                                178                 :              4 : 
                                179                 :              2 : <xc><<EOF>>       {
                                180                 :              2 :                     BEGIN(INITIAL);
                                181                 :              2 :                     pgpa_yyerror(result, parse_error_msg_p, yyscanner,
                                182                 :                :                                  "unterminated comment");
                                183                 :                :                 }
                                184                 :              2 : 
                                185                 :             19 : <xd>{xdstop}  {
                                186                 :             19 :                     BEGIN(INITIAL);
                                187         [ +  + ]:             19 :                     if (yyextra->litbuf.len == 0)
                                188                 :              1 :                         pgpa_yyerror(result, parse_error_msg_p, yyscanner,
                                189                 :                :                                      "zero-length delimited identifier");
                                190                 :             19 :                     yylval->str = pstrdup(yyextra->litbuf.data);
                                191                 :             19 :                     return TOK_IDENT;
                                192                 :                :                 }
                                193                 :                : 
    3 rhaas@postgresql.org      194                 :UNC           0 : <xd>{xddouble}    {
                                195                 :              0 :                     appendStringInfoChar(&yyextra->litbuf, '"');
                                196                 :                :                 }
                                197                 :              0 : 
    3 rhaas@postgresql.org      198                 :GNC          18 : <xd>{xdinside}    {
                                199                 :             18 :                     appendBinaryStringInfo(&yyextra->litbuf, yytext, yyleng);
                                200                 :                :                 }
                                201                 :             18 : 
                                202                 :              1 : <xd><<EOF>>       {
                                203                 :              1 :                     BEGIN(INITIAL);
                                204                 :              1 :                     pgpa_yyerror(result, parse_error_msg_p, yyscanner,
                                205                 :                :                                  "unterminated quoted identifier");
                                206                 :                :                 }
                                207                 :              1 : 
    3 rhaas@postgresql.org      208                 :UNC           0 : %%
                                209                 :                : 
                                210                 :                : /* LCOV_EXCL_STOP */
                                211                 :                : 
                                212                 :                : /*
                                213                 :                :  * Handler for errors while scanning or parsing advice.
                                214                 :                :  *
                                215                 :                :  * bison passes the error message to us via 'message', and the context is
                                216                 :                :  * available via the 'yytext' macro. We assemble those values into a final
                                217                 :                :  * error text and then arrange to pass it back to the caller of pgpa_yyparse()
                                218                 :                :  * by storing it into *parse_error_msg_p.
                                219                 :                :  */
                                220                 :                : void
    3 rhaas@postgresql.org      221                 :GNC          18 : pgpa_yyerror(List **result, char **parse_error_msg_p, yyscan_t yyscanner,
                                222                 :                :              const char *message)
                                223                 :                : {
                                224                 :             18 :     struct yyguts_t *yyg = (struct yyguts_t *) yyscanner;   /* needed for yytext
                                225                 :                :                                                              * macro */
                                226                 :                : 
                                227                 :                : 
                                228                 :                :     /* report only the first error in a parse operation */
                                229         [ +  + ]:             18 :     if (*parse_error_msg_p)
                                230                 :              1 :         return;
                                231                 :                : 
                                232         [ +  + ]:             17 :     if (yytext[0])
                                233                 :             11 :         *parse_error_msg_p = psprintf("%s at or near \"%s\"", message, yytext);
                                234                 :                :     else
                                235                 :              6 :         *parse_error_msg_p = psprintf("%s at end of input", message);
                                236                 :                : }
                                237                 :                : 
                                238                 :                : /*
                                239                 :                :  * Initialize the advice scanner.
                                240                 :                :  *
                                241                 :                :  * This should be called before parsing begins.
                                242                 :                :  */
                                243                 :                : void
                                244                 :            243 : pgpa_scanner_init(const char *str, yyscan_t *yyscannerp)
                                245                 :                : {
                                246                 :                :     yyscan_t    yyscanner;
                                247                 :            243 :     pgpa_yy_extra_type  *yyext = palloc0_object(pgpa_yy_extra_type);
                                248                 :                : 
                                249         [ -  + ]:            243 :     if (yylex_init(yyscannerp) != 0)
    3 rhaas@postgresql.org      250         [ #  # ]:UNC           0 :         elog(ERROR, "yylex_init() failed: %m");
                                251                 :                : 
    3 rhaas@postgresql.org      252                 :GNC         243 :     yyscanner = *yyscannerp;
                                253                 :                : 
                                254                 :            243 :     initStringInfo(&yyext->litbuf);
                                255                 :            243 :     pgpa_yyset_extra(yyext, yyscanner);
                                256                 :                : 
                                257                 :            243 :     yy_scan_string(str, yyscanner);
                                258                 :            243 : }
                                259                 :                : 
                                260                 :                : 
                                261                 :                : /*
                                262                 :                :  * Shut down the advice scanner.
                                263                 :                :  *
                                264                 :                :  * This should be called after parsing is complete.
                                265                 :                :  */
                                266                 :                : void
                                267                 :            243 : pgpa_scanner_finish(yyscan_t yyscanner)
                                268                 :                : {
                                269                 :            243 :     yylex_destroy(yyscanner);
                                270                 :            243 : }
                                271                 :                : 
                                272                 :                : /*
                                273                 :                :  * Interface functions to make flex use palloc() instead of malloc().
                                274                 :                :  * It'd be better to make these static, but flex insists otherwise.
                                275                 :                :  */
                                276                 :                : 
                                277                 :                : void *
                                278                 :            972 : yyalloc(yy_size_t size, yyscan_t yyscanner)
                                279                 :                : {
                                280                 :            972 :     return palloc(size);
                                281                 :                : }
                                282                 :                : 
                                283                 :                : void *
    3 rhaas@postgresql.org      284                 :UNC           0 : yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
                                285                 :                : {
                                286         [ #  # ]:              0 :     if (ptr)
                                287                 :              0 :         return repalloc(ptr, size);
                                288                 :                :     else
                                289                 :              0 :         return palloc(size);
                                290                 :                : }
                                291                 :                : 
                                292                 :                : void
    3 rhaas@postgresql.org      293                 :GNC        1215 : yyfree(void *ptr, yyscan_t yyscanner)
                                294                 :                : {
                                295         [ +  + ]:           1215 :     if (ptr)
                                296                 :            972 :         pfree(ptr);
                                297                 :           1215 : }
        

Generated by: LCOV version 2.4-beta