Age Owner 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;
2577 tgl 126 GIC 28389 : PQExpBuffer output_buf = cur_state->output_buf;
127 28389 :
2577 tgl 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);
2577 tgl 136 GIC 28389 : %}
137 :
2577 tgl 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; }
2577 tgl 144 UIC 0 :
145 0 : /*
2577 tgl 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 */
2577 tgl 151 GIC 5179 :
152 : {space}|"\\" {
2577 tgl 153 ECB : yyless(0);
2577 tgl 154 GIC 5179 : cur_state->start_state = YY_START;
155 5179 : return LEXRES_OK;
2577 tgl 156 CBC 5179 : }
2577 tgl 157 ECB :
158 : {other} { ECHO; }
2577 tgl 159 GIC 18069 :
160 18069 : }
2577 tgl 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 : */
2577 tgl 168 GIC 7272 :
169 : {space}+ { }
2577 tgl 170 ECB :
2577 tgl 171 GIC 7272 : "|" {
172 12 : if (option_type == OT_FILEPIPE)
2577 tgl 173 CBC 12 : {
2577 tgl 174 ECB : /* treat like whole-string case */
175 : ECHO;
2577 tgl 176 GIC 3 : BEGIN(xslashwholeline);
177 3 : }
2577 tgl 178 ECB : else
179 : {
180 : /* vertical bar is not special otherwise */
181 : yyless(0);
2577 tgl 182 GIC 9 : BEGIN(xslasharg);
183 9 : }
2577 tgl 184 ECB : }
185 :
2577 tgl 186 GIC 12 : {other} {
187 7322 : yyless(0);
2577 tgl 188 CBC 7322 : BEGIN(xslasharg);
189 7322 : }
2577 tgl 190 ECB :
2577 tgl 191 CBC 7322 : }
192 :
2577 tgl 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 : */
2577 tgl 201 GIC 2403 :
202 : {space}|"\\" {
2577 tgl 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);
2577 tgl 213 GIC 2403 : cur_state->start_state = YY_START;
214 2403 : return LEXRES_OK;
2577 tgl 215 CBC 2403 : }
2577 tgl 216 ECB :
217 : {quote} {
2577 tgl 218 GIC 500 : *option_quote = '\'';
219 500 : unquoted_option_chars = 0;
2577 tgl 220 CBC 500 : BEGIN(xslashquote);
221 500 : }
2577 tgl 222 ECB :
2577 tgl 223 CBC 500 : "`" {
2577 tgl 224 GIC 9 : backtick_start_offset = output_buf->len;
2577 tgl 225 CBC 9 : *option_quote = '`';
226 9 : unquoted_option_chars = 0;
227 9 : BEGIN(xslashbackquote);
228 9 : }
2577 tgl 229 ECB :
2577 tgl 230 CBC 9 : {dquote} {
2577 tgl 231 GIC 744 : ECHO;
2577 tgl 232 CBC 744 : *option_quote = '"';
233 744 : unquoted_option_chars = 0;
234 744 : BEGIN(xslashdquote);
235 744 : }
2577 tgl 236 ECB :
2577 tgl 237 CBC 744 : :{variable_char}+ {
2577 tgl 238 GIC 527 : /* Possible psql variable substitution */
2201 tgl 239 ECB : if (cur_state->callbacks->get_variable == NULL)
2577 tgl 240 CBC 527 : ECHO;
2577 tgl 241 UIC 0 : else
2577 tgl 242 ECB : {
2577 tgl 243 EUB : char *varname;
244 : char *value;
245 :
246 : varname = psqlscan_extract_substring(cur_state,
2577 tgl 247 GIC 527 : yytext + 1,
248 527 : yyleng - 1);
2577 tgl 249 CBC 527 : value = cur_state->callbacks->get_variable(varname,
2199 250 527 : PQUOTE_PLAIN,
2218 tgl 251 ECB : cur_state->cb_passthrough);
2577 252 : free(varname);
2577 tgl 253 GIC 527 :
254 : /*
2577 tgl 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)
2577 tgl 262 GIC 527 : {
263 : appendPQExpBufferStr(output_buf, value);
2577 tgl 264 CBC 509 : free(value);
2577 tgl 265 GIC 509 : }
2577 tgl 266 ECB : else
267 : ECHO;
2577 tgl 268 GIC 18 :
269 : *option_quote = ':';
2577 tgl 270 CBC 527 : }
271 : unquoted_option_chars = 0;
272 527 : }
273 :
274 527 : :'{variable_char}+' {
2199 tgl 275 GIC 23 : psqlscan_escape_variable(cur_state, yytext, yyleng,
2199 tgl 276 CBC 23 : PQUOTE_SQL_LITERAL);
2201 tgl 277 ECB : *option_quote = ':';
2577 tgl 278 CBC 23 : unquoted_option_chars = 0;
2577 tgl 279 GIC 23 : }
2577 tgl 280 ECB :
2577 tgl 281 CBC 23 :
2577 tgl 282 GIC 12 : :\"{variable_char}+\" {
2199 tgl 283 ECB : psqlscan_escape_variable(cur_state, yytext, yyleng,
2199 tgl 284 CBC 12 : PQUOTE_SQL_IDENT);
285 : *option_quote = ':';
2577 286 12 : unquoted_option_chars = 0;
2577 tgl 287 GIC 12 : }
2577 tgl 288 ECB :
2026 andrew 289 CBC 12 : :\{\?{variable_char}+\} {
2026 andrew 290 GIC 6 : psqlscan_test_variable(cur_state, yytext, yyleng);
2026 andrew 291 CBC 6 : }
2026 andrew 292 ECB :
2577 tgl 293 CBC 6 : :'{variable_char}* {
2577 tgl 294 UIC 0 : /* Throw back everything but the colon */
2577 tgl 295 ECB : yyless(1);
2577 tgl 296 UBC 0 : unquoted_option_chars++;
2577 tgl 297 UIC 0 : ECHO;
2577 tgl 298 UBC 0 : }
2577 tgl 299 EUB :
2577 tgl 300 UBC 0 : :\"{variable_char}* {
2577 tgl 301 UIC 0 : /* Throw back everything but the colon */
2577 tgl 302 EUB : yyless(1);
2577 tgl 303 UBC 0 : unquoted_option_chars++;
2577 tgl 304 UIC 0 : ECHO;
2577 tgl 305 UBC 0 : }
2577 tgl 306 EUB :
2026 andrew 307 UBC 0 : :\{\?{variable_char}* {
2026 andrew 308 UIC 0 : /* Throw back everything but the colon */
2026 andrew 309 EUB : yyless(1);
2026 andrew 310 UBC 0 : unquoted_option_chars++;
2026 andrew 311 UIC 0 : ECHO;
2026 andrew 312 UBC 0 : }
2026 andrew 313 EUB :
2026 andrew 314 UBC 0 : :\{ {
2026 andrew 315 UIC 0 : /* Throw back everything but the colon */
2026 andrew 316 EUB : yyless(1);
2026 andrew 317 UBC 0 : unquoted_option_chars++;
2026 andrew 318 UIC 0 : ECHO;
2026 andrew 319 UBC 0 : }
2026 andrew 320 EUB :
2577 tgl 321 UBC 0 : {other} {
2577 tgl 322 GIC 55227 : unquoted_option_chars++;
2577 tgl 323 GBC 55227 : ECHO;
2577 tgl 324 CBC 55227 : }
2577 tgl 325 ECB :
2577 tgl 326 CBC 55227 : }
327 :
2577 tgl 328 ECB : <xslashquote>{
329 : /*
330 : * single-quoted text: copy literally except for '' and backslash
331 : * sequences
332 : */
2577 tgl 333 GIC 500 :
334 : {quote} { BEGIN(xslasharg); }
2577 tgl 335 CBC 500 :
2577 tgl 336 GIC 500 : {xqdouble} { appendPQExpBufferChar(output_buf, '\''); }
2577 tgl 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'); }
2577 tgl 342 LBC 0 : "\\f" { appendPQExpBufferChar(output_buf, '\f'); }
2577 tgl 343 CBC 3 :
2577 tgl 344 UBC 0 : {xeoctesc} {
2577 tgl 345 CBC 3 : /* octal case */
2577 tgl 346 EUB : appendPQExpBufferChar(output_buf,
2577 tgl 347 CBC 3 : (char) strtol(yytext + 1, NULL, 8));
2577 tgl 348 GIC 3 : }
2577 tgl 349 ECB :
2577 tgl 350 CBC 3 : {xehexesc} {
2577 tgl 351 UIC 0 : /* hex case */
2577 tgl 352 ECB : appendPQExpBufferChar(output_buf,
2577 tgl 353 UBC 0 : (char) strtol(yytext + 2, NULL, 16));
2577 tgl 354 UIC 0 : }
2577 tgl 355 EUB :
2577 tgl 356 UBC 0 : "\\". { psqlscan_emit(cur_state, yytext + 1, 1); }
2577 tgl 357 GIC 6 :
2577 tgl 358 GBC 6 : {other}|\n { ECHO; }
2577 tgl 359 CBC 7640 :
360 7640 : }
2577 tgl 361 ECB :
362 : <xslashbackquote>{
363 : /*
364 : * backticked text: copy everything until next backquote (expanding
365 : * variable references, but doing nought else), then evaluate.
366 : */
2577 tgl 367 GIC 9 :
368 : "`" {
2201 tgl 369 ECB : /* In an inactive \if branch, don't evaluate the command */
370 : if (cur_state->cb_passthrough == NULL ||
2201 tgl 371 GIC 18 : conditional_active((ConditionalStack) cur_state->cb_passthrough))
2577 372 9 : evaluate_backtick(cur_state);
2577 tgl 373 LBC 0 : BEGIN(xslasharg);
2577 tgl 374 CBC 9 : }
2577 tgl 375 EUB :
2199 tgl 376 CBC 9 : :{variable_char}+ {
2199 tgl 377 UIC 0 : /* Possible psql variable substitution */
2199 tgl 378 ECB : if (cur_state->callbacks->get_variable == NULL)
2199 tgl 379 UBC 0 : ECHO;
2199 tgl 380 UIC 0 : else
2199 tgl 381 EUB : {
382 : char *varname;
383 : char *value;
384 :
385 : varname = psqlscan_extract_substring(cur_state,
2199 tgl 386 UIC 0 : yytext + 1,
387 0 : yyleng - 1);
2199 tgl 388 UBC 0 : value = cur_state->callbacks->get_variable(varname,
389 0 : PQUOTE_PLAIN,
2199 tgl 390 EUB : cur_state->cb_passthrough);
391 : free(varname);
2199 tgl 392 UIC 0 :
393 : if (value)
2199 tgl 394 UBC 0 : {
395 : appendPQExpBufferStr(output_buf, value);
396 0 : free(value);
2199 tgl 397 UIC 0 : }
2199 tgl 398 EUB : else
399 : ECHO;
2199 tgl 400 UIC 0 : }
401 : }
2199 tgl 402 EUB :
2199 tgl 403 UIC 0 : :'{variable_char}+' {
404 0 : psqlscan_escape_variable(cur_state, yytext, yyleng,
2199 tgl 405 UBC 0 : PQUOTE_SHELL_ARG);
2199 tgl 406 EUB : }
407 :
2199 tgl 408 UIC 0 : :'{variable_char}* {
409 0 : /* Throw back everything but the colon */
2199 tgl 410 EUB : yyless(1);
2199 tgl 411 UBC 0 : ECHO;
2199 tgl 412 UIC 0 : }
2199 tgl 413 EUB :
2577 tgl 414 UBC 0 : {other}|\n { ECHO; }
2577 tgl 415 GIC 117 :
2577 tgl 416 GBC 117 : }
2577 tgl 417 ECB :
418 : <xslashdquote>{
419 : /* double-quoted text: copy verbatim, including the double quotes */
2577 tgl 420 GIC 744 :
421 : {dquote} {
2577 tgl 422 ECB : ECHO;
2577 tgl 423 GIC 744 : BEGIN(xslasharg);
424 744 : }
2577 tgl 425 ECB :
2577 tgl 426 CBC 744 : {other}|\n { ECHO; }
2577 tgl 427 GIC 13584 :
2577 tgl 428 CBC 13584 : }
2577 tgl 429 ECB :
430 : <xslashwholeline>{
431 : /* copy everything until end of input line */
432 : /* but suppress leading whitespace */
2577 tgl 433 GIC 497 :
434 : {space}+ {
2577 tgl 435 ECB : if (output_buf->len > 0)
2577 tgl 436 GIC 497 : ECHO;
437 347 : }
2577 tgl 438 ECB :
2577 tgl 439 CBC 497 : {other} { ECHO; }
2577 tgl 440 GIC 4420 :
2577 tgl 441 CBC 4420 : }
2577 tgl 442 ECB :
443 : <xslashend>{
444 : /* at end of command, eat a double backslash, but not anything else */
2577 tgl 445 GIC 35 :
446 : "\\\\" {
2577 tgl 447 ECB : cur_state->start_state = YY_START;
2577 tgl 448 GIC 35 : return LEXRES_OK;
449 35 : }
2577 tgl 450 ECB :
451 : {other}|\n {
2577 tgl 452 GIC 63 : yyless(0);
453 63 : cur_state->start_state = YY_START;
2577 tgl 454 CBC 63 : return LEXRES_OK;
455 63 : }
2577 tgl 456 ECB :
457 : }
458 :
2577 tgl 459 GIC 20709 : <<EOF>> {
460 : if (cur_state->buffer_stack == NULL)
2577 tgl 461 CBC 20709 : {
462 : cur_state->start_state = YY_START;
463 20709 : return LEXRES_EOL; /* end of input reached */
2577 tgl 464 GIC 20709 : }
2577 tgl 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);
2577 tgl 471 UIC 0 : psqlscan_select_top_buffer(cur_state);
472 0 : }
2577 tgl 473 EUB :
2577 tgl 474 UBC 0 : %%
2577 tgl 475 UIC 0 :
2068 peter_e 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)
2577 tgl 488 GIC 6183 : {
489 : PQExpBufferData mybuf;
2577 tgl 490 ECB :
491 : /* Must be scanning already */
492 : Assert(state->scanbufhandle != NULL);
2577 tgl 493 GIC 6183 :
494 : /* Build a local buffer that we'll return the data of */
2577 tgl 495 ECB : initPQExpBuffer(&mybuf);
2577 tgl 496 GIC 6183 :
497 : /* Set current output target */
2577 tgl 498 ECB : state->output_buf = &mybuf;
2577 tgl 499 GIC 6183 :
500 : /* Set input source */
2577 tgl 501 ECB : if (state->buffer_stack != NULL)
2577 tgl 502 GIC 6183 : yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
2577 tgl 503 UIC 0 : else
2577 tgl 504 ECB : yy_switch_to_buffer(state->scanbufhandle, state->scanner);
2577 tgl 505 GBC 6183 :
506 : /*
2577 tgl 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;
2577 tgl 511 GIC 6183 :
512 : /* And lex. */
2576 tgl 513 ECB : yylex(NULL, state->scanner);
2577 tgl 514 GIC 6183 :
515 : /* There are no possible errors in this lex state... */
2577 tgl 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);
2577 tgl 522 GIC 6183 :
523 : return mybuf.data;
2577 tgl 524 CBC 6183 : }
525 :
2577 tgl 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,
2577 tgl 547 GIC 16023 : enum slash_option_type type,
548 : char *quote,
2577 tgl 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);
2577 tgl 558 GIC 16023 :
559 : if (quote == NULL)
2577 tgl 560 CBC 16023 : quote = &local_quote;
2577 tgl 561 GIC 14577 : *quote = 0;
2577 tgl 562 CBC 16023 :
2577 tgl 563 ECB : /* Build a local buffer that we'll return the data of */
564 : initPQExpBuffer(&mybuf);
2577 tgl 565 GIC 16023 :
566 : /* Set up static variables that will be used by yylex */
2577 tgl 567 ECB : option_type = type;
2577 tgl 568 GIC 16023 : option_quote = quote;
569 16023 : unquoted_option_chars = 0;
2577 tgl 570 CBC 16023 :
2577 tgl 571 ECB : /* Set current output target */
572 : state->output_buf = &mybuf;
2577 tgl 573 GIC 16023 :
574 : /* Set input source */
2577 tgl 575 ECB : if (state->buffer_stack != NULL)
2577 tgl 576 GIC 16023 : yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
2577 tgl 577 UIC 0 : else
2577 tgl 578 ECB : yy_switch_to_buffer(state->scanbufhandle, state->scanner);
2577 tgl 579 GBC 16023 :
580 : /* Set lexer start state */
2577 tgl 581 ECB : if (type == OT_WHOLE_LINE)
2577 tgl 582 GIC 16023 : state->start_state = xslashwholeline;
583 682 : else
2577 tgl 584 ECB : state->start_state = xslashargstart;
2577 tgl 585 CBC 15341 :
586 : /* And lex. */
2576 tgl 587 ECB : lexresult = yylex(NULL, state->scanner);
2577 tgl 588 GIC 16023 :
589 : /* Save final state for a moment... */
2577 tgl 590 ECB : final_state = state->start_state;
2577 tgl 591 GIC 16023 :
592 : /*
2577 tgl 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);
2577 tgl 597 GIC 16023 :
598 : /*
2577 tgl 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);
2577 tgl 604 GIC 16023 :
605 : switch (final_state)
2577 tgl 606 CBC 16023 : {
607 : case xslashargstart:
608 8007 : /* empty arg */
609 : break;
610 8007 : case xslasharg:
2577 tgl 611 GIC 7331 : /* Strip any unquoted trailing semi-colons if requested */
2577 tgl 612 ECB : if (semicolon)
2577 tgl 613 CBC 7331 : {
614 : while (unquoted_option_chars-- > 0 &&
615 3105 : mybuf.len > 0 &&
2577 tgl 616 GIC 3108 : mybuf.data[mybuf.len - 1] == ';')
2577 tgl 617 CBC 2684 : {
2577 tgl 618 ECB : mybuf.data[--mybuf.len] = '\0';
2577 tgl 619 CBC 3 : }
620 : }
2577 tgl 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)
2577 tgl 627 GIC 7331 : {
628 : dequote_downcase_identifier(mybuf.data,
2548 tgl 629 CBC 128 : (type != OT_SQLIDHACK),
630 : state->encoding);
2548 tgl 631 ECB : /* update mybuf.len for possible shortening */
632 : mybuf.len = strlen(mybuf.data);
2577 tgl 633 GIC 128 : }
634 : break;
2577 tgl 635 CBC 7331 : case xslashquote:
2577 tgl 636 UIC 0 : case xslashbackquote:
2577 tgl 637 ECB : case xslashdquote:
2577 tgl 638 EUB : /* must have hit EOL inside quotes */
639 : pg_log_error("unterminated quoted string");
2577 tgl 640 UIC 0 : termPQExpBuffer(&mybuf);
641 0 : return NULL;
2577 tgl 642 UBC 0 : case xslashwholeline:
2577 tgl 643 GBC 685 : /* always okay */
2577 tgl 644 EUB : break;
2577 tgl 645 CBC 685 : default:
2577 tgl 646 UIC 0 : /* can't get here */
2577 tgl 647 ECB : fprintf(stderr, "invalid YY_START\n");
2577 tgl 648 UBC 0 : exit(1);
2577 tgl 649 UIC 0 : }
2577 tgl 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)
2577 tgl 656 GIC 16023 : {
657 : termPQExpBuffer(&mybuf);
2577 tgl 658 CBC 8681 : return NULL;
2577 tgl 659 GIC 8681 : }
2577 tgl 660 ECB :
661 : /* Else return the completed string. */
662 : return mybuf.data;
2577 tgl 663 GIC 7342 : }
664 :
2577 tgl 665 ECB : /*
666 : * Eat up any unused \\ to complete a backslash command.
667 : */
668 : void
669 : psql_scan_slash_command_end(PsqlScanState state)
2577 tgl 670 GIC 6183 : {
671 : /* Must be scanning already */
2577 tgl 672 ECB : Assert(state->scanbufhandle != NULL);
2577 tgl 673 GIC 6183 :
674 : /* Set current output target */
2577 tgl 675 ECB : state->output_buf = NULL; /* we won't output anything */
2577 tgl 676 GIC 6183 :
677 : /* Set input source */
2577 tgl 678 ECB : if (state->buffer_stack != NULL)
2577 tgl 679 GIC 6183 : yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
2577 tgl 680 UIC 0 : else
2577 tgl 681 ECB : yy_switch_to_buffer(state->scanbufhandle, state->scanner);
2577 tgl 682 GBC 6183 :
683 : /* Set lexer start state */
2577 tgl 684 ECB : state->start_state = xslashend;
2577 tgl 685 GIC 6183 :
686 : /* And lex. */
2576 tgl 687 ECB : yylex(NULL, state->scanner);
2577 tgl 688 GIC 6183 :
689 : /* There are no possible errors in this lex state... */
2577 tgl 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);
2577 tgl 696 GIC 6183 : }
697 6183 :
2201 tgl 698 ECB : /*
699 : * Fetch current paren nesting depth
700 : */
701 : int
702 : psql_scan_get_paren_depth(PsqlScanState state)
2201 tgl 703 GIC 114 : {
704 : return state->paren_depth;
2201 tgl 705 CBC 114 : }
706 :
2201 tgl 707 ECB : /*
708 : * Set paren nesting depth
709 : */
710 : void
711 : psql_scan_set_paren_depth(PsqlScanState state, int depth)
2201 tgl 712 GIC 98 : {
713 : Assert(depth >= 0);
2201 tgl 714 CBC 98 : state->paren_depth = depth;
2201 tgl 715 GIC 98 : }
2201 tgl 716 CBC 98 :
2548 tgl 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)
2548 tgl 735 GIC 224 : {
736 : bool inquotes = false;
2548 tgl 737 CBC 224 : char *cp = str;
2548 tgl 738 GIC 224 :
2548 tgl 739 ECB : while (*cp)
2548 tgl 740 CBC 1539 : {
741 : if (*cp == '"')
742 1315 : {
743 : if (inquotes && cp[1] == '"')
744 62 : {
745 : /* Keep the first quote, remove the second */
2548 tgl 746 ECB : cp++;
2548 tgl 747 GIC 10 : }
748 : else
2435 noah 749 ECB : inquotes = !inquotes;
2548 tgl 750 GIC 52 : /* Collapse out quote at *cp */
751 : memmove(cp, cp + 1, strlen(cp));
2548 tgl 752 CBC 62 : /* do not advance cp */
753 : }
2548 tgl 754 ECB : else
755 : {
756 : if (downcase && !inquotes)
2548 tgl 757 GIC 1253 : *cp = pg_tolower((unsigned char) *cp);
671 758 138 : cp += PQmblenBounded(cp, encoding);
2548 tgl 759 CBC 1253 : }
2548 tgl 760 ECB : }
761 : }
2548 tgl 762 GIC 224 :
763 : /*
2577 tgl 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)
2577 tgl 771 UIC 0 : {
772 : PQExpBuffer output_buf = state->output_buf;
2577 tgl 773 UBC 0 : char *cmd = output_buf->data + backtick_start_offset;
2577 tgl 774 UIC 0 : PQExpBufferData cmd_output;
2577 tgl 775 EUB : FILE *fd;
776 : bool error = false;
19 tgl 777 UNC 0 : int exit_code = 0;
2577 tgl 778 UIC 0 : char buf[512];
779 : size_t result;
2577 tgl 780 EUB :
781 : initPQExpBuffer(&cmd_output);
2577 tgl 782 UIC 0 :
783 : fflush(NULL);
893 784 0 : fd = popen(cmd, "r");
2577 785 0 : if (!fd)
2577 tgl 786 UBC 0 : {
787 : pg_log_error("%s: %m", cmd);
788 0 : error = true;
19 tgl 789 UNC 0 : exit_code = -1;
2577 tgl 790 UBC 0 : }
2577 tgl 791 EUB :
792 : if (!error)
2577 tgl 793 UBC 0 : {
2577 tgl 794 EUB : do
795 : {
796 : result = fread(buf, 1, sizeof(buf), fd);
2577 tgl 797 UIC 0 : if (ferror(fd))
2577 tgl 798 UBC 0 : {
799 : pg_log_error("%s: %m", cmd);
2577 tgl 800 UIC 0 : error = true;
801 0 : break;
2577 tgl 802 UBC 0 : }
2577 tgl 803 EUB : appendBinaryPQExpBuffer(&cmd_output, buf, result);
2577 tgl 804 UIC 0 : } while (!feof(fd));
2577 tgl 805 UBC 0 : }
2577 tgl 806 EUB :
807 : if (fd)
2577 tgl 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);
19 tgl 815 UNC 0 : if (exit_code == -1)
816 0 : {
817 : pg_log_error("%s: %m", cmd);
818 0 : error = true;
819 0 : }
820 : }
821 :
2577 tgl 822 EUB : if (PQExpBufferDataBroken(cmd_output))
2577 tgl 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 */
2577 tgl 829 EUB : output_buf->len = backtick_start_offset;
2577 tgl 830 UBC 0 : output_buf->data[output_buf->len] = '\0';
2577 tgl 831 UIC 0 :
2577 tgl 832 EUB : /* If no error, transfer result to output_buf */
833 : if (!error)
2577 tgl 834 UIC 0 : {
835 : /* strip any trailing newline (but only one) */
836 : if (cmd_output.len > 0 &&
2577 tgl 837 UBC 0 : cmd_output.data[cmd_output.len - 1] == '\n')
2577 tgl 838 UIC 0 : cmd_output.len--;
2577 tgl 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);
19 tgl 844 UNC 0 :
845 : termPQExpBuffer(&cmd_output);
2577 tgl 846 UIC 0 : }
|