LCOV - code coverage report
Current view: top level - src/fe_utils - psqlscan.l (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 164 221 74.2 %
Date: 2020-06-01 00:06:26 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : %top{
       2             : /*-------------------------------------------------------------------------
       3             :  *
       4             :  * psqlscan.l
       5             :  *    lexical scanner for SQL commands
       6             :  *
       7             :  * This lexer used to be part of psql, and that heritage is reflected in
       8             :  * the file name as well as function and typedef names, though it can now
       9             :  * be used by other frontend programs as well.  It's also possible to extend
      10             :  * this lexer with a compatible add-on lexer to handle program-specific
      11             :  * backslash commands.
      12             :  *
      13             :  * This code is mainly concerned with determining where the end of a SQL
      14             :  * statement is: we are looking for semicolons that are not within quotes,
      15             :  * comments, or parentheses.  The most reliable way to handle this is to
      16             :  * borrow the backend's flex lexer rules, lock, stock, and barrel.  The rules
      17             :  * below are (except for a few) the same as the backend's, but their actions
      18             :  * are just ECHO whereas the backend's actions generally do other things.
      19             :  *
      20             :  * XXX The rules in this file must be kept in sync with the backend lexer!!!
      21             :  *
      22             :  * XXX Avoid creating backtracking cases --- see the backend lexer for info.
      23             :  *
      24             :  * See psqlscan_int.h for additional commentary.
      25             :  *
      26             :  *
      27             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
      28             :  * Portions Copyright (c) 1994, Regents of the University of California
      29             :  *
      30             :  * IDENTIFICATION
      31             :  *    src/fe_utils/psqlscan.l
      32             :  *
      33             :  *-------------------------------------------------------------------------
      34             :  */
      35             : #include "postgres_fe.h"
      36             : 
      37             : #include "common/logging.h"
      38             : #include "fe_utils/psqlscan.h"
      39             : 
      40             : #include "libpq-fe.h"
      41             : }
      42             : 
      43             : %{
      44             : 
      45             : /* LCOV_EXCL_START */
      46             : 
      47             : #include "fe_utils/psqlscan_int.h"
      48             : 
      49             : /*
      50             :  * We must have a typedef YYSTYPE for yylex's first argument, but this lexer
      51             :  * doesn't presently make use of that argument, so just declare it as int.
      52             :  */
      53             : typedef int YYSTYPE;
      54             : 
      55             : /*
      56             :  * Set the type of yyextra; we use it as a pointer back to the containing
      57             :  * PsqlScanState.
      58             :  */
      59             : #define YY_EXTRA_TYPE PsqlScanState
      60             : 
      61             : 
      62             : /* Return values from yylex() */
      63             : #define LEXRES_EOL          0   /* end of input */
      64             : #define LEXRES_SEMI         1   /* command-terminating semicolon found */
      65             : #define LEXRES_BACKSLASH    2   /* backslash command start */
      66             : 
      67             : 
      68             : #define ECHO psqlscan_emit(cur_state, yytext, yyleng)
      69             : 
      70             : /*
      71             :  * Work around a bug in flex 2.5.35: it emits a couple of functions that
      72             :  * it forgets to emit declarations for.  Since we use -Wmissing-prototypes,
      73             :  * this would cause warnings.  Providing our own declarations should be
      74             :  * harmless even when the bug gets fixed.
      75             :  */
      76             : extern int  psql_yyget_column(yyscan_t yyscanner);
      77             : extern void psql_yyset_column(int column_no, yyscan_t yyscanner);
      78             : 
      79             : %}
      80             : 
      81             : %option reentrant
      82             : %option bison-bridge
      83             : %option 8bit
      84             : %option never-interactive
      85             : %option nodefault
      86             : %option noinput
      87             : %option nounput
      88             : %option noyywrap
      89             : %option warn
      90             : %option prefix="psql_yy"
      91             : 
      92             : /*
      93             :  * All of the following definitions and rules should exactly match
      94             :  * src/backend/parser/scan.l so far as the flex patterns are concerned.
      95             :  * The rule bodies are just ECHO as opposed to what the backend does,
      96             :  * however.  (But be sure to duplicate code that affects the lexing process,
      97             :  * such as BEGIN() and yyless().)  Also, psqlscan uses a single <<EOF>> rule
      98             :  * whereas scan.l has a separate one for each exclusive state.
      99             :  */
     100             : 
     101             : /*
     102             :  * OK, here is a short description of lex/flex rules behavior.
     103             :  * The longest pattern which matches an input string is always chosen.
     104             :  * For equal-length patterns, the first occurring in the rules list is chosen.
     105             :  * INITIAL is the starting state, to which all non-conditional rules apply.
     106             :  * Exclusive states change parsing rules while the state is active.  When in
     107             :  * an exclusive state, only those rules defined for that state apply.
     108             :  *
     109             :  * We use exclusive states for quoted strings, extended comments,
     110             :  * and to eliminate parsing troubles for numeric strings.
     111             :  * Exclusive states:
     112             :  *  <xb> bit string literal
     113             :  *  <xc> extended C-style comments
     114             :  *  <xd> delimited identifiers (double-quoted identifiers)
     115             :  *  <xh> hexadecimal numeric string
     116             :  *  <xq> standard quoted strings
     117             :  *  <xqs> quote stop (detect continued strings)
     118             :  *  <xe> extended quoted strings (support backslash escape sequences)
     119             :  *  <xdolq> $foo$ quoted strings
     120             :  *  <xui> quoted identifier with Unicode escapes
     121             :  *  <xus> quoted string with Unicode escapes
     122             :  *
     123             :  * Note: we intentionally don't mimic the backend's <xeu> state; we have
     124             :  * no need to distinguish it from <xe> state, and no good way to get out
     125             :  * of it in error cases.  The backend just throws yyerror() in those
     126             :  * cases, but that's not an option here.
     127             :  */
     128             : 
     129             : %x xb
     130             : %x xc
     131             : %x xd
     132             : %x xh
     133             : %x xq
     134             : %x xqs
     135             : %x xe
     136             : %x xdolq
     137             : %x xui
     138             : %x xus
     139             : 
     140             : /*
     141             :  * In order to make the world safe for Windows and Mac clients as well as
     142             :  * Unix ones, we accept either \n or \r as a newline.  A DOS-style \r\n
     143             :  * sequence will be seen as two successive newlines, but that doesn't cause
     144             :  * any problems.  Comments that start with -- and extend to the next
     145             :  * newline are treated as equivalent to a single whitespace character.
     146             :  *
     147             :  * NOTE a fine point: if there is no newline following --, we will absorb
     148             :  * everything to the end of the input as a comment.  This is correct.  Older
     149             :  * versions of Postgres failed to recognize -- as a comment if the input
     150             :  * did not end with a newline.
     151             :  *
     152             :  * XXX perhaps \f (formfeed) should be treated as a newline as well?
     153             :  *
     154             :  * XXX if you change the set of whitespace characters, fix scanner_isspace()
     155             :  * to agree.
     156             :  */
     157             : 
     158             : space           [ \t\n\r\f]
     159             : horiz_space     [ \t\f]
     160             : newline         [\n\r]
     161             : non_newline     [^\n\r]
     162             : 
     163             : comment         ("--"{non_newline}*)
     164             : 
     165             : whitespace      ({space}+|{comment})
     166             : 
     167             : /*
     168             :  * SQL requires at least one newline in the whitespace separating
     169             :  * string literals that are to be concatenated.  Silly, but who are we
     170             :  * to argue?  Note that {whitespace_with_newline} should not have * after
     171             :  * it, whereas {whitespace} should generally have a * after it...
     172             :  */
     173             : 
     174             : special_whitespace      ({space}+|{comment}{newline})
     175             : horiz_whitespace        ({horiz_space}|{comment})
     176             : whitespace_with_newline ({horiz_whitespace}*{newline}{special_whitespace}*)
     177             : 
     178             : quote           '
     179             : /* If we see {quote} then {quotecontinue}, the quoted string continues */
     180             : quotecontinue   {whitespace_with_newline}{quote}
     181             : 
     182             : /*
     183             :  * {quotecontinuefail} is needed to avoid lexer backup when we fail to match
     184             :  * {quotecontinue}.  It might seem that this could just be {whitespace}*,
     185             :  * but if there's a dash after {whitespace_with_newline}, it must be consumed
     186             :  * to see if there's another dash --- which would start a {comment} and thus
     187             :  * allow continuation of the {quotecontinue} token.
     188             :  */
     189             : quotecontinuefail   {whitespace}*"-"?
     190             : 
     191             : /* Bit string
     192             :  * It is tempting to scan the string for only those characters
     193             :  * which are allowed. However, this leads to silently swallowed
     194             :  * characters if illegal characters are included in the string.
     195             :  * For example, if xbinside is [01] then B'ABCD' is interpreted
     196             :  * as a zero-length string, and the ABCD' is lost!
     197             :  * Better to pass the string forward and let the input routines
     198             :  * validate the contents.
     199             :  */
     200             : xbstart         [bB]{quote}
     201             : xbinside        [^']*
     202             : 
     203             : /* Hexadecimal number */
     204             : xhstart         [xX]{quote}
     205             : xhinside        [^']*
     206             : 
     207             : /* National character */
     208             : xnstart         [nN]{quote}
     209             : 
     210             : /* Quoted string that allows backslash escapes */
     211             : xestart         [eE]{quote}
     212             : xeinside        [^\\']+
     213             : xeescape        [\\][^0-7]
     214             : xeoctesc        [\\][0-7]{1,3}
     215             : xehexesc        [\\]x[0-9A-Fa-f]{1,2}
     216             : xeunicode       [\\](u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})
     217             : xeunicodefail   [\\](u[0-9A-Fa-f]{0,3}|U[0-9A-Fa-f]{0,7})
     218             : 
     219             : /* Extended quote
     220             :  * xqdouble implements embedded quote, ''''
     221             :  */
     222             : xqstart         {quote}
     223             : xqdouble        {quote}{quote}
     224             : xqinside        [^']+
     225             : 
     226             : /* $foo$ style quotes ("dollar quoting")
     227             :  * The quoted string starts with $foo$ where "foo" is an optional string
     228             :  * in the form of an identifier, except that it may not contain "$",
     229             :  * and extends to the first occurrence of an identical string.
     230             :  * There is *no* processing of the quoted text.
     231             :  *
     232             :  * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim}
     233             :  * fails to match its trailing "$".
     234             :  */
     235             : dolq_start      [A-Za-z\200-\377_]
     236             : dolq_cont       [A-Za-z\200-\377_0-9]
     237             : dolqdelim       \$({dolq_start}{dolq_cont}*)?\$
     238             : dolqfailed      \${dolq_start}{dolq_cont}*
     239             : dolqinside      [^$]+
     240             : 
     241             : /* Double quote
     242             :  * Allows embedded spaces and other special characters into identifiers.
     243             :  */
     244             : dquote          \"
     245             : xdstart         {dquote}
     246             : xdstop          {dquote}
     247             : xddouble        {dquote}{dquote}
     248             : xdinside        [^"]+
     249             : 
     250             : /* Quoted identifier with Unicode escapes */
     251             : xuistart        [uU]&{dquote}
     252             : 
     253             : /* Quoted string with Unicode escapes */
     254             : xusstart        [uU]&{quote}
     255             : 
     256             : /* error rule to avoid backup */
     257             : xufailed        [uU]&
     258             : 
     259             : 
     260             : /* C-style comments
     261             :  *
     262             :  * The "extended comment" syntax closely resembles allowable operator syntax.
     263             :  * The tricky part here is to get lex to recognize a string starting with
     264             :  * slash-star as a comment, when interpreting it as an operator would produce
     265             :  * a longer match --- remember lex will prefer a longer match!  Also, if we
     266             :  * have something like plus-slash-star, lex will think this is a 3-character
     267             :  * operator whereas we want to see it as a + operator and a comment start.
     268             :  * The solution is two-fold:
     269             :  * 1. append {op_chars}* to xcstart so that it matches as much text as
     270             :  *    {operator} would. Then the tie-breaker (first matching rule of same
     271             :  *    length) ensures xcstart wins.  We put back the extra stuff with yyless()
     272             :  *    in case it contains a star-slash that should terminate the comment.
     273             :  * 2. In the operator rule, check for slash-star within the operator, and
     274             :  *    if found throw it back with yyless().  This handles the plus-slash-star
     275             :  *    problem.
     276             :  * Dash-dash comments have similar interactions with the operator rule.
     277             :  */
     278             : xcstart         \/\*{op_chars}*
     279             : xcstop          \*+\/
     280             : xcinside        [^*/]+
     281             : 
     282             : digit           [0-9]
     283             : ident_start     [A-Za-z\200-\377_]
     284             : ident_cont      [A-Za-z\200-\377_0-9\$]
     285             : 
     286             : identifier      {ident_start}{ident_cont}*
     287             : 
     288             : /* Assorted special-case operators and operator-like tokens */
     289             : typecast        "::"
     290             : dot_dot         \.\.
     291             : colon_equals    ":="
     292             : 
     293             : /*
     294             :  * These operator-like tokens (unlike the above ones) also match the {operator}
     295             :  * rule, which means that they might be overridden by a longer match if they
     296             :  * are followed by a comment start or a + or - character. Accordingly, if you
     297             :  * add to this list, you must also add corresponding code to the {operator}
     298             :  * block to return the correct token in such cases. (This is not needed in
     299             :  * psqlscan.l since the token value is ignored there.)
     300             :  */
     301             : equals_greater  "=>"
     302             : less_equals     "<="
     303             : greater_equals  ">="
     304             : less_greater    "<>"
     305             : not_equals      "!="
     306             : 
     307             : /*
     308             :  * "self" is the set of chars that should be returned as single-character
     309             :  * tokens.  "op_chars" is the set of chars that can make up "Op" tokens,
     310             :  * which can be one or more characters long (but if a single-char token
     311             :  * appears in the "self" set, it is not to be returned as an Op).  Note
     312             :  * that the sets overlap, but each has some chars that are not in the other.
     313             :  *
     314             :  * If you change either set, adjust the character lists appearing in the
     315             :  * rule for "operator"!
     316             :  */
     317             : self            [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
     318             : op_chars        [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
     319             : operator        {op_chars}+
     320             : 
     321             : /* we no longer allow unary minus in numbers.
     322             :  * instead we pass it separately to parser. there it gets
     323             :  * coerced via doNegate() -- Leon aug 20 1999
     324             :  *
     325             :  * {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
     326             :  *
     327             :  * {realfail1} and {realfail2} are added to prevent the need for scanner
     328             :  * backup when the {real} rule fails to match completely.
     329             :  */
     330             : 
     331             : integer         {digit}+
     332             : decimal         (({digit}*\.{digit}+)|({digit}+\.{digit}*))
     333             : decimalfail     {digit}+\.\.
     334             : real            ({integer}|{decimal})[Ee][-+]?{digit}+
     335             : realfail1       ({integer}|{decimal})[Ee]
     336             : realfail2       ({integer}|{decimal})[Ee][-+]
     337             : 
     338             : param           \${integer}
     339             : 
     340             : /* psql-specific: characters allowed in variable names */
     341             : variable_char   [A-Za-z\200-\377_0-9]
     342             : 
     343             : other           .
     344             : 
     345             : /*
     346             :  * Dollar quoted strings are totally opaque, and no escaping is done on them.
     347             :  * Other quoted strings must allow some special characters such as single-quote
     348             :  *  and newline.
     349             :  * Embedded single-quotes are implemented both in the SQL standard
     350             :  *  style of two adjacent single quotes "''" and in the Postgres/Java style
     351             :  *  of escaped-quote "\'".
     352             :  * Other embedded escaped characters are matched explicitly and the leading
     353             :  *  backslash is dropped from the string.
     354             :  * Note that xcstart must appear before operator, as explained above!
     355             :  *  Also whitespace (comment) must appear before operator.
     356             :  */
     357             : 
     358             : %%
     359             : 
     360             : %{
     361             :         /* Declare some local variables inside yylex(), for convenience */
     362             :         PsqlScanState cur_state = yyextra;
     363             :         PQExpBuffer output_buf = cur_state->output_buf;
     364             : 
     365             :         /*
     366             :          * Force flex into the state indicated by start_state.  This has a
     367             :          * couple of purposes: it lets some of the functions below set a new
     368             :          * starting state without ugly direct access to flex variables, and it
     369             :          * allows us to transition from one flex lexer to another so that we
     370             :          * can lex different parts of the source string using separate lexers.
     371             :          */
     372             :         BEGIN(cur_state->start_state);
     373             : %}
     374             : 
     375             : {whitespace}    {
     376             :                     /*
     377             :                      * Note that the whitespace rule includes both true
     378             :                      * whitespace and single-line ("--" style) comments.
     379             :                      * We suppress whitespace at the start of the query
     380             :                      * buffer.  We also suppress all single-line comments,
     381             :                      * which is pretty dubious but is the historical
     382             :                      * behavior.
     383             :                      */
     384             :                     if (!(output_buf->len == 0 || yytext[0] == '-'))
     385             :                         ECHO;
     386             :                 }
     387             : 
     388             : {xcstart}       {
     389             :                     cur_state->xcdepth = 0;
     390             :                     BEGIN(xc);
     391             :                     /* Put back any characters past slash-star; see above */
     392             :                     yyless(2);
     393             :                     ECHO;
     394             :                 }
     395             : 
     396             : <xc>{
     397             : {xcstart}       {
     398             :                     cur_state->xcdepth++;
     399             :                     /* Put back any characters past slash-star; see above */
     400             :                     yyless(2);
     401             :                     ECHO;
     402             :                 }
     403             : 
     404             : {xcstop}        {
     405             :                     if (cur_state->xcdepth <= 0)
     406             :                         BEGIN(INITIAL);
     407             :                     else
     408             :                         cur_state->xcdepth--;
     409             :                     ECHO;
     410             :                 }
     411             : 
     412             : {xcinside}      {
     413             :                     ECHO;
     414             :                 }
     415             : 
     416             : {op_chars}      {
     417             :                     ECHO;
     418             :                 }
     419             : 
     420             : \*+             {
     421             :                     ECHO;
     422             :                 }
     423             : } /* <xc> */
     424             : 
     425             : {xbstart}       {
     426             :                     BEGIN(xb);
     427             :                     ECHO;
     428             :                 }
     429             : <xh>{xhinside}    |
     430             : <xb>{xbinside}    {
     431             :                     ECHO;
     432             :                 }
     433             : 
     434             : {xhstart}       {
     435             :                     /* Hexadecimal bit type.
     436             :                      * At some point we should simply pass the string
     437             :                      * forward to the parser and label it there.
     438             :                      * In the meantime, place a leading "x" on the string
     439             :                      * to mark it for the input routine as a hex string.
     440             :                      */
     441             :                     BEGIN(xh);
     442             :                     ECHO;
     443             :                 }
     444             : 
     445             : {xnstart}       {
     446             :                     yyless(1);  /* eat only 'n' this time */
     447             :                     ECHO;
     448             :                 }
     449             : 
     450             : {xqstart}       {
     451             :                     if (cur_state->std_strings)
     452             :                         BEGIN(xq);
     453             :                     else
     454             :                         BEGIN(xe);
     455             :                     ECHO;
     456             :                 }
     457             : {xestart}       {
     458             :                     BEGIN(xe);
     459             :                     ECHO;
     460             :                 }
     461             : {xusstart}      {
     462             :                     BEGIN(xus);
     463             :                     ECHO;
     464             :                 }
     465             : 
     466             : <xb,xh,xq,xe,xus>{quote} {
     467             :                     /*
     468             :                      * When we are scanning a quoted string and see an end
     469             :                      * quote, we must look ahead for a possible continuation.
     470             :                      * If we don't see one, we know the end quote was in fact
     471             :                      * the end of the string.  To reduce the lexer table size,
     472             :                      * we use a single "xqs" state to do the lookahead for all
     473             :                      * types of strings.
     474             :                      */
     475             :                     cur_state->state_before_str_stop = YYSTATE;
     476             :                     BEGIN(xqs);
     477             :                     ECHO;
     478             :                 }
     479             : <xqs>{quotecontinue} {
     480             :                     /*
     481             :                      * Found a quote continuation, so return to the in-quote
     482             :                      * state and continue scanning the literal.  Nothing is
     483             :                      * added to the literal's contents.
     484             :                      */
     485             :                     BEGIN(cur_state->state_before_str_stop);
     486             :                     ECHO;
     487             :                 }
     488             : <xqs>{quotecontinuefail} |
     489             : <xqs>{other}  {
     490             :                     /*
     491             :                      * Failed to see a quote continuation.  Throw back
     492             :                      * everything after the end quote, and handle the string
     493             :                      * according to the state we were in previously.
     494             :                      */
     495             :                     yyless(0);
     496             :                     BEGIN(INITIAL);
     497             :                     /* There's nothing to echo ... */
     498             :                 }
     499             : 
     500             : <xq,xe,xus>{xqdouble} {
     501             :                     ECHO;
     502             :                 }
     503             : <xq,xus>{xqinside}  {
     504             :                     ECHO;
     505             :                 }
     506             : <xe>{xeinside}  {
     507             :                     ECHO;
     508             :                 }
     509             : <xe>{xeunicode} {
     510             :                     ECHO;
     511             :                 }
     512             : <xe>{xeunicodefail}   {
     513             :                     ECHO;
     514             :                 }
     515             : <xe>{xeescape}  {
     516             :                     ECHO;
     517             :                 }
     518             : <xe>{xeoctesc}  {
     519             :                     ECHO;
     520             :                 }
     521             : <xe>{xehexesc}  {
     522             :                     ECHO;
     523             :                 }
     524             : <xe>.         {
     525             :                     /* This is only needed for \ just before EOF */
     526             :                     ECHO;
     527             :                 }
     528             : 
     529             : {dolqdelim}     {
     530             :                     cur_state->dolqstart = pg_strdup(yytext);
     531             :                     BEGIN(xdolq);
     532             :                     ECHO;
     533             :                 }
     534             : {dolqfailed}    {
     535             :                     /* throw back all but the initial "$" */
     536             :                     yyless(1);
     537             :                     ECHO;
     538             :                 }
     539             : <xdolq>{dolqdelim} {
     540             :                     if (strcmp(yytext, cur_state->dolqstart) == 0)
     541             :                     {
     542             :                         free(cur_state->dolqstart);
     543             :                         cur_state->dolqstart = NULL;
     544             :                         BEGIN(INITIAL);
     545             :                     }
     546             :                     else
     547             :                     {
     548             :                         /*
     549             :                          * When we fail to match $...$ to dolqstart, transfer
     550             :                          * the $... part to the output, but put back the final
     551             :                          * $ for rescanning.  Consider $delim$...$junk$delim$
     552             :                          */
     553             :                         yyless(yyleng - 1);
     554             :                     }
     555             :                     ECHO;
     556             :                 }
     557             : <xdolq>{dolqinside} {
     558             :                     ECHO;
     559             :                 }
     560             : <xdolq>{dolqfailed} {
     561             :                     ECHO;
     562             :                 }
     563             : <xdolq>.      {
     564             :                     /* This is only needed for $ inside the quoted text */
     565             :                     ECHO;
     566             :                 }
     567             : 
     568             : {xdstart}       {
     569             :                     BEGIN(xd);
     570             :                     ECHO;
     571             :                 }
     572             : {xuistart}      {
     573             :                     BEGIN(xui);
     574             :                     ECHO;
     575             :                 }
     576             : <xd>{xdstop}  {
     577             :                     BEGIN(INITIAL);
     578             :                     ECHO;
     579             :                 }
     580             : <xui>{dquote} {
     581             :                     BEGIN(INITIAL);
     582             :                     ECHO;
     583             :                 }
     584             : <xd,xui>{xddouble}    {
     585             :                     ECHO;
     586             :                 }
     587             : <xd,xui>{xdinside}    {
     588             :                     ECHO;
     589             :                 }
     590             : 
     591             : {xufailed}  {
     592             :                     /* throw back all but the initial u/U */
     593             :                     yyless(1);
     594             :                     ECHO;
     595             :                 }
     596             : 
     597             : {typecast}      {
     598             :                     ECHO;
     599             :                 }
     600             : 
     601             : {dot_dot}       {
     602             :                     ECHO;
     603             :                 }
     604             : 
     605             : {colon_equals}  {
     606             :                     ECHO;
     607             :                 }
     608             : 
     609             : {equals_greater} {
     610             :                     ECHO;
     611             :                 }
     612             : 
     613             : {less_equals}   {
     614             :                     ECHO;
     615             :                 }
     616             : 
     617             : {greater_equals} {
     618             :                     ECHO;
     619             :                 }
     620             : 
     621             : {less_greater}  {
     622             :                     ECHO;
     623             :                 }
     624             : 
     625             : {not_equals}    {
     626             :                     ECHO;
     627             :                 }
     628             : 
     629             :     /*
     630             :      * These rules are specific to psql --- they implement parenthesis
     631             :      * counting and detection of command-ending semicolon.  These must
     632             :      * appear before the {self} rule so that they take precedence over it.
     633             :      */
     634             : 
     635             : "("               {
     636             :                     cur_state->paren_depth++;
     637             :                     ECHO;
     638             :                 }
     639             : 
     640             : ")"               {
     641             :                     if (cur_state->paren_depth > 0)
     642             :                         cur_state->paren_depth--;
     643             :                     ECHO;
     644             :                 }
     645             : 
     646             : ";"               {
     647             :                     ECHO;
     648             :                     if (cur_state->paren_depth == 0)
     649             :                     {
     650             :                         /* Terminate lexing temporarily */
     651             :                         cur_state->start_state = YY_START;
     652             :                         return LEXRES_SEMI;
     653             :                     }
     654             :                 }
     655             : 
     656             :     /*
     657             :      * psql-specific rules to handle backslash commands and variable
     658             :      * substitution.  We want these before {self}, also.
     659             :      */
     660             : 
     661             : "\\"[;:]      {
     662             :                     /* Force a semi-colon or colon into the query buffer */
     663             :                     psqlscan_emit(cur_state, yytext + 1, 1);
     664             :                 }
     665             : 
     666             : "\\"          {
     667             :                     /* Terminate lexing temporarily */
     668             :                     cur_state->start_state = YY_START;
     669             :                     return LEXRES_BACKSLASH;
     670             :                 }
     671             : 
     672             : :{variable_char}+   {
     673             :                     /* Possible psql variable substitution */
     674             :                     char       *varname;
     675             :                     char       *value;
     676             : 
     677             :                     varname = psqlscan_extract_substring(cur_state,
     678             :                                                          yytext + 1,
     679             :                                                          yyleng - 1);
     680             :                     if (cur_state->callbacks->get_variable)
     681             :                         value = cur_state->callbacks->get_variable(varname,
     682             :                                                                    PQUOTE_PLAIN,
     683             :                                                                    cur_state->cb_passthrough);
     684             :                     else
     685             :                         value = NULL;
     686             : 
     687             :                     if (value)
     688             :                     {
     689             :                         /* It is a variable, check for recursion */
     690             :                         if (psqlscan_var_is_current_source(cur_state, varname))
     691             :                         {
     692             :                             /* Recursive expansion --- don't go there */
     693             :                             pg_log_warning("skipping recursive expansion of variable \"%s\"",
     694             :                                                               varname);
     695             :                             /* Instead copy the string as is */
     696             :                             ECHO;
     697             :                         }
     698             :                         else
     699             :                         {
     700             :                             /* OK, perform substitution */
     701             :                             psqlscan_push_new_buffer(cur_state, value, varname);
     702             :                             /* yy_scan_string already made buffer active */
     703             :                         }
     704             :                         free(value);
     705             :                     }
     706             :                     else
     707             :                     {
     708             :                         /*
     709             :                          * if the variable doesn't exist we'll copy the string
     710             :                          * as is
     711             :                          */
     712             :                         ECHO;
     713             :                     }
     714             : 
     715             :                     free(varname);
     716             :                 }
     717             : 
     718             : :'{variable_char}+' {
     719             :                     psqlscan_escape_variable(cur_state, yytext, yyleng,
     720             :                                              PQUOTE_SQL_LITERAL);
     721             :                 }
     722             : 
     723             : :\"{variable_char}+\" {
     724             :                     psqlscan_escape_variable(cur_state, yytext, yyleng,
     725             :                                              PQUOTE_SQL_IDENT);
     726             :                 }
     727             : 
     728             : :\{\?{variable_char}+\} {
     729             :                     psqlscan_test_variable(cur_state, yytext, yyleng);
     730             :                 }
     731             : 
     732             :     /*
     733             :      * These rules just avoid the need for scanner backup if one of the
     734             :      * three rules above fails to match completely.
     735             :      */
     736             : 
     737             : :'{variable_char}*  {
     738             :                     /* Throw back everything but the colon */
     739             :                     yyless(1);
     740             :                     ECHO;
     741             :                 }
     742             : 
     743             : :\"{variable_char}*    {
     744             :                     /* Throw back everything but the colon */
     745             :                     yyless(1);
     746             :                     ECHO;
     747             :                 }
     748             : 
     749             : :\{\?{variable_char}*   {
     750             :                     /* Throw back everything but the colon */
     751             :                     yyless(1);
     752             :                     ECHO;
     753             :                 }
     754             : :\{ {
     755             :                     /* Throw back everything but the colon */
     756             :                     yyless(1);
     757             :                     ECHO;
     758             :                 }
     759             : 
     760             :     /*
     761             :      * Back to backend-compatible rules.
     762             :      */
     763             : 
     764             : {self}          {
     765             :                     ECHO;
     766             :                 }
     767             : 
     768             : {operator}      {
     769             :                     /*
     770             :                      * Check for embedded slash-star or dash-dash; those
     771             :                      * are comment starts, so operator must stop there.
     772             :                      * Note that slash-star or dash-dash at the first
     773             :                      * character will match a prior rule, not this one.
     774             :                      */
     775             :                     int         nchars = yyleng;
     776             :                     char       *slashstar = strstr(yytext, "/*");
     777             :                     char       *dashdash = strstr(yytext, "--");
     778             : 
     779             :                     if (slashstar && dashdash)
     780             :                     {
     781             :                         /* if both appear, take the first one */
     782             :                         if (slashstar > dashdash)
     783             :                             slashstar = dashdash;
     784             :                     }
     785             :                     else if (!slashstar)
     786             :                         slashstar = dashdash;
     787             :                     if (slashstar)
     788             :                         nchars = slashstar - yytext;
     789             : 
     790             :                     /*
     791             :                      * For SQL compatibility, '+' and '-' cannot be the
     792             :                      * last char of a multi-char operator unless the operator
     793             :                      * contains chars that are not in SQL operators.
     794             :                      * The idea is to lex '=-' as two operators, but not
     795             :                      * to forbid operator names like '?-' that could not be
     796             :                      * sequences of SQL operators.
     797             :                      */
     798             :                     if (nchars > 1 &&
     799             :                         (yytext[nchars - 1] == '+' ||
     800             :                          yytext[nchars - 1] == '-'))
     801             :                     {
     802             :                         int         ic;
     803             : 
     804             :                         for (ic = nchars - 2; ic >= 0; ic--)
     805             :                         {
     806             :                             char c = yytext[ic];
     807             :                             if (c == '~' || c == '!' || c == '@' ||
     808             :                                 c == '#' || c == '^' || c == '&' ||
     809             :                                 c == '|' || c == '`' || c == '?' ||
     810             :                                 c == '%')
     811             :                                 break;
     812             :                         }
     813             :                         if (ic < 0)
     814             :                         {
     815             :                             /*
     816             :                              * didn't find a qualifying character, so remove
     817             :                              * all trailing [+-]
     818             :                              */
     819             :                             do {
     820             :                                 nchars--;
     821             :                             } while (nchars > 1 &&
     822             :                                  (yytext[nchars - 1] == '+' ||
     823             :                                   yytext[nchars - 1] == '-'));
     824             :                         }
     825             :                     }
     826             : 
     827             :                     if (nchars < yyleng)
     828             :                     {
     829             :                         /* Strip the unwanted chars from the token */
     830             :                         yyless(nchars);
     831             :                     }
     832             :                     ECHO;
     833             :                 }
     834             : 
     835             : {param}         {
     836             :                     ECHO;
     837             :                 }
     838             : 
     839             : {integer}       {
     840             :                     ECHO;
     841             :                 }
     842             : {decimal}       {
     843             :                     ECHO;
     844             :                 }
     845             : {decimalfail}   {
     846             :                     /* throw back the .., and treat as integer */
     847             :                     yyless(yyleng - 2);
     848             :                     ECHO;
     849             :                 }
     850             : {real}          {
     851             :                     ECHO;
     852             :                 }
     853             : {realfail1}     {
     854             :                     /*
     855             :                      * throw back the [Ee], and figure out whether what
     856             :                      * remains is an {integer} or {decimal}.
     857             :                      * (in psql, we don't actually care...)
     858             :                      */
     859             :                     yyless(yyleng - 1);
     860             :                     ECHO;
     861             :                 }
     862             : {realfail2}     {
     863             :                     /* throw back the [Ee][+-], and proceed as above */
     864             :                     yyless(yyleng - 2);
     865             :                     ECHO;
     866             :                 }
     867             : 
     868             : 
     869             : {identifier}    {
     870             :                     ECHO;
     871             :                 }
     872             : 
     873             : {other}         {
     874             :                     ECHO;
     875             :                 }
     876             : 
     877             : <<EOF>>         {
     878             :                     if (cur_state->buffer_stack == NULL)
     879             :                     {
     880             :                         cur_state->start_state = YY_START;
     881             :                         return LEXRES_EOL;      /* end of input reached */
     882             :                     }
     883             : 
     884             :                     /*
     885             :                      * We were expanding a variable, so pop the inclusion
     886             :                      * stack and keep lexing
     887             :                      */
     888             :                     psqlscan_pop_buffer_stack(cur_state);
     889             :                     psqlscan_select_top_buffer(cur_state);
     890             :                 }
     891             : 
     892             : %%
     893             : 
     894             : /* LCOV_EXCL_STOP */
     895             : 
     896             : /*
     897             :  * Create a lexer working state struct.
     898             :  *
     899             :  * callbacks is a struct of function pointers that encapsulate some
     900             :  * behavior we need from the surrounding program.  This struct must
     901             :  * remain valid for the lifespan of the PsqlScanState.
     902             :  */
     903             : PsqlScanState
     904             : psql_scan_create(const PsqlScanCallbacks *callbacks)
     905        3984 : {
     906             :     PsqlScanState state;
     907             : 
     908             :     state = (PsqlScanStateData *) pg_malloc0(sizeof(PsqlScanStateData));
     909        3984 : 
     910             :     state->callbacks = callbacks;
     911        3984 : 
     912             :     yylex_init(&state->scanner);
     913        3984 : 
     914             :     yyset_extra(state, state->scanner);
     915        3984 : 
     916             :     psql_scan_reset(state);
     917        3984 : 
     918             :     return state;
     919        3984 : }
     920             : 
     921             : /*
     922             :  * Destroy a lexer working state struct, releasing all resources.
     923             :  */
     924             : void
     925             : psql_scan_destroy(PsqlScanState state)
     926        3900 : {
     927             :     psql_scan_finish(state);
     928        3900 : 
     929             :     psql_scan_reset(state);
     930        3900 : 
     931             :     yylex_destroy(state->scanner);
     932        3900 : 
     933             :     free(state);
     934        3900 : }
     935        3900 : 
     936             : /*
     937             :  * Set the callback passthrough pointer for the lexer.
     938             :  *
     939             :  * This could have been integrated into psql_scan_create, but keeping it
     940             :  * separate allows the application to change the pointer later, which might
     941             :  * be useful.
     942             :  */
     943             : void
     944             : psql_scan_set_passthrough(PsqlScanState state, void *passthrough)
     945        3502 : {
     946             :     state->cb_passthrough = passthrough;
     947        3502 : }
     948        3502 : 
     949             : /*
     950             :  * Set up to perform lexing of the given input line.
     951             :  *
     952             :  * The text at *line, extending for line_len bytes, will be scanned by
     953             :  * subsequent calls to the psql_scan routines.  psql_scan_finish should
     954             :  * be called when scanning is complete.  Note that the lexer retains
     955             :  * a pointer to the storage at *line --- this string must not be altered
     956             :  * or freed until after psql_scan_finish is called.
     957             :  *
     958             :  * encoding is the libpq identifier for the character encoding in use,
     959             :  * and std_strings says whether standard_conforming_strings is on.
     960             :  */
     961             : void
     962             : psql_scan_setup(PsqlScanState state,
     963      301242 :                 const char *line, int line_len,
     964             :                 int encoding, bool std_strings)
     965             : {
     966             :     /* Mustn't be scanning already */
     967             :     Assert(state->scanbufhandle == NULL);
     968             :     Assert(state->buffer_stack == NULL);
     969             : 
     970             :     /* Do we need to hack the character set encoding? */
     971             :     state->encoding = encoding;
     972      301242 :     state->safe_encoding = pg_valid_server_encoding_id(encoding);
     973      301242 : 
     974             :     /* Save standard-strings flag as well */
     975             :     state->std_strings = std_strings;
     976      301242 : 
     977             :     /* Set up flex input buffer with appropriate translation and padding */
     978             :     state->scanbufhandle = psqlscan_prepare_buffer(state, line, line_len,
     979      301242 :                                                    &state->scanbuf);
     980             :     state->scanline = line;
     981      301242 : 
     982             :     /* Set lookaside data in case we have to map unsafe encoding */
     983             :     state->curline = state->scanbuf;
     984      301242 :     state->refline = state->scanline;
     985      301242 : }
     986      301242 : 
     987             : /*
     988             :  * Do lexical analysis of SQL command text.
     989             :  *
     990             :  * The text previously passed to psql_scan_setup is scanned, and appended
     991             :  * (possibly with transformation) to query_buf.
     992             :  *
     993             :  * The return value indicates the condition that stopped scanning:
     994             :  *
     995             :  * PSCAN_SEMICOLON: found a command-ending semicolon.  (The semicolon is
     996             :  * transferred to query_buf.)  The command accumulated in query_buf should
     997             :  * be executed, then clear query_buf and call again to scan the remainder
     998             :  * of the line.
     999             :  *
    1000             :  * PSCAN_BACKSLASH: found a backslash that starts a special command.
    1001             :  * Any previous data on the line has been transferred to query_buf.
    1002             :  * The caller will typically next apply a separate flex lexer to scan
    1003             :  * the special command.
    1004             :  *
    1005             :  * PSCAN_INCOMPLETE: the end of the line was reached, but we have an
    1006             :  * incomplete SQL command.  *prompt is set to the appropriate prompt type.
    1007             :  *
    1008             :  * PSCAN_EOL: the end of the line was reached, and there is no lexical
    1009             :  * reason to consider the command incomplete.  The caller may or may not
    1010             :  * choose to send it.  *prompt is set to the appropriate prompt type if
    1011             :  * the caller chooses to collect more input.
    1012             :  *
    1013             :  * In the PSCAN_INCOMPLETE and PSCAN_EOL cases, psql_scan_finish() should
    1014             :  * be called next, then the cycle may be repeated with a fresh input line.
    1015             :  *
    1016             :  * In all cases, *prompt is set to an appropriate prompt type code for the
    1017             :  * next line-input operation.
    1018             :  */
    1019             : PsqlScanResult
    1020             : psql_scan(PsqlScanState state,
    1021      463780 :           PQExpBuffer query_buf,
    1022             :           promptStatus_t *prompt)
    1023             : {
    1024             :     PsqlScanResult result;
    1025             :     int         lexresult;
    1026             : 
    1027             :     /* Must be scanning already */
    1028             :     Assert(state->scanbufhandle != NULL);
    1029             : 
    1030             :     /* Set current output target */
    1031             :     state->output_buf = query_buf;
    1032      463780 : 
    1033             :     /* Set input source */
    1034             :     if (state->buffer_stack != NULL)
    1035      463780 :         yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
    1036          60 :     else
    1037             :         yy_switch_to_buffer(state->scanbufhandle, state->scanner);
    1038      463720 : 
    1039             :     /* And lex. */
    1040             :     lexresult = yylex(NULL, state->scanner);
    1041      463780 : 
    1042             :     /*
    1043             :      * Check termination state and return appropriate result info.
    1044             :      */
    1045             :     switch (lexresult)
    1046      463780 :     {
    1047             :         case LEXRES_EOL:        /* end of input */
    1048      301148 :             switch (state->start_state)
    1049      301148 :             {
    1050             :                 case INITIAL:
    1051      271874 :                 case xqs:       /* we treat this like INITIAL */
    1052             :                     if (state->paren_depth > 0)
    1053      271874 :                     {
    1054             :                         result = PSCAN_INCOMPLETE;
    1055       20052 :                         *prompt = PROMPT_PAREN;
    1056       20052 :                     }
    1057             :                     else if (query_buf->len > 0)
    1058      251822 :                     {
    1059             :                         result = PSCAN_EOL;
    1060       44384 :                         *prompt = PROMPT_CONTINUE;
    1061       44384 :                     }
    1062             :                     else
    1063             :                     {
    1064             :                         /* never bother to send an empty buffer */
    1065             :                         result = PSCAN_INCOMPLETE;
    1066      207438 :                         *prompt = PROMPT_READY;
    1067      207438 :                     }
    1068             :                     break;
    1069      271874 :                 case xb:
    1070           0 :                     result = PSCAN_INCOMPLETE;
    1071           0 :                     *prompt = PROMPT_SINGLEQUOTE;
    1072           0 :                     break;
    1073           0 :                 case xc:
    1074         418 :                     result = PSCAN_INCOMPLETE;
    1075         418 :                     *prompt = PROMPT_COMMENT;
    1076         418 :                     break;
    1077         418 :                 case xd:
    1078          12 :                     result = PSCAN_INCOMPLETE;
    1079          12 :                     *prompt = PROMPT_DOUBLEQUOTE;
    1080          12 :                     break;
    1081          12 :                 case xh:
    1082           0 :                     result = PSCAN_INCOMPLETE;
    1083           0 :                     *prompt = PROMPT_SINGLEQUOTE;
    1084           0 :                     break;
    1085           0 :                 case xe:
    1086         602 :                     result = PSCAN_INCOMPLETE;
    1087         602 :                     *prompt = PROMPT_SINGLEQUOTE;
    1088         602 :                     break;
    1089         602 :                 case xq:
    1090        6488 :                     result = PSCAN_INCOMPLETE;
    1091        6488 :                     *prompt = PROMPT_SINGLEQUOTE;
    1092        6488 :                     break;
    1093        6488 :                 case xdolq:
    1094       21754 :                     result = PSCAN_INCOMPLETE;
    1095       21754 :                     *prompt = PROMPT_DOLLARQUOTE;
    1096       21754 :                     break;
    1097       21754 :                 case xui:
    1098           0 :                     result = PSCAN_INCOMPLETE;
    1099           0 :                     *prompt = PROMPT_DOUBLEQUOTE;
    1100           0 :                     break;
    1101           0 :                 case xus:
    1102           0 :                     result = PSCAN_INCOMPLETE;
    1103           0 :                     *prompt = PROMPT_SINGLEQUOTE;
    1104           0 :                     break;
    1105           0 :                 default:
    1106           0 :                     /* can't get here */
    1107             :                     fprintf(stderr, "invalid YY_START\n");
    1108           0 :                     exit(1);
    1109           0 :             }
    1110             :             break;
    1111      301148 :         case LEXRES_SEMI:       /* semicolon */
    1112      156362 :             result = PSCAN_SEMICOLON;
    1113      156362 :             *prompt = PROMPT_READY;
    1114      156362 :             break;
    1115      156362 :         case LEXRES_BACKSLASH:  /* backslash */
    1116        6270 :             result = PSCAN_BACKSLASH;
    1117        6270 :             *prompt = PROMPT_READY;
    1118        6270 :             break;
    1119        6270 :         default:
    1120           0 :             /* can't get here */
    1121             :             fprintf(stderr, "invalid yylex result\n");
    1122           0 :             exit(1);
    1123           0 :     }
    1124             : 
    1125             :     return result;
    1126      463780 : }
    1127             : 
    1128             : /*
    1129             :  * Clean up after scanning a string.  This flushes any unread input and
    1130             :  * releases resources (but not the PsqlScanState itself).  Note however
    1131             :  * that this does not reset the lexer scan state; that can be done by
    1132             :  * psql_scan_reset(), which is an orthogonal operation.
    1133             :  *
    1134             :  * It is legal to call this when not scanning anything (makes it easier
    1135             :  * to deal with error recovery).
    1136             :  */
    1137             : void
    1138             : psql_scan_finish(PsqlScanState state)
    1139      305058 : {
    1140             :     /* Drop any incomplete variable expansions. */
    1141             :     while (state->buffer_stack != NULL)
    1142      305058 :         psqlscan_pop_buffer_stack(state);
    1143           0 : 
    1144             :     /* Done with the outer scan buffer, too */
    1145             :     if (state->scanbufhandle)
    1146      305058 :         yy_delete_buffer(state->scanbufhandle, state->scanner);
    1147      301158 :     state->scanbufhandle = NULL;
    1148      305058 :     if (state->scanbuf)
    1149      305058 :         free(state->scanbuf);
    1150      301158 :     state->scanbuf = NULL;
    1151      305058 : }
    1152      305058 : 
    1153             : /*
    1154             :  * Reset lexer scanning state to start conditions.  This is appropriate
    1155             :  * for executing \r psql commands (or any other time that we discard the
    1156             :  * prior contents of query_buf).  It is not, however, necessary to do this
    1157             :  * when we execute and clear the buffer after getting a PSCAN_SEMICOLON or
    1158             :  * PSCAN_EOL scan result, because the scan state must be INITIAL when those
    1159             :  * conditions are returned.
    1160             :  *
    1161             :  * Note that this is unrelated to flushing unread input; that task is
    1162             :  * done by psql_scan_finish().
    1163             :  */
    1164             : void
    1165             : psql_scan_reset(PsqlScanState state)
    1166        8274 : {
    1167             :     state->start_state = INITIAL;
    1168        8274 :     state->paren_depth = 0;
    1169        8274 :     state->xcdepth = 0;          /* not really necessary */
    1170        8274 :     if (state->dolqstart)
    1171        8274 :         free(state->dolqstart);
    1172           0 :     state->dolqstart = NULL;
    1173        8274 : }
    1174        8274 : 
    1175             : /*
    1176             :  * Reselect this lexer (psqlscan.l) after using another one.
    1177             :  *
    1178             :  * Currently and for foreseeable uses, it's sufficient to reset to INITIAL
    1179             :  * state, because we'd never switch to another lexer in a different state.
    1180             :  * However, we don't want to reset e.g. paren_depth, so this can't be
    1181             :  * the same as psql_scan_reset().
    1182             :  *
    1183             :  * Note: psql setjmp error recovery just calls psql_scan_reset(), so that
    1184             :  * must be a superset of this.
    1185             :  *
    1186             :  * Note: it seems likely that other lexers could just assign INITIAL for
    1187             :  * themselves, since that probably has the value zero in every flex-generated
    1188             :  * lexer.  But let's not assume that.
    1189             :  */
    1190             : void
    1191             : psql_scan_reselect_sql_lexer(PsqlScanState state)
    1192       27688 : {
    1193             :     state->start_state = INITIAL;
    1194       27688 : }
    1195       27688 : 
    1196             : /*
    1197             :  * Return true if lexer is currently in an "inside quotes" state.
    1198             :  *
    1199             :  * This is pretty grotty but is needed to preserve the old behavior
    1200             :  * that mainloop.c drops blank lines not inside quotes without even
    1201             :  * echoing them.
    1202             :  */
    1203             : bool
    1204             : psql_scan_in_quote(PsqlScanState state)
    1205       68658 : {
    1206             :     return state->start_state != INITIAL &&
    1207       69318 :             state->start_state != xqs;
    1208         660 : }
    1209             : 
    1210             : /*
    1211             :  * Push the given string onto the stack of stuff to scan.
    1212             :  *
    1213             :  * NOTE SIDE EFFECT: the new buffer is made the active flex input buffer.
    1214             :  */
    1215             : void
    1216             : psqlscan_push_new_buffer(PsqlScanState state, const char *newstr,
    1217         272 :                          const char *varname)
    1218             : {
    1219             :     StackElem  *stackelem;
    1220             : 
    1221             :     stackelem = (StackElem *) pg_malloc(sizeof(StackElem));
    1222         272 : 
    1223             :     /*
    1224             :      * In current usage, the passed varname points at the current flex input
    1225             :      * buffer; we must copy it before calling psqlscan_prepare_buffer()
    1226             :      * because that will change the buffer state.
    1227             :      */
    1228             :     stackelem->varname = varname ? pg_strdup(varname) : NULL;
    1229         272 : 
    1230             :     stackelem->buf = psqlscan_prepare_buffer(state, newstr, strlen(newstr),
    1231         272 :                                              &stackelem->bufstring);
    1232             :     state->curline = stackelem->bufstring;
    1233         272 :     if (state->safe_encoding)
    1234         272 :     {
    1235             :         stackelem->origstring = NULL;
    1236         272 :         state->refline = stackelem->bufstring;
    1237         272 :     }
    1238             :     else
    1239             :     {
    1240             :         stackelem->origstring = pg_strdup(newstr);
    1241           0 :         state->refline = stackelem->origstring;
    1242           0 :     }
    1243             :     stackelem->next = state->buffer_stack;
    1244         272 :     state->buffer_stack = stackelem;
    1245         272 : }
    1246         272 : 
    1247             : /*
    1248             :  * Pop the topmost buffer stack item (there must be one!)
    1249             :  *
    1250             :  * NB: after this, the flex input state is unspecified; caller must
    1251             :  * switch to an appropriate buffer to continue lexing.
    1252             :  * See psqlscan_select_top_buffer().
    1253             :  */
    1254             : void
    1255             : psqlscan_pop_buffer_stack(PsqlScanState state)
    1256         272 : {
    1257             :     StackElem  *stackelem = state->buffer_stack;
    1258         272 : 
    1259             :     state->buffer_stack = stackelem->next;
    1260         272 :     yy_delete_buffer(stackelem->buf, state->scanner);
    1261         272 :     free(stackelem->bufstring);
    1262         272 :     if (stackelem->origstring)
    1263         272 :         free(stackelem->origstring);
    1264           0 :     if (stackelem->varname)
    1265         272 :         free(stackelem->varname);
    1266         272 :     free(stackelem);
    1267         272 : }
    1268         272 : 
    1269             : /*
    1270             :  * Select the topmost surviving buffer as the active input.
    1271             :  */
    1272             : void
    1273             : psqlscan_select_top_buffer(PsqlScanState state)
    1274         272 : {
    1275             :     StackElem  *stackelem = state->buffer_stack;
    1276         272 : 
    1277             :     if (stackelem != NULL)
    1278         272 :     {
    1279             :         yy_switch_to_buffer(stackelem->buf, state->scanner);
    1280           0 :         state->curline = stackelem->bufstring;
    1281           0 :         state->refline = stackelem->origstring ? stackelem->origstring : stackelem->bufstring;
    1282           0 :     }
    1283             :     else
    1284             :     {
    1285             :         yy_switch_to_buffer(state->scanbufhandle, state->scanner);
    1286         272 :         state->curline = state->scanbuf;
    1287         272 :         state->refline = state->scanline;
    1288         272 :     }
    1289             : }
    1290         272 : 
    1291             : /*
    1292             :  * Check if specified variable name is the source for any string
    1293             :  * currently being scanned
    1294             :  */
    1295             : bool
    1296             : psqlscan_var_is_current_source(PsqlScanState state, const char *varname)
    1297         272 : {
    1298             :     StackElem  *stackelem;
    1299             : 
    1300             :     for (stackelem = state->buffer_stack;
    1301         272 :          stackelem != NULL;
    1302             :          stackelem = stackelem->next)
    1303           0 :     {
    1304             :         if (stackelem->varname && strcmp(stackelem->varname, varname) == 0)
    1305           0 :             return true;
    1306           0 :     }
    1307             :     return false;
    1308         272 : }
    1309             : 
    1310             : /*
    1311             :  * Set up a flex input buffer to scan the given data.  We always make a
    1312             :  * copy of the data.  If working in an unsafe encoding, the copy has
    1313             :  * multibyte sequences replaced by FFs to avoid fooling the lexer rules.
    1314             :  *
    1315             :  * NOTE SIDE EFFECT: the new buffer is made the active flex input buffer.
    1316             :  */
    1317             : YY_BUFFER_STATE
    1318             : psqlscan_prepare_buffer(PsqlScanState state, const char *txt, int len,
    1319      301514 :                         char **txtcopy)
    1320             : {
    1321             :     char       *newtxt;
    1322             : 
    1323             :     /* Flex wants two \0 characters after the actual data */
    1324             :     newtxt = pg_malloc(len + 2);
    1325      301514 :     *txtcopy = newtxt;
    1326      301514 :     newtxt[len] = newtxt[len + 1] = YY_END_OF_BUFFER_CHAR;
    1327      301514 : 
    1328             :     if (state->safe_encoding)
    1329      301514 :         memcpy(newtxt, txt, len);
    1330      301514 :     else
    1331             :     {
    1332             :         /* Gotta do it the hard way */
    1333             :         int         i = 0;
    1334           0 : 
    1335             :         while (i < len)
    1336           0 :         {
    1337             :             int         thislen = PQmblen(txt + i, state->encoding);
    1338           0 : 
    1339             :             /* first byte should always be okay... */
    1340             :             newtxt[i] = txt[i];
    1341           0 :             i++;
    1342           0 :             while (--thislen > 0 && i < len)
    1343           0 :                 newtxt[i++] = (char) 0xFF;
    1344           0 :         }
    1345             :     }
    1346             : 
    1347             :     return yy_scan_buffer(newtxt, len + 2, state->scanner);
    1348      301514 : }
    1349             : 
    1350             : /*
    1351             :  * psqlscan_emit() --- body for ECHO macro
    1352             :  *
    1353             :  * NB: this must be used for ALL and ONLY the text copied from the flex
    1354             :  * input data.  If you pass it something that is not part of the yytext
    1355             :  * string, you are making a mistake.  Internally generated text can be
    1356             :  * appended directly to state->output_buf.
    1357             :  */
    1358             : void
    1359             : psqlscan_emit(PsqlScanState state, const char *txt, int len)
    1360     3560262 : {
    1361             :     PQExpBuffer output_buf = state->output_buf;
    1362     3560262 : 
    1363             :     if (state->safe_encoding)
    1364     3560262 :         appendBinaryPQExpBuffer(output_buf, txt, len);
    1365     3560262 :     else
    1366             :     {
    1367             :         /* Gotta do it the hard way */
    1368             :         const char *reference = state->refline;
    1369           0 :         int         i;
    1370             : 
    1371             :         reference += (txt - state->curline);
    1372           0 : 
    1373             :         for (i = 0; i < len; i++)
    1374           0 :         {
    1375             :             char        ch = txt[i];
    1376           0 : 
    1377             :             if (ch == (char) 0xFF)
    1378           0 :                 ch = reference[i];
    1379           0 :             appendPQExpBufferChar(output_buf, ch);
    1380           0 :         }
    1381             :     }
    1382             : }
    1383     3560262 : 
    1384             : /*
    1385             :  * psqlscan_extract_substring --- fetch value of (part of) the current token
    1386             :  *
    1387             :  * This is like psqlscan_emit(), except that the data is returned as a
    1388             :  * malloc'd string rather than being pushed directly to state->output_buf.
    1389             :  */
    1390             : char *
    1391             : psqlscan_extract_substring(PsqlScanState state, const char *txt, int len)
    1392        2088 : {
    1393             :     char       *result = (char *) pg_malloc(len + 1);
    1394        2088 : 
    1395             :     if (state->safe_encoding)
    1396        2088 :         memcpy(result, txt, len);
    1397        2088 :     else
    1398             :     {
    1399             :         /* Gotta do it the hard way */
    1400             :         const char *reference = state->refline;
    1401           0 :         int         i;
    1402             : 
    1403             :         reference += (txt - state->curline);
    1404           0 : 
    1405             :         for (i = 0; i < len; i++)
    1406           0 :         {
    1407             :             char        ch = txt[i];
    1408           0 : 
    1409             :             if (ch == (char) 0xFF)
    1410           0 :                 ch = reference[i];
    1411           0 :             result[i] = ch;
    1412           0 :         }
    1413             :     }
    1414             :     result[len] = '\0';
    1415        2088 :     return result;
    1416        2088 : }
    1417             : 
    1418             : /*
    1419             :  * psqlscan_escape_variable --- process :'VARIABLE' or :"VARIABLE"
    1420             :  *
    1421             :  * If the variable name is found, escape its value using the appropriate
    1422             :  * quoting method and emit the value to output_buf.  (Since the result is
    1423             :  * surely quoted, there is never any reason to rescan it.)  If we don't
    1424             :  * find the variable or escaping fails, emit the token as-is.
    1425             :  */
    1426             : void
    1427             : psqlscan_escape_variable(PsqlScanState state, const char *txt, int len,
    1428          52 :                          PsqlScanQuoteType quote)
    1429             : {
    1430             :     char       *varname;
    1431             :     char       *value;
    1432             : 
    1433             :     /* Variable lookup. */
    1434             :     varname = psqlscan_extract_substring(state, txt + 2, len - 3);
    1435          52 :     if (state->callbacks->get_variable)
    1436          52 :         value = state->callbacks->get_variable(varname, quote,
    1437          52 :                                                state->cb_passthrough);
    1438             :     else
    1439             :         value = NULL;
    1440           0 :     free(varname);
    1441          52 : 
    1442             :     if (value)
    1443          52 :     {
    1444             :         /* Emit the suitably-escaped value */
    1445             :         appendPQExpBufferStr(state->output_buf, value);
    1446          28 :         free(value);
    1447          28 :     }
    1448             :     else
    1449             :     {
    1450             :         /* Emit original token as-is */
    1451             :         psqlscan_emit(state, txt, len);
    1452          24 :     }
    1453             : }
    1454          52 : 
    1455             : void
    1456             : psqlscan_test_variable(PsqlScanState state, const char *txt, int len)
    1457          16 : {
    1458             :     char    *varname;
    1459             :     char    *value;
    1460             : 
    1461             :     varname = psqlscan_extract_substring(state, txt + 3, len - 4);
    1462          16 :     if (state->callbacks->get_variable)
    1463          16 :         value = state->callbacks->get_variable(varname, PQUOTE_PLAIN,
    1464          16 :                                                state->cb_passthrough);
    1465             :     else
    1466             :         value = NULL;
    1467           0 :     free(varname);
    1468          16 : 
    1469             :     if (value != NULL)
    1470          16 :     {
    1471             :         psqlscan_emit(state, "TRUE", 4);
    1472           8 :         free(value);
    1473           8 :     }
    1474             :     else
    1475             :     {
    1476             :         psqlscan_emit(state, "FALSE", 5);
    1477           8 :     }
    1478             : }

Generated by: LCOV version 1.13