LCOV - differential code coverage report
Current view: top level - src/bin/psql - psqlscanslash.l (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC CBC EUB ECB DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 65.9 % 299 197 7 2 54 39 7 107 83 53 112 3
Current Date: 2023-04-08 15:15:32 Functions: 85.7 % 7 6 1 6 1 6
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : %top{
       2                 : /*-------------------------------------------------------------------------
       3                 :  *
       4                 :  * psqlscanslash.l
       5                 :  *    lexical scanner for psql backslash commands
       6                 :  *
       7                 :  * XXX Avoid creating backtracking cases --- see the backend lexer for info.
       8                 :  *
       9                 :  * See fe_utils/psqlscan_int.h for additional commentary.
      10                 :  *
      11                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      12                 :  * Portions Copyright (c) 1994, Regents of the University of California
      13                 :  *
      14                 :  * IDENTIFICATION
      15                 :  *    src/bin/psql/psqlscanslash.l
      16                 :  *
      17                 :  *-------------------------------------------------------------------------
      18                 :  */
      19                 : #include "postgres_fe.h"
      20                 : 
      21                 : #include "common.h"
      22                 : #include "psqlscanslash.h"
      23                 : 
      24                 : #include "common/logging.h"
      25                 : #include "fe_utils/conditional.h"
      26                 : 
      27                 : #include "libpq-fe.h"
      28                 : }
      29                 : 
      30                 : %{
      31                 : #include "fe_utils/psqlscan_int.h"
      32                 : 
      33                 : /*
      34                 :  * We must have a typedef YYSTYPE for yylex's first argument, but this lexer
      35                 :  * doesn't presently make use of that argument, so just declare it as int.
      36                 :  */
      37                 : typedef int YYSTYPE;
      38                 : 
      39                 : /*
      40                 :  * Set the type of yyextra; we use it as a pointer back to the containing
      41                 :  * PsqlScanState.
      42                 :  */
      43                 : #define YY_EXTRA_TYPE PsqlScanState
      44                 : 
      45                 : /*
      46                 :  * These variables do not need to be saved across calls.  Yeah, it's a bit
      47                 :  * of a hack, but putting them into PsqlScanStateData would be klugy too.
      48                 :  */
      49                 : static enum slash_option_type option_type;
      50                 : static char *option_quote;
      51                 : static int  unquoted_option_chars;
      52                 : static int  backtick_start_offset;
      53                 : 
      54                 : 
      55                 : /* Return values from yylex() */
      56                 : #define LEXRES_EOL          0   /* end of input */
      57                 : #define LEXRES_OK           1   /* OK completion of backslash argument */
      58                 : 
      59                 : 
      60                 : static void evaluate_backtick(PsqlScanState state);
      61                 : 
      62                 : #define ECHO psqlscan_emit(cur_state, yytext, yyleng)
      63                 : 
      64                 : /*
      65                 :  * Work around a bug in flex 2.5.35: it emits a couple of functions that
      66                 :  * it forgets to emit declarations for.  Since we use -Wmissing-prototypes,
      67                 :  * this would cause warnings.  Providing our own declarations should be
      68                 :  * harmless even when the bug gets fixed.
      69                 :  */
      70                 : extern int  slash_yyget_column(yyscan_t yyscanner);
      71                 : extern void slash_yyset_column(int column_no, yyscan_t yyscanner);
      72                 : 
      73                 : /* LCOV_EXCL_START */
      74                 : 
      75                 : %}
      76                 : 
      77                 : /* Except for the prefix, these options should match psqlscan.l */
      78                 : %option reentrant
      79                 : %option bison-bridge
      80                 : %option 8bit
      81                 : %option never-interactive
      82                 : %option nodefault
      83                 : %option noinput
      84                 : %option nounput
      85                 : %option noyywrap
      86                 : %option warn
      87                 : %option prefix="slash_yy"
      88                 : 
      89                 : /*
      90                 :  * OK, here is a short description of lex/flex rules behavior.
      91                 :  * The longest pattern which matches an input string is always chosen.
      92                 :  * For equal-length patterns, the first occurring in the rules list is chosen.
      93                 :  * INITIAL is the starting state, to which all non-conditional rules apply.
      94                 :  * Exclusive states change parsing rules while the state is active.  When in
      95                 :  * an exclusive state, only those rules defined for that state apply.
      96                 :  */
      97                 : 
      98                 : /* Exclusive states for lexing backslash commands */
      99                 : %x xslashcmd
     100                 : %x xslashargstart
     101                 : %x xslasharg
     102                 : %x xslashquote
     103                 : %x xslashbackquote
     104                 : %x xslashdquote
     105                 : %x xslashwholeline
     106                 : %x xslashend
     107                 : 
     108                 : /*
     109                 :  * Assorted character class definitions that should match psqlscan.l.
     110                 :  */
     111                 : space           [ \t\n\r\f]
     112                 : quote           '
     113                 : xeoctesc        [\\][0-7]{1,3}
     114                 : xehexesc        [\\]x[0-9A-Fa-f]{1,2}
     115                 : xqdouble        {quote}{quote}
     116                 : dquote          \"
     117                 : variable_char   [A-Za-z\200-\377_0-9]
     118                 : 
     119                 : other           .
     120                 : 
     121                 : %%
     122                 : 
     123                 : %{
     124                 :         /* Declare some local variables inside yylex(), for convenience */
     125                 :         PsqlScanState cur_state = yyextra;
     126 GIC       28389 :         PQExpBuffer output_buf = cur_state->output_buf;
     127           28389 : 
     128 ECB             :         /*
     129                 :          * Force flex into the state indicated by start_state.  This has a
     130                 :          * couple of purposes: it lets some of the functions below set a new
     131                 :          * starting state without ugly direct access to flex variables, and it
     132                 :          * allows us to transition from one flex lexer to another so that we
     133                 :          * can lex different parts of the source string using separate lexers.
     134                 :          */
     135                 :         BEGIN(cur_state->start_state);
     136 GIC       28389 : %}
     137                 : 
     138 ECB             :     /*
     139                 :      * We don't really expect to be invoked in the INITIAL state in this
     140                 :      * lexer; but if we are, just spit data to the output_buf until EOF.
     141                 :      */
     142                 : 
     143                 : {other}|\n      { ECHO; }
     144 UIC           0 : 
     145               0 :     /*
     146 EUB             :      * Exclusive lexer states to handle backslash command lexing
     147                 :      */
     148                 : 
     149                 : <xslashcmd>{
     150                 :     /* command name ends at whitespace or backslash; eat all else */
     151 GIC        5179 : 
     152                 : {space}|"\\"  {
     153 ECB             :                     yyless(0);
     154 GIC        5179 :                     cur_state->start_state = YY_START;
     155            5179 :                     return LEXRES_OK;
     156 CBC        5179 :                 }
     157 ECB             : 
     158                 : {other}         { ECHO; }
     159 GIC       18069 : 
     160           18069 : }
     161 ECB             : 
     162                 : <xslashargstart>{
     163                 :     /*
     164                 :      * Discard any whitespace before argument, then go to xslasharg state.
     165                 :      * An exception is that "|" is only special at start of argument, so we
     166                 :      * check for it here.
     167                 :      */
     168 GIC        7272 : 
     169                 : {space}+        { }
     170 ECB             : 
     171 GIC        7272 : "|"               {
     172              12 :                     if (option_type == OT_FILEPIPE)
     173 CBC          12 :                     {
     174 ECB             :                         /* treat like whole-string case */
     175                 :                         ECHO;
     176 GIC           3 :                         BEGIN(xslashwholeline);
     177               3 :                     }
     178 ECB             :                     else
     179                 :                     {
     180                 :                         /* vertical bar is not special otherwise */
     181                 :                         yyless(0);
     182 GIC           9 :                         BEGIN(xslasharg);
     183               9 :                     }
     184 ECB             :                 }
     185                 : 
     186 GIC          12 : {other}         {
     187            7322 :                     yyless(0);
     188 CBC        7322 :                     BEGIN(xslasharg);
     189            7322 :                 }
     190 ECB             : 
     191 CBC        7322 : }
     192                 : 
     193 ECB             : <xslasharg>{
     194                 :     /*
     195                 :      * Default processing of text in a slash command's argument.
     196                 :      *
     197                 :      * Note: unquoted_option_chars counts the number of characters at the
     198                 :      * end of the argument that were not subject to any form of quoting.
     199                 :      * psql_scan_slash_option needs this to strip trailing semicolons safely.
     200                 :      */
     201 GIC        2403 : 
     202                 : {space}|"\\"  {
     203 ECB             :                     /*
     204                 :                      * Unquoted space is end of arg; do not eat.  Likewise
     205                 :                      * backslash is end of command or next command, do not eat
     206                 :                      *
     207                 :                      * XXX this means we can't conveniently accept options
     208                 :                      * that include unquoted backslashes; therefore, option
     209                 :                      * processing that encourages use of backslashes is rather
     210                 :                      * broken.
     211                 :                      */
     212                 :                     yyless(0);
     213 GIC        2403 :                     cur_state->start_state = YY_START;
     214            2403 :                     return LEXRES_OK;
     215 CBC        2403 :                 }
     216 ECB             : 
     217                 : {quote}         {
     218 GIC         500 :                     *option_quote = '\'';
     219             500 :                     unquoted_option_chars = 0;
     220 CBC         500 :                     BEGIN(xslashquote);
     221             500 :                 }
     222 ECB             : 
     223 CBC         500 : "`"               {
     224 GIC           9 :                     backtick_start_offset = output_buf->len;
     225 CBC           9 :                     *option_quote = '`';
     226               9 :                     unquoted_option_chars = 0;
     227               9 :                     BEGIN(xslashbackquote);
     228               9 :                 }
     229 ECB             : 
     230 CBC           9 : {dquote}        {
     231 GIC         744 :                     ECHO;
     232 CBC         744 :                     *option_quote = '"';
     233             744 :                     unquoted_option_chars = 0;
     234             744 :                     BEGIN(xslashdquote);
     235             744 :                 }
     236 ECB             : 
     237 CBC         744 : :{variable_char}+   {
     238 GIC         527 :                     /* Possible psql variable substitution */
     239 ECB             :                     if (cur_state->callbacks->get_variable == NULL)
     240 CBC         527 :                         ECHO;
     241 UIC           0 :                     else
     242 ECB             :                     {
     243 EUB             :                         char       *varname;
     244                 :                         char       *value;
     245                 : 
     246                 :                         varname = psqlscan_extract_substring(cur_state,
     247 GIC         527 :                                                              yytext + 1,
     248             527 :                                                              yyleng - 1);
     249 CBC         527 :                         value = cur_state->callbacks->get_variable(varname,
     250             527 :                                                                    PQUOTE_PLAIN,
     251 ECB             :                                                                    cur_state->cb_passthrough);
     252                 :                         free(varname);
     253 GIC         527 : 
     254                 :                         /*
     255 ECB             :                          * The variable value is just emitted without any
     256                 :                          * further examination.  This is consistent with the
     257                 :                          * pre-8.0 code behavior, if not with the way that
     258                 :                          * variables are handled outside backslash commands.
     259                 :                          * Note that we needn't guard against recursion here.
     260                 :                          */
     261                 :                         if (value)
     262 GIC         527 :                         {
     263                 :                             appendPQExpBufferStr(output_buf, value);
     264 CBC         509 :                             free(value);
     265 GIC         509 :                         }
     266 ECB             :                         else
     267                 :                             ECHO;
     268 GIC          18 : 
     269                 :                         *option_quote = ':';
     270 CBC         527 :                     }
     271                 :                     unquoted_option_chars = 0;
     272             527 :                 }
     273                 : 
     274             527 : :'{variable_char}+' {
     275 GIC          23 :                     psqlscan_escape_variable(cur_state, yytext, yyleng,
     276 CBC          23 :                                              PQUOTE_SQL_LITERAL);
     277 ECB             :                     *option_quote = ':';
     278 CBC          23 :                     unquoted_option_chars = 0;
     279 GIC          23 :                 }
     280 ECB             : 
     281 CBC          23 : 
     282 GIC          12 : :\"{variable_char}+\" {
     283 ECB             :                     psqlscan_escape_variable(cur_state, yytext, yyleng,
     284 CBC          12 :                                              PQUOTE_SQL_IDENT);
     285                 :                     *option_quote = ':';
     286              12 :                     unquoted_option_chars = 0;
     287 GIC          12 :                 }
     288 ECB             : 
     289 CBC          12 : :\{\?{variable_char}+\} {
     290 GIC           6 :                     psqlscan_test_variable(cur_state, yytext, yyleng);
     291 CBC           6 :                 }
     292 ECB             : 
     293 CBC           6 : :'{variable_char}*  {
     294 UIC           0 :                     /* Throw back everything but the colon */
     295 ECB             :                     yyless(1);
     296 UBC           0 :                     unquoted_option_chars++;
     297 UIC           0 :                     ECHO;
     298 UBC           0 :                 }
     299 EUB             : 
     300 UBC           0 : :\"{variable_char}*    {
     301 UIC           0 :                     /* Throw back everything but the colon */
     302 EUB             :                     yyless(1);
     303 UBC           0 :                     unquoted_option_chars++;
     304 UIC           0 :                     ECHO;
     305 UBC           0 :                 }
     306 EUB             : 
     307 UBC           0 : :\{\?{variable_char}*   {
     308 UIC           0 :                     /* Throw back everything but the colon */
     309 EUB             :                     yyless(1);
     310 UBC           0 :                     unquoted_option_chars++;
     311 UIC           0 :                     ECHO;
     312 UBC           0 :                 }
     313 EUB             : 
     314 UBC           0 : :\{     {
     315 UIC           0 :                     /* Throw back everything but the colon */
     316 EUB             :                     yyless(1);
     317 UBC           0 :                     unquoted_option_chars++;
     318 UIC           0 :                     ECHO;
     319 UBC           0 :                 }
     320 EUB             : 
     321 UBC           0 : {other}         {
     322 GIC       55227 :                     unquoted_option_chars++;
     323 GBC       55227 :                     ECHO;
     324 CBC       55227 :                 }
     325 ECB             : 
     326 CBC       55227 : }
     327                 : 
     328 ECB             : <xslashquote>{
     329                 :     /*
     330                 :      * single-quoted text: copy literally except for '' and backslash
     331                 :      * sequences
     332                 :      */
     333 GIC         500 : 
     334                 : {quote}         { BEGIN(xslasharg); }
     335 CBC         500 : 
     336 GIC         500 : {xqdouble}      { appendPQExpBufferChar(output_buf, '\''); }
     337 CBC          44 : 
     338              44 : "\\n"         { appendPQExpBufferChar(output_buf, '\n'); }
     339               3 : "\\t"         { appendPQExpBufferChar(output_buf, '\t'); }
     340               3 : "\\b"         { appendPQExpBufferChar(output_buf, '\b'); }
     341               3 : "\\r"         { appendPQExpBufferChar(output_buf, '\r'); }
     342 LBC           0 : "\\f"         { appendPQExpBufferChar(output_buf, '\f'); }
     343 CBC           3 : 
     344 UBC           0 : {xeoctesc}      {
     345 CBC           3 :                     /* octal case */
     346 EUB             :                     appendPQExpBufferChar(output_buf,
     347 CBC           3 :                                           (char) strtol(yytext + 1, NULL, 8));
     348 GIC           3 :                 }
     349 ECB             : 
     350 CBC           3 : {xehexesc}      {
     351 UIC           0 :                     /* hex case */
     352 ECB             :                     appendPQExpBufferChar(output_buf,
     353 UBC           0 :                                           (char) strtol(yytext + 2, NULL, 16));
     354 UIC           0 :                 }
     355 EUB             : 
     356 UBC           0 : "\\".         { psqlscan_emit(cur_state, yytext + 1, 1); }
     357 GIC           6 : 
     358 GBC           6 : {other}|\n      { ECHO; }
     359 CBC        7640 : 
     360            7640 : }
     361 ECB             : 
     362                 : <xslashbackquote>{
     363                 :     /*
     364                 :      * backticked text: copy everything until next backquote (expanding
     365                 :      * variable references, but doing nought else), then evaluate.
     366                 :      */
     367 GIC           9 : 
     368                 : "`"               {
     369 ECB             :                     /* In an inactive \if branch, don't evaluate the command */
     370                 :                     if (cur_state->cb_passthrough == NULL ||
     371 GIC          18 :                         conditional_active((ConditionalStack) cur_state->cb_passthrough))
     372               9 :                         evaluate_backtick(cur_state);
     373 LBC           0 :                     BEGIN(xslasharg);
     374 CBC           9 :                 }
     375 EUB             : 
     376 CBC           9 : :{variable_char}+   {
     377 UIC           0 :                     /* Possible psql variable substitution */
     378 ECB             :                     if (cur_state->callbacks->get_variable == NULL)
     379 UBC           0 :                         ECHO;
     380 UIC           0 :                     else
     381 EUB             :                     {
     382                 :                         char       *varname;
     383                 :                         char       *value;
     384                 : 
     385                 :                         varname = psqlscan_extract_substring(cur_state,
     386 UIC           0 :                                                              yytext + 1,
     387               0 :                                                              yyleng - 1);
     388 UBC           0 :                         value = cur_state->callbacks->get_variable(varname,
     389               0 :                                                                    PQUOTE_PLAIN,
     390 EUB             :                                                                    cur_state->cb_passthrough);
     391                 :                         free(varname);
     392 UIC           0 : 
     393                 :                         if (value)
     394 UBC           0 :                         {
     395                 :                             appendPQExpBufferStr(output_buf, value);
     396               0 :                             free(value);
     397 UIC           0 :                         }
     398 EUB             :                         else
     399                 :                             ECHO;
     400 UIC           0 :                     }
     401                 :                 }
     402 EUB             : 
     403 UIC           0 : :'{variable_char}+' {
     404               0 :                     psqlscan_escape_variable(cur_state, yytext, yyleng,
     405 UBC           0 :                                              PQUOTE_SHELL_ARG);
     406 EUB             :                 }
     407                 : 
     408 UIC           0 : :'{variable_char}*  {
     409               0 :                     /* Throw back everything but the colon */
     410 EUB             :                     yyless(1);
     411 UBC           0 :                     ECHO;
     412 UIC           0 :                 }
     413 EUB             : 
     414 UBC           0 : {other}|\n      { ECHO; }
     415 GIC         117 : 
     416 GBC         117 : }
     417 ECB             : 
     418                 : <xslashdquote>{
     419                 :     /* double-quoted text: copy verbatim, including the double quotes */
     420 GIC         744 : 
     421                 : {dquote}        {
     422 ECB             :                     ECHO;
     423 GIC         744 :                     BEGIN(xslasharg);
     424             744 :                 }
     425 ECB             : 
     426 CBC         744 : {other}|\n      { ECHO; }
     427 GIC       13584 : 
     428 CBC       13584 : }
     429 ECB             : 
     430                 : <xslashwholeline>{
     431                 :     /* copy everything until end of input line */
     432                 :     /* but suppress leading whitespace */
     433 GIC         497 : 
     434                 : {space}+        {
     435 ECB             :                     if (output_buf->len > 0)
     436 GIC         497 :                         ECHO;
     437             347 :                 }
     438 ECB             : 
     439 CBC         497 : {other}         { ECHO; }
     440 GIC        4420 : 
     441 CBC        4420 : }
     442 ECB             : 
     443                 : <xslashend>{
     444                 :     /* at end of command, eat a double backslash, but not anything else */
     445 GIC          35 : 
     446                 : "\\\\"            {
     447 ECB             :                     cur_state->start_state = YY_START;
     448 GIC          35 :                     return LEXRES_OK;
     449              35 :                 }
     450 ECB             : 
     451                 : {other}|\n      {
     452 GIC          63 :                     yyless(0);
     453              63 :                     cur_state->start_state = YY_START;
     454 CBC          63 :                     return LEXRES_OK;
     455              63 :                 }
     456 ECB             : 
     457                 : }
     458                 : 
     459 GIC       20709 : <<EOF>>         {
     460                 :                     if (cur_state->buffer_stack == NULL)
     461 CBC       20709 :                     {
     462                 :                         cur_state->start_state = YY_START;
     463           20709 :                         return LEXRES_EOL;      /* end of input reached */
     464 GIC       20709 :                     }
     465 ECB             : 
     466                 :                     /*
     467                 :                      * We were expanding a variable, so pop the inclusion
     468                 :                      * stack and keep lexing
     469                 :                      */
     470                 :                     psqlscan_pop_buffer_stack(cur_state);
     471 UIC           0 :                     psqlscan_select_top_buffer(cur_state);
     472               0 :                 }
     473 EUB             : 
     474 UBC           0 : %%
     475 UIC           0 : 
     476 EUB             : /* LCOV_EXCL_STOP */
     477                 : 
     478                 : /*
     479                 :  * Scan the command name of a psql backslash command.  This should be called
     480                 :  * after psql_scan() returns PSCAN_BACKSLASH.  It is assumed that the input
     481                 :  * has been consumed through the leading backslash.
     482                 :  *
     483                 :  * The return value is a malloc'd copy of the command name, as parsed off
     484                 :  * from the input.
     485                 :  */
     486                 : char *
     487                 : psql_scan_slash_command(PsqlScanState state)
     488 GIC        6183 : {
     489                 :     PQExpBufferData mybuf;
     490 ECB             : 
     491                 :     /* Must be scanning already */
     492                 :     Assert(state->scanbufhandle != NULL);
     493 GIC        6183 : 
     494                 :     /* Build a local buffer that we'll return the data of */
     495 ECB             :     initPQExpBuffer(&mybuf);
     496 GIC        6183 : 
     497                 :     /* Set current output target */
     498 ECB             :     state->output_buf = &mybuf;
     499 GIC        6183 : 
     500                 :     /* Set input source */
     501 ECB             :     if (state->buffer_stack != NULL)
     502 GIC        6183 :         yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
     503 UIC           0 :     else
     504 ECB             :         yy_switch_to_buffer(state->scanbufhandle, state->scanner);
     505 GBC        6183 : 
     506                 :     /*
     507 ECB             :      * Set lexer start state.  Note that this is sufficient to switch
     508                 :      * state->scanner over to using the tables in this lexer file.
     509                 :      */
     510                 :     state->start_state = xslashcmd;
     511 GIC        6183 : 
     512                 :     /* And lex. */
     513 ECB             :     yylex(NULL, state->scanner);
     514 GIC        6183 : 
     515                 :     /* There are no possible errors in this lex state... */
     516 ECB             : 
     517                 :     /*
     518                 :      * In case the caller returns to using the regular SQL lexer, reselect the
     519                 :      * appropriate initial state.
     520                 :      */
     521                 :     psql_scan_reselect_sql_lexer(state);
     522 GIC        6183 : 
     523                 :     return mybuf.data;
     524 CBC        6183 : }
     525                 : 
     526 ECB             : /*
     527                 :  * Parse off the next argument for a backslash command, and return it as a
     528                 :  * malloc'd string.  If there are no more arguments, returns NULL.
     529                 :  *
     530                 :  * type tells what processing, if any, to perform on the option string;
     531                 :  * for example, if it's a SQL identifier, we want to downcase any unquoted
     532                 :  * letters.
     533                 :  *
     534                 :  * if quote is not NULL, *quote is set to 0 if no quoting was found, else
     535                 :  * the last quote symbol used in the argument.
     536                 :  *
     537                 :  * if semicolon is true, unquoted trailing semicolon(s) that would otherwise
     538                 :  * be taken as part of the option string will be stripped.
     539                 :  *
     540                 :  * NOTE: the only possible syntax errors for backslash options are unmatched
     541                 :  * quotes, which are detected when we run out of input.  Therefore, on a
     542                 :  * syntax error we just throw away the string and return NULL; there is no
     543                 :  * need to worry about flushing remaining input.
     544                 :  */
     545                 : char *
     546                 : psql_scan_slash_option(PsqlScanState state,
     547 GIC       16023 :                        enum slash_option_type type,
     548                 :                        char *quote,
     549 ECB             :                        bool semicolon)
     550                 : {
     551                 :     PQExpBufferData mybuf;
     552                 :     int         lexresult PG_USED_FOR_ASSERTS_ONLY;
     553                 :     int         final_state;
     554                 :     char        local_quote;
     555                 : 
     556                 :     /* Must be scanning already */
     557                 :     Assert(state->scanbufhandle != NULL);
     558 GIC       16023 : 
     559                 :     if (quote == NULL)
     560 CBC       16023 :         quote = &local_quote;
     561 GIC       14577 :     *quote = 0;
     562 CBC       16023 : 
     563 ECB             :     /* Build a local buffer that we'll return the data of */
     564                 :     initPQExpBuffer(&mybuf);
     565 GIC       16023 : 
     566                 :     /* Set up static variables that will be used by yylex */
     567 ECB             :     option_type = type;
     568 GIC       16023 :     option_quote = quote;
     569           16023 :     unquoted_option_chars = 0;
     570 CBC       16023 : 
     571 ECB             :     /* Set current output target */
     572                 :     state->output_buf = &mybuf;
     573 GIC       16023 : 
     574                 :     /* Set input source */
     575 ECB             :     if (state->buffer_stack != NULL)
     576 GIC       16023 :         yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
     577 UIC           0 :     else
     578 ECB             :         yy_switch_to_buffer(state->scanbufhandle, state->scanner);
     579 GBC       16023 : 
     580                 :     /* Set lexer start state */
     581 ECB             :     if (type == OT_WHOLE_LINE)
     582 GIC       16023 :         state->start_state = xslashwholeline;
     583             682 :     else
     584 ECB             :         state->start_state = xslashargstart;
     585 CBC       15341 : 
     586                 :     /* And lex. */
     587 ECB             :     lexresult = yylex(NULL, state->scanner);
     588 GIC       16023 : 
     589                 :     /* Save final state for a moment... */
     590 ECB             :     final_state = state->start_state;
     591 GIC       16023 : 
     592                 :     /*
     593 ECB             :      * In case the caller returns to using the regular SQL lexer, reselect the
     594                 :      * appropriate initial state.
     595                 :      */
     596                 :     psql_scan_reselect_sql_lexer(state);
     597 GIC       16023 : 
     598                 :     /*
     599 ECB             :      * Check the lex result: we should have gotten back either LEXRES_OK
     600                 :      * or LEXRES_EOL (the latter indicating end of string).  If we were inside
     601                 :      * a quoted string, as indicated by final_state, EOL is an error.
     602                 :      */
     603                 :     Assert(lexresult == LEXRES_EOL || lexresult == LEXRES_OK);
     604 GIC       16023 : 
     605                 :     switch (final_state)
     606 CBC       16023 :     {
     607                 :         case xslashargstart:
     608            8007 :             /* empty arg */
     609                 :             break;
     610            8007 :         case xslasharg:
     611 GIC        7331 :             /* Strip any unquoted trailing semi-colons if requested */
     612 ECB             :             if (semicolon)
     613 CBC        7331 :             {
     614                 :                 while (unquoted_option_chars-- > 0 &&
     615            3105 :                        mybuf.len > 0 &&
     616 GIC        3108 :                        mybuf.data[mybuf.len - 1] == ';')
     617 CBC        2684 :                 {
     618 ECB             :                     mybuf.data[--mybuf.len] = '\0';
     619 CBC           3 :                 }
     620                 :             }
     621 ECB             : 
     622                 :             /*
     623                 :              * If SQL identifier processing was requested, then we strip out
     624                 :              * excess double quotes and optionally downcase unquoted letters.
     625                 :              */
     626                 :             if (type == OT_SQLID || type == OT_SQLIDHACK)
     627 GIC        7331 :             {
     628                 :                 dequote_downcase_identifier(mybuf.data,
     629 CBC         128 :                                             (type != OT_SQLIDHACK),
     630                 :                                             state->encoding);
     631 ECB             :                 /* update mybuf.len for possible shortening */
     632                 :                 mybuf.len = strlen(mybuf.data);
     633 GIC         128 :             }
     634                 :             break;
     635 CBC        7331 :         case xslashquote:
     636 UIC           0 :         case xslashbackquote:
     637 ECB             :         case xslashdquote:
     638 EUB             :             /* must have hit EOL inside quotes */
     639                 :             pg_log_error("unterminated quoted string");
     640 UIC           0 :             termPQExpBuffer(&mybuf);
     641               0 :             return NULL;
     642 UBC           0 :         case xslashwholeline:
     643 GBC         685 :             /* always okay */
     644 EUB             :             break;
     645 CBC         685 :         default:
     646 UIC           0 :             /* can't get here */
     647 ECB             :             fprintf(stderr, "invalid YY_START\n");
     648 UBC           0 :             exit(1);
     649 UIC           0 :     }
     650 EUB             : 
     651                 :     /*
     652                 :      * An unquoted empty argument isn't possible unless we are at end of
     653                 :      * command.  Return NULL instead.
     654                 :      */
     655                 :     if (mybuf.len == 0 && *quote == 0)
     656 GIC       16023 :     {
     657                 :         termPQExpBuffer(&mybuf);
     658 CBC        8681 :         return NULL;
     659 GIC        8681 :     }
     660 ECB             : 
     661                 :     /* Else return the completed string. */
     662                 :     return mybuf.data;
     663 GIC        7342 : }
     664                 : 
     665 ECB             : /*
     666                 :  * Eat up any unused \\ to complete a backslash command.
     667                 :  */
     668                 : void
     669                 : psql_scan_slash_command_end(PsqlScanState state)
     670 GIC        6183 : {
     671                 :     /* Must be scanning already */
     672 ECB             :     Assert(state->scanbufhandle != NULL);
     673 GIC        6183 : 
     674                 :     /* Set current output target */
     675 ECB             :     state->output_buf = NULL;    /* we won't output anything */
     676 GIC        6183 : 
     677                 :     /* Set input source */
     678 ECB             :     if (state->buffer_stack != NULL)
     679 GIC        6183 :         yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
     680 UIC           0 :     else
     681 ECB             :         yy_switch_to_buffer(state->scanbufhandle, state->scanner);
     682 GBC        6183 : 
     683                 :     /* Set lexer start state */
     684 ECB             :     state->start_state = xslashend;
     685 GIC        6183 : 
     686                 :     /* And lex. */
     687 ECB             :     yylex(NULL, state->scanner);
     688 GIC        6183 : 
     689                 :     /* There are no possible errors in this lex state... */
     690 ECB             : 
     691                 :     /*
     692                 :      * We expect the caller to return to using the regular SQL lexer, so
     693                 :      * reselect the appropriate initial state.
     694                 :      */
     695                 :     psql_scan_reselect_sql_lexer(state);
     696 GIC        6183 : }
     697            6183 : 
     698 ECB             : /*
     699                 :  * Fetch current paren nesting depth
     700                 :  */
     701                 : int
     702                 : psql_scan_get_paren_depth(PsqlScanState state)
     703 GIC         114 : {
     704                 :     return state->paren_depth;
     705 CBC         114 : }
     706                 : 
     707 ECB             : /*
     708                 :  * Set paren nesting depth
     709                 :  */
     710                 : void
     711                 : psql_scan_set_paren_depth(PsqlScanState state, int depth)
     712 GIC          98 : {
     713                 :     Assert(depth >= 0);
     714 CBC          98 :     state->paren_depth = depth;
     715 GIC          98 : }
     716 CBC          98 : 
     717 ECB             : /*
     718                 :  * De-quote and optionally downcase a SQL identifier.
     719                 :  *
     720                 :  * The string at *str is modified in-place; it can become shorter,
     721                 :  * but not longer.
     722                 :  *
     723                 :  * If downcase is true then non-quoted letters are folded to lower case.
     724                 :  * Ideally this behavior will match the backend's downcase_identifier();
     725                 :  * but note that it could differ if LC_CTYPE is different in the frontend.
     726                 :  *
     727                 :  * Note that a string like FOO"BAR"BAZ will be converted to fooBARbaz;
     728                 :  * this is somewhat inconsistent with the SQL spec, which would have us
     729                 :  * parse it as several identifiers.  But for psql's purposes, we want a
     730                 :  * string like "foo"."bar" to be treated as one option, so there's little
     731                 :  * choice; this routine doesn't get to change the token boundaries.
     732                 :  */
     733                 : void
     734                 : dequote_downcase_identifier(char *str, bool downcase, int encoding)
     735 GIC         224 : {
     736                 :     bool        inquotes = false;
     737 CBC         224 :     char       *cp = str;
     738 GIC         224 : 
     739 ECB             :     while (*cp)
     740 CBC        1539 :     {
     741                 :         if (*cp == '"')
     742            1315 :         {
     743                 :             if (inquotes && cp[1] == '"')
     744              62 :             {
     745                 :                 /* Keep the first quote, remove the second */
     746 ECB             :                 cp++;
     747 GIC          10 :             }
     748                 :             else
     749 ECB             :                 inquotes = !inquotes;
     750 GIC          52 :             /* Collapse out quote at *cp */
     751                 :             memmove(cp, cp + 1, strlen(cp));
     752 CBC          62 :             /* do not advance cp */
     753                 :         }
     754 ECB             :         else
     755                 :         {
     756                 :             if (downcase && !inquotes)
     757 GIC        1253 :                 *cp = pg_tolower((unsigned char) *cp);
     758             138 :             cp += PQmblenBounded(cp, encoding);
     759 CBC        1253 :         }
     760 ECB             :     }
     761                 : }
     762 GIC         224 : 
     763                 : /*
     764 ECB             :  * Evaluate a backticked substring of a slash command's argument.
     765                 :  *
     766                 :  * The portion of output_buf starting at backtick_start_offset is evaluated
     767                 :  * as a shell command and then replaced by the command's output.
     768                 :  */
     769                 : static void
     770                 : evaluate_backtick(PsqlScanState state)
     771 UIC           0 : {
     772                 :     PQExpBuffer output_buf = state->output_buf;
     773 UBC           0 :     char       *cmd = output_buf->data + backtick_start_offset;
     774 UIC           0 :     PQExpBufferData cmd_output;
     775 EUB             :     FILE       *fd;
     776                 :     bool        error = false;
     777 UNC           0 :     int         exit_code = 0;
     778 UIC           0 :     char        buf[512];
     779                 :     size_t      result;
     780 EUB             : 
     781                 :     initPQExpBuffer(&cmd_output);
     782 UIC           0 : 
     783                 :     fflush(NULL);
     784               0 :     fd = popen(cmd, "r");
     785               0 :     if (!fd)
     786 UBC           0 :     {
     787                 :         pg_log_error("%s: %m", cmd);
     788               0 :         error = true;
     789 UNC           0 :         exit_code = -1;
     790 UBC           0 :     }
     791 EUB             : 
     792                 :     if (!error)
     793 UBC           0 :     {
     794 EUB             :         do
     795                 :         {
     796                 :             result = fread(buf, 1, sizeof(buf), fd);
     797 UIC           0 :             if (ferror(fd))
     798 UBC           0 :             {
     799                 :                 pg_log_error("%s: %m", cmd);
     800 UIC           0 :                 error = true;
     801               0 :                 break;
     802 UBC           0 :             }
     803 EUB             :             appendBinaryPQExpBuffer(&cmd_output, buf, result);
     804 UIC           0 :         } while (!feof(fd));
     805 UBC           0 :     }
     806 EUB             : 
     807                 :     if (fd)
     808 UIC           0 :     {
     809                 :         /*
     810                 :          * Although pclose's result always sets the shell result variables, we
     811                 :          * historically have abandoned the backtick substitution only if it
     812                 :          * returns -1.
     813                 :          */
     814                 :         exit_code = pclose(fd);
     815 UNC           0 :         if (exit_code == -1)
     816               0 :         {
     817                 :             pg_log_error("%s: %m", cmd);
     818               0 :             error = true;
     819               0 :         }
     820                 :     }
     821                 : 
     822 EUB             :     if (PQExpBufferDataBroken(cmd_output))
     823 UIC           0 :     {
     824                 :         pg_log_error("%s: out of memory", cmd);
     825               0 :         error = true;
     826               0 :     }
     827                 : 
     828                 :     /* Now done with cmd, delete it from output_buf */
     829 EUB             :     output_buf->len = backtick_start_offset;
     830 UBC           0 :     output_buf->data[output_buf->len] = '\0';
     831 UIC           0 : 
     832 EUB             :     /* If no error, transfer result to output_buf */
     833                 :     if (!error)
     834 UIC           0 :     {
     835                 :         /* strip any trailing newline (but only one) */
     836                 :         if (cmd_output.len > 0 &&
     837 UBC           0 :             cmd_output.data[cmd_output.len - 1] == '\n')
     838 UIC           0 :             cmd_output.len--;
     839 UBC           0 :         appendBinaryPQExpBuffer(output_buf, cmd_output.data, cmd_output.len);
     840               0 :     }
     841                 : 
     842                 :     /* And finally, set the shell result variables */
     843                 :     SetShellResultVariables(exit_code);
     844 UNC           0 : 
     845                 :     termPQExpBuffer(&cmd_output);
     846 UIC           0 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a