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