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