LCOV - code coverage report
Current view: top level - src/backend/replication - repl_scanner.l (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 82.5 % 120 99
Test Date: 2026-03-03 13:15:30 Functions: 66.7 % 12 8
Legend: Lines:     hit not hit

            Line data    Source code
       1              : %top{
       2              : /*-------------------------------------------------------------------------
       3              :  *
       4              :  * repl_scanner.l
       5              :  *    a lexical scanner for the replication commands
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  *
      11              :  * IDENTIFICATION
      12              :  *    src/backend/replication/repl_scanner.l
      13              :  *
      14              :  *-------------------------------------------------------------------------
      15              :  */
      16              : #include "postgres.h"
      17              : 
      18              : #include "nodes/parsenodes.h"
      19              : #include "utils/builtins.h"
      20              : #include "parser/scansup.h"
      21              : 
      22              : /*
      23              :  * NB: include repl_gram.h only AFTER including walsender_private.h, because
      24              :  * walsender_private includes headers that define XLogRecPtr.
      25              :  */
      26              : #include "replication/walsender_private.h"
      27              : #include "repl_gram.h"
      28              : }
      29              : 
      30              : %{
      31              : /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
      32              : #undef fprintf
      33              : #define fprintf(file, fmt, msg)  fprintf_to_ereport(fmt, msg)
      34              : 
      35              : static void
      36            0 : fprintf_to_ereport(const char *fmt, const char *msg)
      37              : {
      38            0 :     ereport(ERROR, (errmsg_internal("%s", msg)));
      39              : }
      40              : 
      41              : struct replication_yy_extra_type
      42              : {
      43              :     /* Pushed-back token (we only handle one) */
      44              :     int         repl_pushed_back_token;
      45              : 
      46              :     /* Work area for collecting literals */
      47              :     StringInfoData litbuf;
      48              : };
      49              : 
      50              : static void startlit(yyscan_t yyscanner);
      51              : static char *litbufdup(yyscan_t yyscanner);
      52              : static void addlit(char *ytext, int yleng, yyscan_t yyscanner);
      53              : static void addlitchar(unsigned char ychar, yyscan_t yyscanner);
      54              : 
      55              : /* LCOV_EXCL_START */
      56              : 
      57              : %}
      58              : 
      59              : %option reentrant
      60              : %option bison-bridge
      61              : %option 8bit
      62              : %option never-interactive
      63              : %option nodefault
      64              : %option noinput
      65              : %option nounput
      66              : %option noyywrap
      67              : %option noyyalloc
      68              : %option noyyrealloc
      69              : %option noyyfree
      70              : %option warn
      71              : %option prefix="replication_yy"
      72              : %option extra-type="struct replication_yy_extra_type *"
      73              : 
      74              : /*
      75              :  * Exclusive states:
      76              :  *  <xd> delimited identifiers (double-quoted identifiers)
      77              :  *  <xq> standard single-quoted strings
      78              :  */
      79              : %x xd
      80              : %x xq
      81              : 
      82              : space           [ \t\n\r\f\v]
      83              : 
      84              : quote           '
      85              : quotestop       {quote}
      86              : 
      87              : /* Extended quote
      88              :  * xqdouble implements embedded quote, ''''
      89              :  */
      90              : xqstart         {quote}
      91              : xqdouble        {quote}{quote}
      92              : xqinside        [^']+
      93              : 
      94              : /* Double quote
      95              :  * Allows embedded spaces and other special characters into identifiers.
      96              :  */
      97              : dquote          \"
      98              : xdstart         {dquote}
      99              : xdstop          {dquote}
     100              : xddouble        {dquote}{dquote}
     101              : xdinside        [^"]+
     102              : 
     103              : digit           [0-9]
     104              : hexdigit        [0-9A-Fa-f]
     105              : 
     106              : ident_start     [A-Za-z\200-\377_]
     107              : ident_cont      [A-Za-z\200-\377_0-9\$]
     108              : 
     109              : identifier      {ident_start}{ident_cont}*
     110              : 
     111              : %%
     112              : 
     113              : %{
     114              :     /* This code is inserted at the start of replication_yylex() */
     115              : 
     116              :     /* If we have a pushed-back token, return that. */
     117              :     if (yyextra->repl_pushed_back_token)
     118        28636 :     {
     119              :         int         result = yyextra->repl_pushed_back_token;
     120         3109 : 
     121              :         yyextra->repl_pushed_back_token = 0;
     122         3109 :         return result;
     123         3109 :     }
     124              : %}
     125              : 
     126              : BASE_BACKUP         { return K_BASE_BACKUP; }
     127          190 : IDENTIFY_SYSTEM     { return K_IDENTIFY_SYSTEM; }
     128          775 : READ_REPLICATION_SLOT   { return K_READ_REPLICATION_SLOT; }
     129          775 : SHOW        { return K_SHOW; }
     130            6 : TIMELINE            { return K_TIMELINE; }
     131          602 : START_REPLICATION   { return K_START_REPLICATION; }
     132          284 : CREATE_REPLICATION_SLOT     { return K_CREATE_REPLICATION_SLOT; }
     133          730 : DROP_REPLICATION_SLOT       { return K_DROP_REPLICATION_SLOT; }
     134          492 : ALTER_REPLICATION_SLOT      { return K_ALTER_REPLICATION_SLOT; }
     135          281 : TIMELINE_HISTORY    { return K_TIMELINE_HISTORY; }
     136            7 : PHYSICAL            { return K_PHYSICAL; }
     137           13 : RESERVE_WAL         { return K_RESERVE_WAL; }
     138          145 : LOGICAL             { return K_LOGICAL; }
     139          144 : SLOT                { return K_SLOT; }
     140          792 : TEMPORARY           { return K_TEMPORARY; }
     141          636 : TWO_PHASE           { return K_TWO_PHASE; }
     142          140 : EXPORT_SNAPSHOT     { return K_EXPORT_SNAPSHOT; }
     143            3 : NOEXPORT_SNAPSHOT   { return K_NOEXPORT_SNAPSHOT; }
     144            0 : USE_SNAPSHOT        { return K_USE_SNAPSHOT; }
     145            0 : WAIT                { return K_WAIT; }
     146            0 : UPLOAD_MANIFEST     { return K_UPLOAD_MANIFEST; }
     147          455 : 
     148           13 : {space}+        { /* do nothing */ }
     149        12585 : 
     150        12585 : {digit}+        {
     151          478 :                     yylval->uintval = strtoul(yytext, NULL, 10);
     152          478 :                     return UCONST;
     153          478 :                 }
     154              : 
     155              : {hexdigit}+\/{hexdigit}+        {
     156          730 :                     uint32  hi,
     157              :                             lo;
     158              :                     if (sscanf(yytext, "%X/%08X", &hi, &lo) != 2)
     159          730 :                         replication_yyerror(NULL, yyscanner, "invalid streaming start location");
     160            0 :                     yylval->recptr = ((uint64) hi) << 32 | lo;
     161          730 :                     return RECPTR;
     162          730 :                 }
     163              : 
     164              : {xqstart}       {
     165         2879 :                     BEGIN(xq);
     166         2879 :                     startlit(yyscanner);
     167         2879 :                 }
     168              : 
     169         2879 : <xq>{quotestop}   {
     170         2879 :                     yyless(1);
     171         2879 :                     BEGIN(INITIAL);
     172         2879 :                     yylval->str = litbufdup(yyscanner);
     173         2879 :                     return SCONST;
     174         2879 :                 }
     175              : 
     176              : <xq>{xqdouble}    {
     177            0 :                     addlitchar('\'', yyscanner);
     178            0 :                 }
     179              : 
     180            0 : <xq>{xqinside}  {
     181         2878 :                     addlit(yytext, yyleng, yyscanner);
     182         2878 :                 }
     183              : 
     184         2878 : {xdstart}       {
     185         1191 :                     BEGIN(xd);
     186         1191 :                     startlit(yyscanner);
     187         1191 :                 }
     188              : 
     189         1191 : <xd>{xdstop}  {
     190         1191 :                     int         len;
     191              : 
     192              :                     yyless(1);
     193         1191 :                     BEGIN(INITIAL);
     194         1191 :                     yylval->str = litbufdup(yyscanner);
     195         1191 :                     len = strlen(yylval->str);
     196         1191 :                     truncate_identifier(yylval->str, len, true);
     197         1191 :                     return IDENT;
     198         1191 :                 }
     199              : 
     200              : <xd>{xdinside}  {
     201         1191 :                     addlit(yytext, yyleng, yyscanner);
     202         1191 :                 }
     203              : 
     204         1191 : {identifier}    {
     205         6811 :                     int         len = strlen(yytext);
     206         6811 : 
     207              :                     yylval->str = downcase_truncate_identifier(yytext, len, true);
     208         6811 :                     return IDENT;
     209         6811 :                 }
     210              : 
     211              : .               {
     212         4621 :                     /* Any char not recognized above is returned as itself */
     213              :                     return yytext[0];
     214         4621 :                 }
     215              : 
     216              : <xq,xd><<EOF>>    { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
     217            0 : 
     218              : 
     219         3109 : <<EOF>>         {
     220              :                     yyterminate();
     221         3109 :                 }
     222              : 
     223              : %%
     224            0 : 
     225              : /* LCOV_EXCL_STOP */
     226              : 
     227              : /* see scan.l */
     228              : #undef yyextra
     229              : #define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
     230              : 
     231              : static void
     232              : startlit(yyscan_t yyscanner)
     233         4070 : {
     234              :     initStringInfo(&yyextra->litbuf);
     235         4070 : }
     236         4070 : 
     237              : static char *
     238              : litbufdup(yyscan_t yyscanner)
     239         4070 : {
     240              :     return yyextra->litbuf.data;
     241         4070 : }
     242              : 
     243              : static void
     244              : addlit(char *ytext, int yleng, yyscan_t yyscanner)
     245         4069 : {
     246              :     appendBinaryStringInfo(&yyextra->litbuf, ytext, yleng);
     247         4069 : }
     248         4069 : 
     249              : static void
     250              : addlitchar(unsigned char ychar, yyscan_t yyscanner)
     251            0 : {
     252              :     appendStringInfoChar(&yyextra->litbuf, ychar);
     253            0 : }
     254            0 : 
     255              : /*
     256              :   * (The first argument is enforced by Bison to match the first argument of
     257              :   * yyparse(), but it is not used here.)
     258              :   */
     259              : void
     260              : replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message)
     261            0 : {
     262              :     ereport(ERROR,
     263            0 :             (errcode(ERRCODE_SYNTAX_ERROR),
     264              :              errmsg_internal("%s", message)));
     265              : }
     266              : 
     267              : void
     268              : replication_scanner_init(const char *str, yyscan_t *yyscannerp)
     269         5582 : {
     270              :     yyscan_t    yyscanner;
     271              :     struct replication_yy_extra_type *yyext = palloc0_object(struct replication_yy_extra_type);
     272         5582 : 
     273              :     if (yylex_init(yyscannerp) != 0)
     274         5582 :         elog(ERROR, "yylex_init() failed: %m");
     275            0 : 
     276              :     yyscanner = *yyscannerp;
     277         5582 : 
     278              :     yyset_extra(yyext, yyscanner);
     279         5582 : 
     280              :     yy_scan_string(str, yyscanner);
     281         5582 : }
     282         5582 : 
     283              : void
     284              : replication_scanner_finish(yyscan_t yyscanner)
     285         5582 : {
     286              :     pfree(yyextra);
     287         5582 :     yylex_destroy(yyscanner);
     288         5582 : }
     289         5582 : 
     290              : /*
     291              :  * Check to see if the first token of a command is a WalSender keyword.
     292              :  *
     293              :  * To keep repl_scanner.l minimal, we don't ask it to know every construct
     294              :  * that the core lexer knows.  Therefore, we daren't lex more than the
     295              :  * first token of a general SQL command.  That will usually look like an
     296              :  * IDENT token here, although some other cases are possible.
     297              :  */
     298              : bool
     299              : replication_scanner_is_replication_command(yyscan_t yyscanner)
     300         5582 : {
     301              :     YYSTYPE     dummy;
     302              :     int         first_token = replication_yylex(&dummy, yyscanner);
     303         5582 : 
     304              :     switch (first_token)
     305         5582 :     {
     306              :         case K_IDENTIFY_SYSTEM:
     307         3109 :         case K_BASE_BACKUP:
     308              :         case K_START_REPLICATION:
     309              :         case K_CREATE_REPLICATION_SLOT:
     310              :         case K_DROP_REPLICATION_SLOT:
     311              :         case K_ALTER_REPLICATION_SLOT:
     312              :         case K_READ_REPLICATION_SLOT:
     313              :         case K_TIMELINE_HISTORY:
     314              :         case K_UPLOAD_MANIFEST:
     315              :         case K_SHOW:
     316              :             /* Yes; push back the first token so we can parse later. */
     317              :             yyextra->repl_pushed_back_token = first_token;
     318         3109 :             return true;
     319         3109 :         default:
     320         2473 :             /* Nope; we don't bother to push back the token. */
     321              :             return false;
     322         2473 :     }
     323              : }
     324              : 
     325              : /*
     326              :  * Interface functions to make flex use palloc() instead of malloc().
     327              :  * It'd be better to make these static, but flex insists otherwise.
     328              :  */
     329              : 
     330              : void *
     331              : yyalloc(yy_size_t size, yyscan_t yyscanner)
     332        22328 : {
     333              :     return palloc(size);
     334        22328 : }
     335              : 
     336              : void *
     337              : yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
     338            0 : {
     339              :     if (ptr)
     340            0 :         return repalloc(ptr, size);
     341            0 :     else
     342              :         return palloc(size);
     343            0 : }
     344              : 
     345              : void
     346              : yyfree(void *ptr, yyscan_t yyscanner)
     347        27910 : {
     348              :     if (ptr)
     349        27910 :         pfree(ptr);
     350        22328 : }
     351        27910 : /* END: function "replication_yyfree" */
        

Generated by: LCOV version 2.0-1