Branch data Line data Source code
1 : : /*
2 : : * psql - the PostgreSQL interactive terminal
3 : : *
4 : : * Copyright (c) 2000-2026, PostgreSQL Global Development Group
5 : : *
6 : : * src/bin/psql/common.c
7 : : */
8 : : #include "postgres_fe.h"
9 : :
10 : : #include <ctype.h>
11 : : #include <limits.h>
12 : : #include <math.h>
13 : : #include <pwd.h>
14 : : #include <signal.h>
15 : : #ifndef WIN32
16 : : #include <unistd.h> /* for write() */
17 : : #else
18 : : #include <io.h> /* for _write() */
19 : : #include <win32.h>
20 : : #endif
21 : :
22 : : #include "command.h"
23 : : #include "common.h"
24 : : #include "common/logging.h"
25 : : #include "copy.h"
26 : : #include "crosstabview.h"
27 : : #include "fe_utils/cancel.h"
28 : : #include "fe_utils/mbprint.h"
29 : : #include "fe_utils/string_utils.h"
30 : : #include "mainloop.h"
31 : : #include "mb/pg_wchar.h"
32 : : #include "portability/instr_time.h"
33 : : #include "settings.h"
34 : :
35 : : static bool DescribeQuery(const char *query, double *elapsed_msec);
36 : : static int ExecQueryAndProcessResults(const char *query,
37 : : double *elapsed_msec,
38 : : bool *svpt_gone_p,
39 : : int num_copy_from_stdin,
40 : : bool is_watch,
41 : : int min_rows,
42 : : const printQueryOpt *opt,
43 : : FILE *printQueryFout);
44 : : static bool command_no_begin(const char *query);
45 : :
46 : :
47 : : /*
48 : : * openQueryOutputFile --- attempt to open a query output file
49 : : *
50 : : * fname == NULL selects stdout, else an initial '|' selects a pipe,
51 : : * else plain file.
52 : : *
53 : : * Returns output file pointer into *fout, and is-a-pipe flag into *is_pipe.
54 : : * Caller is responsible for adjusting SIGPIPE state if it's a pipe.
55 : : *
56 : : * On error, reports suitable error message and returns false.
57 : : */
58 : : bool
59 : 11257 : openQueryOutputFile(const char *fname, FILE **fout, bool *is_pipe)
60 : : {
61 [ + + - + ]: 11257 : if (!fname || fname[0] == '\0')
62 : : {
63 : 11225 : *fout = stdout;
64 : 11225 : *is_pipe = false;
65 : : }
66 [ + + ]: 32 : else if (*fname == '|')
67 : : {
68 : 4 : fflush(NULL);
69 : 4 : *fout = popen(fname + 1, "w");
70 : 4 : *is_pipe = true;
71 : : }
72 : : else
73 : : {
74 : 28 : *fout = fopen(fname, "w");
75 : 28 : *is_pipe = false;
76 : : }
77 : :
78 [ - + ]: 11257 : if (*fout == NULL)
79 : : {
80 : 0 : pg_log_error("%s: %m", fname);
81 : 0 : return false;
82 : : }
83 : :
84 : 11257 : return true;
85 : : }
86 : :
87 : : /*
88 : : * Check if an output stream for \g needs to be opened, and if yes,
89 : : * open it and update the caller's gfile_fout and is_pipe state variables.
90 : : * Return true if OK, false if an error occurred.
91 : : */
92 : : static bool
93 : 97835 : SetupGOutput(FILE **gfile_fout, bool *is_pipe)
94 : : {
95 : : /* If there is a \g file or program, and it's not already open, open it */
96 [ + + + + ]: 97835 : if (pset.gfname != NULL && *gfile_fout == NULL)
97 : : {
98 [ + - ]: 20 : if (openQueryOutputFile(pset.gfname, gfile_fout, is_pipe))
99 : : {
100 [ + + ]: 20 : if (*is_pipe)
101 : 4 : disable_sigpipe_trap();
102 : : }
103 : : else
104 : 0 : return false;
105 : : }
106 : 97835 : return true;
107 : : }
108 : :
109 : : /*
110 : : * Close the output stream for \g, if we opened it.
111 : : */
112 : : static void
113 : 260154 : CloseGOutput(FILE *gfile_fout, bool is_pipe)
114 : : {
115 [ + + ]: 260154 : if (gfile_fout)
116 : : {
117 [ + + ]: 20 : if (is_pipe)
118 : : {
119 : 4 : SetShellResultVariables(pclose(gfile_fout));
120 : 4 : restore_sigpipe_trap();
121 : : }
122 : : else
123 : 16 : fclose(gfile_fout);
124 : : }
125 : 260154 : }
126 : :
127 : : /*
128 : : * Reset pset pipeline state
129 : : */
130 : : static void
131 : 0 : pipelineReset(void)
132 : : {
133 : 0 : pset.piped_syncs = 0;
134 : 0 : pset.piped_commands = 0;
135 : 0 : pset.available_results = 0;
136 : 0 : pset.requested_results = 0;
137 : 0 : }
138 : :
139 : : /*
140 : : * setQFout
141 : : * -- handler for -o command line option and \o command
142 : : *
143 : : * On success, updates pset with the new output file and returns true.
144 : : * On failure, returns false without changing pset state.
145 : : */
146 : : bool
147 : 11237 : setQFout(const char *fname)
148 : : {
149 : : FILE *fout;
150 : : bool is_pipe;
151 : :
152 : : /* First make sure we can open the new output file/pipe */
153 [ - + ]: 11237 : if (!openQueryOutputFile(fname, &fout, &is_pipe))
154 : 0 : return false;
155 : :
156 : : /* Close old file/pipe */
157 [ + - + + : 11237 : if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
+ - ]
158 : : {
159 [ - + ]: 12 : if (pset.queryFoutPipe)
160 : 0 : SetShellResultVariables(pclose(pset.queryFout));
161 : : else
162 : 12 : fclose(pset.queryFout);
163 : : }
164 : :
165 : 11237 : pset.queryFout = fout;
166 : 11237 : pset.queryFoutPipe = is_pipe;
167 : :
168 : : /* Adjust SIGPIPE handling appropriately: ignore signal if is_pipe */
169 : 11237 : set_sigpipe_trap_state(is_pipe);
170 : 11237 : restore_sigpipe_trap();
171 : :
172 : 11237 : return true;
173 : : }
174 : :
175 : :
176 : : /*
177 : : * Variable-fetching callback for flex lexer
178 : : *
179 : : * If the specified variable exists, return its value as a string (malloc'd
180 : : * and expected to be freed by the caller); else return NULL.
181 : : *
182 : : * If "quote" isn't PQUOTE_PLAIN, then return the value suitably quoted and
183 : : * escaped for the specified quoting requirement. (Failure in escaping
184 : : * should lead to printing an error and returning NULL.)
185 : : *
186 : : * "passthrough" is the pointer previously given to psql_scan_set_passthrough.
187 : : * In psql, passthrough points to a ConditionalStack, which we check to
188 : : * determine whether variable expansion is allowed.
189 : : */
190 : : char *
191 : 2963 : psql_get_variable(const char *varname, PsqlScanQuoteType quote,
192 : : void *passthrough)
193 : : {
194 : 2963 : char *result = NULL;
195 : : const char *value;
196 : :
197 : : /* In an inactive \if branch, suppress all variable substitutions */
198 [ + - + + ]: 2963 : if (passthrough && !conditional_active((ConditionalStack) passthrough))
199 : 48 : return NULL;
200 : :
201 : 2915 : value = GetVariable(pset.vars, varname);
202 [ + + ]: 2915 : if (!value)
203 : 333 : return NULL;
204 : :
205 [ + + - - ]: 2582 : switch (quote)
206 : : {
207 : 1858 : case PQUOTE_PLAIN:
208 : 1858 : result = pg_strdup(value);
209 : 1858 : break;
210 : 724 : case PQUOTE_SQL_LITERAL:
211 : : case PQUOTE_SQL_IDENT:
212 : : {
213 : : /*
214 : : * For these cases, we use libpq's quoting functions, which
215 : : * assume the string is in the connection's client encoding.
216 : : */
217 : : char *escaped_value;
218 : :
219 [ - + ]: 724 : if (!pset.db)
220 : : {
221 : 0 : pg_log_error("cannot escape without active connection");
222 : 0 : return NULL;
223 : : }
224 : :
225 [ + + ]: 724 : if (quote == PQUOTE_SQL_LITERAL)
226 : : escaped_value =
227 : 703 : PQescapeLiteral(pset.db, value, strlen(value));
228 : : else
229 : : escaped_value =
230 : 21 : PQescapeIdentifier(pset.db, value, strlen(value));
231 : :
232 [ - + ]: 724 : if (escaped_value == NULL)
233 : : {
234 : 0 : const char *error = PQerrorMessage(pset.db);
235 : :
236 : 0 : pg_log_info("%s", error);
237 : 0 : return NULL;
238 : : }
239 : :
240 : : /*
241 : : * Rather than complicate the lexer's API with a notion of
242 : : * which free() routine to use, just pay the price of an extra
243 : : * strdup().
244 : : */
245 : 724 : result = pg_strdup(escaped_value);
246 : 724 : PQfreemem(escaped_value);
247 : 724 : break;
248 : : }
249 : 0 : case PQUOTE_SHELL_ARG:
250 : : {
251 : : /*
252 : : * For this we use appendShellStringNoError, which is
253 : : * encoding-agnostic, which is fine since the shell probably
254 : : * is too. In any case, the only special character is "'",
255 : : * which is not known to appear in valid multibyte characters.
256 : : */
257 : : PQExpBufferData buf;
258 : :
259 : 0 : initPQExpBuffer(&buf);
260 [ # # ]: 0 : if (!appendShellStringNoError(&buf, value))
261 : : {
262 : 0 : pg_log_error("shell command argument contains a newline or carriage return: \"%s\"",
263 : : value);
264 : 0 : free(buf.data);
265 : 0 : return NULL;
266 : : }
267 : 0 : result = buf.data;
268 : 0 : break;
269 : : }
270 : :
271 : : /* No default: we want a compiler warning for missing cases */
272 : : }
273 : :
274 : 2582 : return result;
275 : : }
276 : :
277 : :
278 : : /*
279 : : * for backend Notice messages (INFO, WARNING, etc)
280 : : */
281 : : void
282 : 184296 : NoticeProcessor(void *arg, const char *message)
283 : : {
284 : : (void) arg; /* not used */
285 : 184296 : pg_log_info("%s", message);
286 : 184296 : }
287 : :
288 : :
289 : :
290 : : /*
291 : : * Code to support query cancellation
292 : : *
293 : : * Before we start a query, we enable the SIGINT signal catcher to send a
294 : : * cancel request to the backend.
295 : : *
296 : : * SIGINT is supposed to abort all long-running psql operations, not only
297 : : * database queries. In most places, this is accomplished by checking
298 : : * cancel_pressed during long-running loops. However, that won't work when
299 : : * blocked on user input (in readline() or fgets()). In those places, we
300 : : * set sigint_interrupt_enabled true while blocked, instructing the signal
301 : : * catcher to longjmp through sigint_interrupt_jmp. We assume readline and
302 : : * fgets are coded to handle possible interruption.
303 : : *
304 : : * On Windows, currently this does not work, so control-C is less useful
305 : : * there.
306 : : */
307 : : volatile sig_atomic_t sigint_interrupt_enabled = false;
308 : :
309 : : sigjmp_buf sigint_interrupt_jmp;
310 : :
311 : : static void
312 : 1 : psql_cancel_callback(void)
313 : : {
314 : : /*
315 : : * Set this before the longjmp below, so that a non-interactive script
316 : : * also stops when Ctrl+C is pressed while psql is waiting for COPY data
317 : : * or \prompt input, just like it does when a query is running.
318 : : */
319 : 1 : cancel_pressed = true;
320 : :
321 : : #ifndef WIN32
322 : : /* if we are waiting for input, longjmp out of it */
323 [ - + ]: 1 : if (sigint_interrupt_enabled)
324 : : {
325 : 0 : sigint_interrupt_enabled = false;
326 : 0 : siglongjmp(sigint_interrupt_jmp, 1);
327 : : }
328 : : #endif
329 : 1 : }
330 : :
331 : : void
332 : 11229 : psql_setup_cancel_handler(void)
333 : : {
334 : 11229 : setup_cancel_handler(psql_cancel_callback);
335 : 11229 : }
336 : :
337 : :
338 : : /*
339 : : * ConnectionUp
340 : : *
341 : : * Returns whether our backend connection is still there.
342 : : */
343 : : static bool
344 : 291414 : ConnectionUp(void)
345 : : {
346 : 291414 : return PQstatus(pset.db) != CONNECTION_BAD;
347 : : }
348 : :
349 : :
350 : :
351 : : /*
352 : : * CheckConnection
353 : : *
354 : : * Verify that we still have a good connection to the backend, and if not,
355 : : * see if it can be restored.
356 : : *
357 : : * Returns true if either the connection was still there, or it could be
358 : : * restored successfully; false otherwise. If, however, there was no
359 : : * connection and the session is non-interactive, this will exit the program
360 : : * with a code of EXIT_BADCONN.
361 : : */
362 : : static bool
363 : 291234 : CheckConnection(void)
364 : : {
365 : : bool OK;
366 : :
367 : 291234 : OK = ConnectionUp();
368 [ + + ]: 291234 : if (!OK)
369 : : {
370 [ + - ]: 12 : if (!pset.cur_cmd_interactive)
371 : : {
372 : 12 : pg_log_error("connection to server was lost");
373 : 12 : exit(EXIT_BADCONN);
374 : : }
375 : :
376 : 0 : fprintf(stderr, _("The connection to the server was lost. Attempting reset: "));
377 : 0 : PQreset(pset.db);
378 : 0 : pipelineReset();
379 : 0 : OK = ConnectionUp();
380 [ # # ]: 0 : if (!OK)
381 : : {
382 : 0 : fprintf(stderr, _("Failed.\n"));
383 : :
384 : : /*
385 : : * Transition to having no connection; but stash away the failed
386 : : * connection so that we can still refer to its parameters in a
387 : : * later \connect attempt. Keep the state cleanup here in sync
388 : : * with do_connect().
389 : : */
390 [ # # ]: 0 : if (pset.dead_conn)
391 : 0 : PQfinish(pset.dead_conn);
392 : 0 : pset.dead_conn = pset.db;
393 : 0 : pset.db = NULL;
394 : 0 : ResetCancelConn();
395 : 0 : UnsyncVariables();
396 : : }
397 : : else
398 : : {
399 : 0 : fprintf(stderr, _("Succeeded.\n"));
400 : :
401 : : /*
402 : : * Re-sync, just in case anything changed. Keep this in sync with
403 : : * do_connect().
404 : : */
405 : 0 : SyncVariables();
406 : 0 : connection_warnings(false); /* Must be after SyncVariables */
407 : : }
408 : : }
409 : :
410 : 291222 : return OK;
411 : : }
412 : :
413 : :
414 : :
415 : :
416 : : /*
417 : : * AcceptResult
418 : : *
419 : : * Checks whether a result is valid, giving an error message if necessary;
420 : : * and ensures that the connection to the backend is still up.
421 : : *
422 : : * Returns true for valid result, false for error state.
423 : : */
424 : : static bool
425 : 292523 : AcceptResult(const PGresult *result, bool show_error)
426 : : {
427 : : bool OK;
428 : :
429 [ - + ]: 292523 : if (!result)
430 : 0 : OK = false;
431 : : else
432 [ + + + ]: 292523 : switch (PQresultStatus(result))
433 : : {
434 : 261475 : case PGRES_COMMAND_OK:
435 : : case PGRES_TUPLES_OK:
436 : : case PGRES_TUPLES_CHUNK:
437 : : case PGRES_EMPTY_QUERY:
438 : : case PGRES_COPY_IN:
439 : : case PGRES_COPY_OUT:
440 : : case PGRES_PIPELINE_SYNC:
441 : : /* Fine, do nothing */
442 : 261475 : OK = true;
443 : 261475 : break;
444 : :
445 : 31047 : case PGRES_PIPELINE_ABORTED:
446 : : case PGRES_BAD_RESPONSE:
447 : : case PGRES_NONFATAL_ERROR:
448 : : case PGRES_FATAL_ERROR:
449 : 31047 : OK = false;
450 : 31047 : break;
451 : :
452 : 1 : default:
453 : 1 : OK = false;
454 : 1 : pg_log_error("unexpected PQresultStatus: %d",
455 : : PQresultStatus(result));
456 : 1 : break;
457 : : }
458 : :
459 [ + + + + ]: 292523 : if (!OK && show_error)
460 : : {
461 : 4 : const char *error = PQerrorMessage(pset.db);
462 : :
463 [ + - ]: 4 : if (strlen(error))
464 : 4 : pg_log_info("%s", error);
465 : :
466 : 4 : CheckConnection();
467 : : }
468 : :
469 : 292523 : return OK;
470 : : }
471 : :
472 : :
473 : : /*
474 : : * Set special variables from a query result
475 : : * - ERROR: true/false, whether an error occurred on this query
476 : : * - SQLSTATE: code of error, or "00000" if no error, or "" if unknown
477 : : * - ROW_COUNT: how many rows were returned or affected, or "0"
478 : : * - LAST_ERROR_SQLSTATE: same for last error
479 : : * - LAST_ERROR_MESSAGE: message of last error
480 : : *
481 : : * Note: current policy is to apply this only to the results of queries
482 : : * entered by the user, not queries generated by slash commands.
483 : : */
484 : : static void
485 : 260102 : SetResultVariables(PGresult *result, bool success)
486 : : {
487 [ + + ]: 260102 : if (success)
488 : : {
489 : 228804 : const char *ntuples = PQcmdTuples(result);
490 : :
491 : 228804 : SetVariable(pset.vars, "ERROR", "false");
492 : 228804 : SetVariable(pset.vars, "SQLSTATE", "00000");
493 [ + + ]: 228804 : SetVariable(pset.vars, "ROW_COUNT", *ntuples ? ntuples : "0");
494 : : }
495 : : else
496 : : {
497 : 31298 : const char *code = PQresultErrorField(result, PG_DIAG_SQLSTATE);
498 : 31298 : const char *mesg = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
499 : :
500 : 31298 : SetVariable(pset.vars, "ERROR", "true");
501 : :
502 : : /*
503 : : * If there is no SQLSTATE code, use an empty string. This can happen
504 : : * for libpq-detected errors (e.g., lost connection, ENOMEM).
505 : : */
506 [ + + ]: 31298 : if (code == NULL)
507 : 106 : code = "";
508 : 31298 : SetVariable(pset.vars, "SQLSTATE", code);
509 : 31298 : SetVariable(pset.vars, "ROW_COUNT", "0");
510 : 31298 : SetVariable(pset.vars, "LAST_ERROR_SQLSTATE", code);
511 [ + + ]: 31298 : SetVariable(pset.vars, "LAST_ERROR_MESSAGE", mesg ? mesg : "");
512 : : }
513 : 260102 : }
514 : :
515 : :
516 : : /*
517 : : * Set special variables from a shell command result
518 : : * - SHELL_ERROR: true/false, whether command returned exit code 0
519 : : * - SHELL_EXIT_CODE: exit code according to shell conventions
520 : : *
521 : : * The argument is a wait status as returned by wait(2) or waitpid(2),
522 : : * which also applies to pclose(3) and system(3).
523 : : */
524 : : void
525 : 4 : SetShellResultVariables(int wait_result)
526 : : {
527 : : char buf[32];
528 : :
529 [ + - ]: 4 : SetVariable(pset.vars, "SHELL_ERROR",
530 : : (wait_result == 0) ? "false" : "true");
531 : 4 : snprintf(buf, sizeof(buf), "%d", wait_result_to_exit_code(wait_result));
532 : 4 : SetVariable(pset.vars, "SHELL_EXIT_CODE", buf);
533 : 4 : }
534 : :
535 : :
536 : : /*
537 : : * Set special pipeline variables
538 : : * - PIPELINE_SYNC_COUNT: The number of piped syncs
539 : : * - PIPELINE_COMMAND_COUNT: The number of piped commands
540 : : * - PIPELINE_RESULT_COUNT: The number of results available to read
541 : : */
542 : : static void
543 : 261147 : SetPipelineVariables(void)
544 : : {
545 : : char buf[32];
546 : :
547 : 261147 : snprintf(buf, sizeof(buf), "%d", pset.piped_syncs);
548 : 261147 : SetVariable(pset.vars, "PIPELINE_SYNC_COUNT", buf);
549 : 261147 : snprintf(buf, sizeof(buf), "%d", pset.piped_commands);
550 : 261147 : SetVariable(pset.vars, "PIPELINE_COMMAND_COUNT", buf);
551 : 261147 : snprintf(buf, sizeof(buf), "%d", pset.available_results);
552 : 261147 : SetVariable(pset.vars, "PIPELINE_RESULT_COUNT", buf);
553 : 261147 : }
554 : :
555 : :
556 : : /*
557 : : * ClearOrSaveResult
558 : : *
559 : : * If the result represents an error, remember it for possible display by
560 : : * \errverbose. Otherwise, just PQclear() it.
561 : : *
562 : : * Note: current policy is to apply this to the results of all queries,
563 : : * including "back door" queries, for debugging's sake. It's OK to use
564 : : * PQclear() directly on results known to not be error results, however.
565 : : */
566 : : static void
567 : 261993 : ClearOrSaveResult(PGresult *result)
568 : : {
569 [ + + ]: 261993 : if (result)
570 : : {
571 [ + + ]: 261457 : switch (PQresultStatus(result))
572 : : {
573 : 31197 : case PGRES_NONFATAL_ERROR:
574 : : case PGRES_FATAL_ERROR:
575 : 31197 : PQclear(pset.last_error_result);
576 : 31197 : pset.last_error_result = result;
577 : 31197 : break;
578 : :
579 : 230260 : default:
580 : 230260 : PQclear(result);
581 : 230260 : break;
582 : : }
583 : : }
584 : 261993 : }
585 : :
586 : :
587 : : /*
588 : : * Consume all results
589 : : */
590 : : static void
591 : 0 : ClearOrSaveAllResults(void)
592 : : {
593 : : PGresult *result;
594 : :
595 [ # # ]: 0 : while ((result = PQgetResult(pset.db)) != NULL)
596 : 0 : ClearOrSaveResult(result);
597 : 0 : }
598 : :
599 : :
600 : : /*
601 : : * Print microtiming output. Always print raw milliseconds; if the interval
602 : : * is >= 1 second, also break it down into days/hours/minutes/seconds.
603 : : */
604 : : static void
605 : 2 : PrintTiming(double elapsed_msec)
606 : : {
607 : : double seconds;
608 : : double minutes;
609 : : double hours;
610 : : double days;
611 : :
612 [ + - ]: 2 : if (elapsed_msec < 1000.0)
613 : : {
614 : : /* This is the traditional (pre-v10) output format */
615 : 2 : printf(_("Time: %.3f ms\n"), elapsed_msec);
616 : 2 : return;
617 : : }
618 : :
619 : : /*
620 : : * Note: we could print just seconds, in a format like %06.3f, when the
621 : : * total is less than 1min. But that's hard to interpret unless we tack
622 : : * on "s" or otherwise annotate it. Forcing the display to include
623 : : * minutes seems like a better solution.
624 : : */
625 : 0 : seconds = elapsed_msec / 1000.0;
626 : 0 : minutes = floor(seconds / 60.0);
627 : 0 : seconds -= 60.0 * minutes;
628 [ # # ]: 0 : if (minutes < 60.0)
629 : : {
630 : 0 : printf(_("Time: %.3f ms (%02d:%06.3f)\n"),
631 : : elapsed_msec, (int) minutes, seconds);
632 : 0 : return;
633 : : }
634 : :
635 : 0 : hours = floor(minutes / 60.0);
636 : 0 : minutes -= 60.0 * hours;
637 [ # # ]: 0 : if (hours < 24.0)
638 : : {
639 : 0 : printf(_("Time: %.3f ms (%02d:%02d:%06.3f)\n"),
640 : : elapsed_msec, (int) hours, (int) minutes, seconds);
641 : 0 : return;
642 : : }
643 : :
644 : 0 : days = floor(hours / 24.0);
645 : 0 : hours -= 24.0 * days;
646 : 0 : printf(_("Time: %.3f ms (%.0f d %02d:%02d:%06.3f)\n"),
647 : : elapsed_msec, days, (int) hours, (int) minutes, seconds);
648 : : }
649 : :
650 : :
651 : : /*
652 : : * PSQLexec
653 : : *
654 : : * This is the way to send "backdoor" queries (those not directly entered
655 : : * by the user). It is subject to -E but not -e.
656 : : *
657 : : * Caller is responsible for handling the ensuing processing if a COPY
658 : : * command is sent.
659 : : *
660 : : * Note: we don't bother to check PQclientEncoding; it is assumed that no
661 : : * caller uses this path to issue "SET CLIENT_ENCODING".
662 : : */
663 : : PGresult *
664 : 30759 : PSQLexec(const char *query)
665 : : {
666 : : PGresult *res;
667 : :
668 [ - + ]: 30759 : if (!pset.db)
669 : : {
670 : 0 : pg_log_error("You are currently not connected to a database.");
671 : 0 : return NULL;
672 : : }
673 : :
674 [ - + ]: 30759 : if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
675 : : {
676 : 0 : printf(_("/**** INTERNAL QUERY ****/\n"
677 : : "%s\n"
678 : : "/************************/\n\n"), query);
679 : 0 : fflush(stdout);
680 [ # # ]: 0 : if (pset.logfile)
681 : : {
682 : 0 : fprintf(pset.logfile,
683 : 0 : _("/**** INTERNAL QUERY ****/\n"
684 : : "%s\n"
685 : : "/************************/\n\n"), query);
686 : 0 : fflush(pset.logfile);
687 : : }
688 : :
689 [ # # ]: 0 : if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
690 : 0 : return NULL;
691 : : }
692 : :
693 : 30759 : SetCancelConn(pset.db);
694 : :
695 : 30759 : res = PQexec(pset.db, query);
696 : :
697 : 30759 : ResetCancelConn();
698 : :
699 [ - + ]: 30759 : if (!AcceptResult(res, true))
700 : : {
701 : 0 : ClearOrSaveResult(res);
702 : 0 : res = NULL;
703 : : }
704 : :
705 : 30759 : return res;
706 : : }
707 : :
708 : :
709 : : /*
710 : : * PSQLexecWatch
711 : : *
712 : : * This function is used for \watch command to send the query to
713 : : * the server and print out the result.
714 : : *
715 : : * Returns 1 if the query executed successfully, 0 if it cannot be repeated,
716 : : * e.g., because of the interrupt, -1 on error.
717 : : */
718 : : int
719 : 129 : PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout, int min_rows)
720 : : {
721 : 129 : bool timing = pset.timing;
722 : 129 : double elapsed_msec = 0;
723 : : int res;
724 : :
725 [ - + ]: 129 : if (!pset.db)
726 : : {
727 : 0 : pg_log_error("You are currently not connected to a database.");
728 : 0 : return 0;
729 : : }
730 : :
731 : 129 : SetCancelConn(pset.db);
732 : :
733 : 129 : res = ExecQueryAndProcessResults(query,
734 : : &elapsed_msec, NULL,
735 : : -1,
736 : : true, min_rows,
737 : : opt, printQueryFout);
738 : :
739 : 127 : ResetCancelConn();
740 : :
741 : : /* Possible microtiming output */
742 [ - + ]: 127 : if (timing)
743 : 0 : PrintTiming(elapsed_msec);
744 : :
745 : 127 : return res;
746 : : }
747 : :
748 : :
749 : : /*
750 : : * PrintNotifications: check for asynchronous notifications, and print them out
751 : : */
752 : : static void
753 : 261077 : PrintNotifications(void)
754 : : {
755 : : PGnotify *notify;
756 : :
757 : 261077 : PQconsumeInput(pset.db);
758 [ + + ]: 261089 : while ((notify = PQnotifies(pset.db)) != NULL)
759 : : {
760 : : /* for backward compatibility, only show payload if nonempty */
761 [ + + ]: 12 : if (notify->extra[0])
762 : 11 : fprintf(pset.queryFout, _("Asynchronous notification \"%s\" with payload \"%s\" received from server process with PID %d.\n"),
763 : : notify->relname, notify->extra, notify->be_pid);
764 : : else
765 : 1 : fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
766 : : notify->relname, notify->be_pid);
767 : 12 : fflush(pset.queryFout);
768 : 12 : PQfreemem(notify);
769 : 12 : PQconsumeInput(pset.db);
770 : : }
771 : 261077 : }
772 : :
773 : :
774 : : /*
775 : : * PrintQueryTuples: assuming query result is OK, print its tuples
776 : : *
777 : : * We use the options given by opt unless that's NULL, in which case
778 : : * we use pset.popt.
779 : : *
780 : : * Output is to printQueryFout unless that's NULL, in which case
781 : : * we use pset.queryFout.
782 : : *
783 : : * Returns true if successful, false otherwise.
784 : : */
785 : : static bool
786 : 97067 : PrintQueryTuples(const PGresult *result, const printQueryOpt *opt,
787 : : FILE *printQueryFout)
788 : : {
789 : 97067 : bool ok = true;
790 [ + + ]: 97067 : FILE *fout = printQueryFout ? printQueryFout : pset.queryFout;
791 : :
792 [ + + ]: 97067 : printQuery(result, opt ? opt : &pset.popt, fout, false, pset.logfile);
793 : 97067 : fflush(fout);
794 [ - + ]: 97067 : if (ferror(fout))
795 : : {
796 : 0 : pg_log_error("could not print result table: %m");
797 : 0 : ok = false;
798 : : }
799 : :
800 : 97067 : return ok;
801 : : }
802 : :
803 : :
804 : : /*
805 : : * StoreQueryTuple: assuming query result is OK, save data into variables
806 : : *
807 : : * Returns true if successful, false otherwise.
808 : : */
809 : : static bool
810 : 597 : StoreQueryTuple(const PGresult *result)
811 : : {
812 : 597 : bool success = true;
813 : :
814 [ + + ]: 597 : if (PQntuples(result) < 1)
815 : : {
816 : 12 : pg_log_error("no rows returned for \\gset");
817 : 12 : success = false;
818 : : }
819 [ + + ]: 585 : else if (PQntuples(result) > 1)
820 : : {
821 : 8 : pg_log_error("more than one row returned for \\gset");
822 : 8 : success = false;
823 : : }
824 : : else
825 : : {
826 : : int i;
827 : :
828 [ + + ]: 1272 : for (i = 0; i < PQnfields(result); i++)
829 : : {
830 : 699 : char *colname = PQfname(result, i);
831 : : char *varname;
832 : : char *value;
833 : :
834 : : /* concatenate prefix and column name */
835 : 699 : varname = psprintf("%s%s", pset.gset_prefix, colname);
836 : :
837 [ + + ]: 699 : if (VariableHasHook(pset.vars, varname))
838 : : {
839 : 4 : pg_log_warning("attempt to \\gset into specially treated variable \"%s\" ignored",
840 : : varname);
841 : 4 : continue;
842 : : }
843 : :
844 [ + + ]: 695 : if (!PQgetisnull(result, 0, i))
845 : 687 : value = PQgetvalue(result, 0, i);
846 : : else
847 : : {
848 : : /* for NULL value, unset rather than set the variable */
849 : 8 : value = NULL;
850 : : }
851 : :
852 [ + + ]: 695 : if (!SetVariable(pset.vars, varname, value))
853 : : {
854 : 4 : pfree(varname);
855 : 4 : success = false;
856 : 4 : break;
857 : : }
858 : :
859 : 691 : pfree(varname);
860 : : }
861 : : }
862 : :
863 : 597 : return success;
864 : : }
865 : :
866 : :
867 : : /*
868 : : * ExecQueryTuples: assuming query result is OK, execute each query
869 : : * result field as a SQL statement
870 : : *
871 : : * Returns true if successful, false otherwise.
872 : : */
873 : : static bool
874 : 29 : ExecQueryTuples(const PGresult *result)
875 : : {
876 : 29 : bool success = true;
877 : 29 : int nrows = PQntuples(result);
878 : 29 : int ncolumns = PQnfields(result);
879 : : int r,
880 : : c;
881 : :
882 : : /*
883 : : * We must turn off gexec_flag to avoid infinite recursion.
884 : : */
885 : 29 : pset.gexec_flag = false;
886 : :
887 [ + + ]: 290 : for (r = 0; r < nrows; r++)
888 : : {
889 [ + + ]: 534 : for (c = 0; c < ncolumns; c++)
890 : : {
891 [ + + ]: 273 : if (!PQgetisnull(result, r, c))
892 : : {
893 : 269 : const char *query = PQgetvalue(result, r, c);
894 : :
895 : : /* Abandon execution if cancel_pressed */
896 [ - + ]: 269 : if (cancel_pressed)
897 : 0 : goto loop_exit;
898 : :
899 : : /*
900 : : * ECHO_ALL mode should echo these queries, but SendQuery
901 : : * assumes that MainLoop did that, so we have to do it here.
902 : : */
903 [ + + + - ]: 269 : if (pset.echo == PSQL_ECHO_ALL && !pset.singlestep)
904 : : {
905 : 264 : puts(query);
906 : 264 : fflush(stdout);
907 : : }
908 : :
909 [ + + ]: 269 : if (!SendQuery(query, -1))
910 : : {
911 : : /* Error - abandon execution if ON_ERROR_STOP */
912 : 4 : success = false;
913 [ - + ]: 4 : if (pset.on_error_stop)
914 : 0 : goto loop_exit;
915 : : }
916 : : }
917 : : }
918 : : }
919 : :
920 : 29 : loop_exit:
921 : :
922 : : /*
923 : : * Restore state. We know gexec_flag was on, else we'd not be here. (We
924 : : * also know it'll get turned off at end of command, but that's not ours
925 : : * to do here.)
926 : : */
927 : 29 : pset.gexec_flag = true;
928 : :
929 : : /* Return true if all queries were successful */
930 : 29 : return success;
931 : : }
932 : :
933 : :
934 : : /*
935 : : * Marshal the COPY data. Either path will get the
936 : : * connection out of its COPY state, then call PQresultStatus()
937 : : * once and report any error. Return whether all was ok.
938 : : *
939 : : * For COPY OUT, direct the output to copystream, or discard if that's NULL.
940 : : * For COPY IN, read from copystream (which mustn't be NULL).
941 : : *
942 : : * Update *resultp if further processing is necessary; set to NULL otherwise.
943 : : * Return a result when queryFout can safely output a result status: on COPY
944 : : * IN, or on COPY OUT if written to something other than pset.queryFout.
945 : : * Returning NULL prevents the command status from being printed, which we
946 : : * want if the status line doesn't get taken as part of the COPY data.
947 : : */
948 : : static bool
949 : 1182 : HandleCopyResult(PGresult **resultp, FILE *copystream)
950 : : {
951 : : bool success;
952 : : PGresult *copy_result;
953 : 1182 : ExecStatusType result_status = PQresultStatus(*resultp);
954 : :
955 : : Assert(result_status == PGRES_COPY_OUT ||
956 : : result_status == PGRES_COPY_IN);
957 : :
958 : 1182 : SetCancelConn(pset.db);
959 : :
960 [ + + ]: 1182 : if (result_status == PGRES_COPY_OUT)
961 : : {
962 : 501 : success = handleCopyOut(pset.db,
963 : : copystream,
964 : : ©_result)
965 [ + + + - ]: 501 : && (copystream != NULL);
966 : :
967 : : /*
968 : : * Suppress status printing if the report would go to the same place
969 : : * as the COPY data just went. Note this doesn't prevent error
970 : : * reporting, since handleCopyOut did that.
971 : : */
972 [ + + ]: 501 : if (copystream == pset.queryFout)
973 : : {
974 : 484 : PQclear(copy_result);
975 : 484 : copy_result = NULL;
976 : : }
977 : : }
978 : : else
979 : : {
980 : : /* COPY IN */
981 : : Assert(copystream);
982 : 681 : success = handleCopyIn(pset.db,
983 : : copystream,
984 : 681 : PQbinaryTuples(*resultp),
985 : : ©_result);
986 : : }
987 : 1182 : ResetCancelConn();
988 : :
989 : : /*
990 : : * Replace the PGRES_COPY_OUT/IN result with COPY command's exit status,
991 : : * or with NULL if we want to suppress printing anything.
992 : : */
993 : 1182 : PQclear(*resultp);
994 : 1182 : *resultp = copy_result;
995 : :
996 : 1182 : return success;
997 : : }
998 : :
999 : : /*
1000 : : * PrintQueryStatus: report command status as required
1001 : : */
1002 : : static void
1003 : 229044 : PrintQueryStatus(PGresult *result, FILE *printQueryFout)
1004 : : {
1005 : : char buf[16];
1006 : 229044 : const char *cmdstatus = PQcmdStatus(result);
1007 [ + - ]: 229044 : FILE *fout = printQueryFout ? printQueryFout : pset.queryFout;
1008 : :
1009 : : /* Do nothing if it's a TUPLES_OK result that isn't from RETURNING */
1010 [ + + ]: 229044 : if (PQresultStatus(result) == PGRES_TUPLES_OK)
1011 : : {
1012 [ + + ]: 97829 : if (!(strncmp(cmdstatus, "INSERT", 6) == 0 ||
1013 [ + + ]: 97247 : strncmp(cmdstatus, "UPDATE", 6) == 0 ||
1014 [ + + ]: 96892 : strncmp(cmdstatus, "DELETE", 6) == 0 ||
1015 [ + + ]: 96740 : strncmp(cmdstatus, "MERGE", 5) == 0))
1016 : 96628 : return;
1017 : : }
1018 : :
1019 [ + + ]: 132416 : if (!pset.quiet)
1020 : : {
1021 [ - + ]: 745 : if (pset.popt.topt.format == PRINT_HTML)
1022 : : {
1023 : 0 : fputs("<p>", fout);
1024 : 0 : html_escaped_print(cmdstatus, fout);
1025 : 0 : fputs("</p>\n", fout);
1026 : : }
1027 : : else
1028 : 745 : fprintf(fout, "%s\n", cmdstatus);
1029 : 745 : fflush(fout);
1030 : : }
1031 : :
1032 [ - + ]: 132416 : if (pset.logfile)
1033 : 0 : fprintf(pset.logfile, "%s\n", cmdstatus);
1034 : :
1035 : 132416 : snprintf(buf, sizeof(buf), "%u", PQoidValue(result));
1036 : 132416 : SetVariable(pset.vars, "LASTOID", buf);
1037 : : }
1038 : :
1039 : :
1040 : : /*
1041 : : * PrintQueryResult: print out (or store or execute) query result as required
1042 : : *
1043 : : * last is true if this is the last result of a command string.
1044 : : * opt and printQueryFout are defined as for PrintQueryTuples.
1045 : : * printStatusFout is where to send command status; NULL means pset.queryFout.
1046 : : *
1047 : : * Returns true if the query executed successfully, false otherwise.
1048 : : */
1049 : : static bool
1050 : 229686 : PrintQueryResult(PGresult *result, bool last,
1051 : : const printQueryOpt *opt, FILE *printQueryFout,
1052 : : FILE *printStatusFout)
1053 : : {
1054 : : bool success;
1055 : :
1056 [ - + ]: 229686 : if (!result)
1057 : 0 : return false;
1058 : :
1059 [ + + + - : 229686 : switch (PQresultStatus(result))
- - ]
1060 : : {
1061 : 97798 : case PGRES_TUPLES_OK:
1062 : : /* store or execute or print the data ... */
1063 [ + + + + ]: 97798 : if (last && pset.gset_prefix)
1064 : 597 : success = StoreQueryTuple(result);
1065 [ + + + + ]: 97201 : else if (last && pset.gexec_flag)
1066 : 29 : success = ExecQueryTuples(result);
1067 [ + + + + ]: 97172 : else if (last && pset.crosstab_flag)
1068 : 96 : success = PrintResultInCrosstab(result);
1069 [ + + + + ]: 97076 : else if (last || pset.show_all_results)
1070 : 97067 : success = PrintQueryTuples(result, opt, printQueryFout);
1071 : : else
1072 : 9 : success = true;
1073 : :
1074 : : /*
1075 : : * If it's INSERT/UPDATE/DELETE/MERGE RETURNING, also print
1076 : : * status.
1077 : : */
1078 [ + + + + ]: 97798 : if (last || pset.show_all_results)
1079 : 97789 : PrintQueryStatus(result, printStatusFout);
1080 : :
1081 : 97798 : break;
1082 : :
1083 : 131215 : case PGRES_COMMAND_OK:
1084 [ + + + - ]: 131215 : if (last || pset.show_all_results)
1085 : 131215 : PrintQueryStatus(result, printStatusFout);
1086 : 131215 : success = true;
1087 : 131215 : break;
1088 : :
1089 : 673 : case PGRES_EMPTY_QUERY:
1090 : 673 : success = true;
1091 : 673 : break;
1092 : :
1093 : 0 : case PGRES_COPY_OUT:
1094 : : case PGRES_COPY_IN:
1095 : : /* nothing to do here: already processed */
1096 : 0 : success = true;
1097 : 0 : break;
1098 : :
1099 : 0 : case PGRES_PIPELINE_ABORTED:
1100 : : case PGRES_BAD_RESPONSE:
1101 : : case PGRES_NONFATAL_ERROR:
1102 : : case PGRES_FATAL_ERROR:
1103 : 0 : success = false;
1104 : 0 : break;
1105 : :
1106 : 0 : default:
1107 : 0 : success = false;
1108 : 0 : pg_log_error("unexpected PQresultStatus: %d",
1109 : : PQresultStatus(result));
1110 : 0 : break;
1111 : : }
1112 : :
1113 : 229686 : return success;
1114 : : }
1115 : :
1116 : : /*
1117 : : * SendQuery: send the query string to the backend
1118 : : * (and print out result)
1119 : : *
1120 : : * Note: This is the "front door" way to send a query. That is, use it to
1121 : : * send queries actually entered by the user. These queries will be subject to
1122 : : * single step mode.
1123 : : * To send "back door" queries (generated by slash commands, etc.) in a
1124 : : * controlled way, use PSQLexec().
1125 : : *
1126 : : * In the most common case, the caller can determine whether the query
1127 : : * includes any COPY FROM STDIN command(s); if so, pass the count of them.
1128 : : * Otherwise pass num_copy_from_stdin == -1 and we'll compute it locally.
1129 : : *
1130 : : * Returns true if the query executed successfully, false otherwise.
1131 : : */
1132 : : bool
1133 : 261091 : SendQuery(const char *query, int num_copy_from_stdin)
1134 : : {
1135 : 261091 : bool timing = pset.timing;
1136 : : PGTransactionStatusType transaction_status;
1137 : 261091 : double elapsed_msec = 0;
1138 : 261091 : bool OK = false;
1139 : : int i;
1140 : 261091 : bool on_error_rollback_savepoint = false;
1141 : 261091 : bool svpt_gone = false;
1142 : :
1143 [ - + ]: 261091 : if (!pset.db)
1144 : : {
1145 : 0 : pg_log_error("You are currently not connected to a database.");
1146 : 0 : goto sendquery_cleanup;
1147 : : }
1148 : :
1149 [ - + ]: 261091 : if (pset.singlestep)
1150 : : {
1151 : : char buf[3];
1152 : :
1153 : 0 : fflush(stderr);
1154 : 0 : printf(_("/**(Single step mode: verify command)******************************************/\n"
1155 : : "%s\n"
1156 : : "/**(press return to proceed or enter x and return to cancel)*******************/\n"),
1157 : : query);
1158 : 0 : fflush(stdout);
1159 [ # # ]: 0 : if (fgets(buf, sizeof(buf), stdin) != NULL)
1160 [ # # ]: 0 : if (buf[0] == 'x')
1161 : 0 : goto sendquery_cleanup;
1162 [ # # ]: 0 : if (cancel_pressed)
1163 : 0 : goto sendquery_cleanup;
1164 : : }
1165 [ + + ]: 261091 : else if (pset.echo == PSQL_ECHO_QUERIES)
1166 : : {
1167 : 87 : puts(query);
1168 : 87 : fflush(stdout);
1169 : : }
1170 : :
1171 [ - + ]: 261091 : if (pset.logfile)
1172 : : {
1173 : 0 : fprintf(pset.logfile,
1174 : 0 : _("/******** QUERY *********/\n"
1175 : : "%s\n"
1176 : : "/************************/\n\n"), query);
1177 : 0 : fflush(pset.logfile);
1178 : : }
1179 : :
1180 : 261091 : SetCancelConn(pset.db);
1181 : :
1182 : 261091 : transaction_status = PQtransactionStatus(pset.db);
1183 : :
1184 [ + + ]: 261091 : if (transaction_status == PQTRANS_IDLE &&
1185 [ + + ]: 231510 : !pset.autocommit &&
1186 [ + + ]: 56 : !command_no_begin(query))
1187 : : {
1188 : : PGresult *result;
1189 : :
1190 : 48 : result = PQexec(pset.db, "BEGIN");
1191 [ - + ]: 48 : if (PQresultStatus(result) != PGRES_COMMAND_OK)
1192 : : {
1193 : 0 : pg_log_info("%s", PQerrorMessage(pset.db));
1194 : 0 : ClearOrSaveResult(result);
1195 : 0 : goto sendquery_cleanup;
1196 : : }
1197 : 48 : ClearOrSaveResult(result);
1198 : 48 : transaction_status = PQtransactionStatus(pset.db);
1199 : : }
1200 : :
1201 [ + + ]: 261091 : if (transaction_status == PQTRANS_INTRANS &&
1202 [ + + ]: 27884 : pset.on_error_rollback != PSQL_ERROR_ROLLBACK_OFF &&
1203 [ + - ]: 104 : (pset.cur_cmd_interactive ||
1204 [ + - ]: 104 : pset.on_error_rollback == PSQL_ERROR_ROLLBACK_ON))
1205 : : {
1206 : : PGresult *result;
1207 : :
1208 : 104 : result = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint");
1209 [ - + ]: 104 : if (PQresultStatus(result) != PGRES_COMMAND_OK)
1210 : : {
1211 : 0 : pg_log_info("%s", PQerrorMessage(pset.db));
1212 : 0 : ClearOrSaveResult(result);
1213 : 0 : goto sendquery_cleanup;
1214 : : }
1215 : 104 : ClearOrSaveResult(result);
1216 : 104 : on_error_rollback_savepoint = true;
1217 : : }
1218 : :
1219 [ + + ]: 261091 : if (pset.gdesc_flag)
1220 : : {
1221 : : /* Describe query's result columns, without executing it */
1222 : 57 : OK = DescribeQuery(query, &elapsed_msec);
1223 : : }
1224 : : else
1225 : : {
1226 : : /* Default fetch-and-print mode */
1227 : 261034 : OK = (ExecQueryAndProcessResults(query,
1228 : : &elapsed_msec, &svpt_gone,
1229 : : num_copy_from_stdin,
1230 : : false, 0,
1231 : : NULL, NULL) > 0);
1232 : : }
1233 : :
1234 [ + + + + ]: 261077 : if (!OK && pset.echo == PSQL_ECHO_ERRORS)
1235 : 4 : pg_log_info("STATEMENT: %s", query);
1236 : :
1237 : : /* If we made a temporary savepoint, possibly release/rollback */
1238 [ + + ]: 261077 : if (on_error_rollback_savepoint)
1239 : : {
1240 : 104 : const char *svptcmd = NULL;
1241 : :
1242 : 104 : transaction_status = PQtransactionStatus(pset.db);
1243 : :
1244 [ + + + - ]: 104 : switch (transaction_status)
1245 : : {
1246 : 28 : case PQTRANS_INERROR:
1247 : : /* We always rollback on an error */
1248 : 28 : svptcmd = "ROLLBACK TO pg_psql_temporary_savepoint";
1249 : 28 : break;
1250 : :
1251 : 28 : case PQTRANS_IDLE:
1252 : : /* If they are no longer in a transaction, then do nothing */
1253 : 28 : break;
1254 : :
1255 : 48 : case PQTRANS_INTRANS:
1256 : :
1257 : : /*
1258 : : * Release our savepoint, but do nothing if they are messing
1259 : : * with savepoints themselves
1260 : : */
1261 [ + + ]: 48 : if (!svpt_gone)
1262 : 44 : svptcmd = "RELEASE pg_psql_temporary_savepoint";
1263 : 48 : break;
1264 : :
1265 : 0 : case PQTRANS_ACTIVE:
1266 : : case PQTRANS_UNKNOWN:
1267 : : default:
1268 : 0 : OK = false;
1269 : : /* PQTRANS_UNKNOWN is expected given a broken connection. */
1270 [ # # # # ]: 0 : if (transaction_status != PQTRANS_UNKNOWN || ConnectionUp())
1271 : 0 : pg_log_error("unexpected transaction status (%d)",
1272 : : transaction_status);
1273 : 0 : break;
1274 : : }
1275 : :
1276 [ + + ]: 104 : if (svptcmd)
1277 : : {
1278 : : PGresult *svptres;
1279 : :
1280 : 72 : svptres = PQexec(pset.db, svptcmd);
1281 [ - + ]: 72 : if (PQresultStatus(svptres) != PGRES_COMMAND_OK)
1282 : : {
1283 : 0 : pg_log_info("%s", PQerrorMessage(pset.db));
1284 : 0 : ClearOrSaveResult(svptres);
1285 : 0 : OK = false;
1286 : :
1287 : 0 : goto sendquery_cleanup;
1288 : : }
1289 : 72 : PQclear(svptres);
1290 : : }
1291 : : }
1292 : :
1293 : : /* Possible microtiming output */
1294 [ + + ]: 261077 : if (timing)
1295 : 2 : PrintTiming(elapsed_msec);
1296 : :
1297 : : /* check for events that may occur during query execution */
1298 : :
1299 [ + + + - ]: 261106 : if (pset.encoding != PQclientEncoding(pset.db) &&
1300 : 29 : PQclientEncoding(pset.db) >= 0)
1301 : : {
1302 : : /* track effects of SET CLIENT_ENCODING */
1303 : 29 : pset.encoding = PQclientEncoding(pset.db);
1304 : 29 : pset.popt.topt.encoding = pset.encoding;
1305 : 29 : SetVariable(pset.vars, "ENCODING",
1306 : : pg_encoding_to_char(pset.encoding));
1307 : : }
1308 : :
1309 : 261077 : PrintNotifications();
1310 : :
1311 : : /* perform cleanup that should occur after any attempted query */
1312 : :
1313 : 261077 : sendquery_cleanup:
1314 : :
1315 : : /* global cancellation reset */
1316 : 261077 : ResetCancelConn();
1317 : :
1318 : : /* reset \g's output-to-filename trigger */
1319 [ + + ]: 261077 : if (pset.gfname)
1320 : : {
1321 : 20 : free(pset.gfname);
1322 : 20 : pset.gfname = NULL;
1323 : : }
1324 : :
1325 : : /* restore print settings if \g changed them */
1326 [ + + ]: 261077 : if (pset.gsavepopt)
1327 : : {
1328 : 110 : restorePsetInfo(&pset.popt, pset.gsavepopt);
1329 : 110 : pset.gsavepopt = NULL;
1330 : : }
1331 : :
1332 : : /* clean up after extended protocol queries */
1333 : 261077 : clean_extended_state();
1334 : :
1335 : : /* reset \gset trigger */
1336 [ + + ]: 261077 : if (pset.gset_prefix)
1337 : : {
1338 : 597 : free(pset.gset_prefix);
1339 : 597 : pset.gset_prefix = NULL;
1340 : : }
1341 : :
1342 : : /* reset \gdesc trigger */
1343 : 261077 : pset.gdesc_flag = false;
1344 : :
1345 : : /* reset \gexec trigger */
1346 : 261077 : pset.gexec_flag = false;
1347 : :
1348 : : /* reset \crosstabview trigger */
1349 : 261077 : pset.crosstab_flag = false;
1350 [ + + ]: 1305385 : for (i = 0; i < lengthof(pset.ctv_args); i++)
1351 : : {
1352 : 1044308 : pg_free(pset.ctv_args[i]);
1353 : 1044308 : pset.ctv_args[i] = NULL;
1354 : : }
1355 : :
1356 : 261077 : return OK;
1357 : : }
1358 : :
1359 : :
1360 : : /*
1361 : : * DescribeQuery: describe the result columns of a query, without executing it
1362 : : *
1363 : : * Returns true if the operation executed successfully, false otherwise.
1364 : : *
1365 : : * If pset.timing is on, total query time (exclusive of result-printing) is
1366 : : * stored into *elapsed_msec.
1367 : : */
1368 : : static bool
1369 : 57 : DescribeQuery(const char *query, double *elapsed_msec)
1370 : : {
1371 : 57 : bool timing = pset.timing;
1372 : : PGresult *result;
1373 : : bool OK;
1374 : : instr_time before,
1375 : : after;
1376 : :
1377 : 57 : *elapsed_msec = 0;
1378 : :
1379 [ - + ]: 57 : if (timing)
1380 : 0 : INSTR_TIME_SET_CURRENT(before);
1381 : : else
1382 : 57 : INSTR_TIME_SET_ZERO(before);
1383 : :
1384 : : /*
1385 : : * To parse the query but not execute it, we prepare it, using the unnamed
1386 : : * prepared statement. This is invisible to psql users, since there's no
1387 : : * way to access the unnamed prepared statement from psql user space. The
1388 : : * next Parse or Query protocol message would overwrite the statement
1389 : : * anyway. (So there's no great need to clear it when done, which is a
1390 : : * good thing because libpq provides no easy way to do that.)
1391 : : */
1392 : 57 : result = PQprepare(pset.db, "", query, 0, NULL);
1393 [ + + ]: 57 : if (PQresultStatus(result) != PGRES_COMMAND_OK)
1394 : : {
1395 : 21 : pg_log_info("%s", PQerrorMessage(pset.db));
1396 : 21 : SetResultVariables(result, false);
1397 : 21 : ClearOrSaveResult(result);
1398 : 21 : return false;
1399 : : }
1400 : 36 : PQclear(result);
1401 : :
1402 : 36 : result = PQdescribePrepared(pset.db, "");
1403 [ + - + - ]: 72 : OK = AcceptResult(result, true) &&
1404 : 36 : (PQresultStatus(result) == PGRES_COMMAND_OK);
1405 [ + - + - ]: 36 : if (OK && result)
1406 : : {
1407 [ + + ]: 36 : if (PQnfields(result) > 0)
1408 : : {
1409 : : PQExpBufferData buf;
1410 : : int i;
1411 : :
1412 : 24 : initPQExpBuffer(&buf);
1413 : :
1414 : 24 : printfPQExpBuffer(&buf,
1415 : : "SELECT name AS \"%s\", pg_catalog.format_type(tp, tpm) AS \"%s\"\n"
1416 : : "FROM (VALUES ",
1417 : : gettext_noop("Column"),
1418 : : gettext_noop("Type"));
1419 : :
1420 [ + + ]: 108 : for (i = 0; i < PQnfields(result); i++)
1421 : : {
1422 : : const char *name;
1423 : : char *escname;
1424 : :
1425 [ + + ]: 84 : if (i > 0)
1426 : 60 : appendPQExpBufferChar(&buf, ',');
1427 : :
1428 : 84 : name = PQfname(result, i);
1429 : 84 : escname = PQescapeLiteral(pset.db, name, strlen(name));
1430 : :
1431 [ - + ]: 84 : if (escname == NULL)
1432 : : {
1433 : 0 : pg_log_info("%s", PQerrorMessage(pset.db));
1434 : 0 : PQclear(result);
1435 : 0 : termPQExpBuffer(&buf);
1436 : 0 : return false;
1437 : : }
1438 : :
1439 : 84 : appendPQExpBuffer(&buf, "(%s, '%u'::pg_catalog.oid, %d)",
1440 : : escname,
1441 : : PQftype(result, i),
1442 : : PQfmod(result, i));
1443 : :
1444 : 84 : PQfreemem(escname);
1445 : : }
1446 : :
1447 : 24 : appendPQExpBufferStr(&buf, ") s(name, tp, tpm)");
1448 : 24 : PQclear(result);
1449 : :
1450 : 24 : result = PQexec(pset.db, buf.data);
1451 : 24 : OK = AcceptResult(result, true);
1452 : :
1453 [ - + ]: 24 : if (timing)
1454 : : {
1455 : 0 : INSTR_TIME_SET_CURRENT(after);
1456 : 0 : INSTR_TIME_SUBTRACT(after, before);
1457 : 0 : *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
1458 : : }
1459 : :
1460 [ + - + - ]: 24 : if (OK && result)
1461 : 24 : OK = PrintQueryResult(result, true, NULL, NULL, NULL);
1462 : :
1463 : 24 : termPQExpBuffer(&buf);
1464 : : }
1465 : : else
1466 : 12 : fprintf(pset.queryFout,
1467 : 12 : _("The command has no result, or the result has no columns.\n"));
1468 : : }
1469 : :
1470 : 36 : SetResultVariables(result, OK);
1471 : 36 : ClearOrSaveResult(result);
1472 : :
1473 : 36 : return OK;
1474 : : }
1475 : :
1476 : : /*
1477 : : * Read and discard all results in an aborted pipeline.
1478 : : *
1479 : : * If a synchronisation point is found, we can stop discarding results as
1480 : : * the pipeline will switch back to a clean state. If no synchronisation
1481 : : * point is available, we need to stop when there are no more pending
1482 : : * results, otherwise, calling PQgetResult() would block.
1483 : : */
1484 : : static PGresult *
1485 : 108 : discardAbortedPipelineResults(void)
1486 : : {
1487 : : for (;;)
1488 : 196 : {
1489 : 304 : PGresult *res = PQgetResult(pset.db);
1490 : 304 : ExecStatusType result_status = PQresultStatus(res);
1491 : :
1492 [ + + ]: 304 : if (result_status == PGRES_PIPELINE_SYNC)
1493 : : {
1494 : : /*
1495 : : * Found a synchronisation point. The sync counter is decremented
1496 : : * by the caller.
1497 : : */
1498 : 52 : return res;
1499 : : }
1500 [ + + - + ]: 252 : else if (res != NULL && result_status == PGRES_FATAL_ERROR)
1501 : : {
1502 : : /*
1503 : : * Found a FATAL error sent by the backend, and we cannot recover
1504 : : * from this state. Instead, return the last result and let the
1505 : : * outer loop handle it.
1506 : : */
1507 : : PGresult *fatal_res PG_USED_FOR_ASSERTS_ONLY;
1508 : :
1509 : : /*
1510 : : * Fetch result to consume the end of the current query being
1511 : : * processed.
1512 : : */
1513 : 0 : fatal_res = PQgetResult(pset.db);
1514 : : Assert(fatal_res == NULL);
1515 : 0 : return res;
1516 : : }
1517 [ + + ]: 252 : else if (res == NULL)
1518 : : {
1519 : : /*
1520 : : * A query was processed, decrement the counters.
1521 : : *
1522 : : * It is possible to get here with available_results == 0 when an
1523 : : * error is generated by the Sync message processing itself. Such
1524 : : * errors are not counted in available_results because they are
1525 : : * not associated with a piped command. In that case, skip the
1526 : : * counter decrements and continue to find the Sync result.
1527 : : *
1528 : : * If the connection has been lost, there will never be any more
1529 : : * results to read, so bail out.
1530 : : */
1531 [ - + ]: 180 : if (!ConnectionUp())
1532 : 0 : return NULL;
1533 [ + + ]: 180 : if (pset.available_results > 0)
1534 : 152 : pset.available_results--;
1535 [ + - ]: 180 : if (pset.requested_results > 0)
1536 : 180 : pset.requested_results--;
1537 : : }
1538 : :
1539 [ + + ]: 252 : if (pset.requested_results == 0)
1540 : : {
1541 : : /* We have read all the requested results, leave */
1542 : 56 : return res;
1543 : : }
1544 : :
1545 [ + + - + ]: 196 : if (pset.available_results == 0 && pset.piped_syncs == 0)
1546 : : {
1547 : : /*
1548 : : * There are no more results to get and there is no
1549 : : * synchronisation point to stop at. This will leave the pipeline
1550 : : * in an aborted state.
1551 : : */
1552 : 0 : return res;
1553 : : }
1554 : :
1555 : : /*
1556 : : * An aborted pipeline will have either NULL results or results in an
1557 : : * PGRES_PIPELINE_ABORTED status.
1558 : : */
1559 : : Assert(res == NULL || result_status == PGRES_PIPELINE_ABORTED);
1560 : 196 : PQclear(res);
1561 : : }
1562 : : }
1563 : :
1564 : : /*
1565 : : * ExecQueryAndProcessResults: utility function for use by SendQuery()
1566 : : * and PSQLexecWatch().
1567 : : *
1568 : : * Sends query and cycles through PGresult objects.
1569 : : *
1570 : : * If our command string contained a COPY FROM STDIN or COPY TO STDOUT, the
1571 : : * PGresult associated with these commands must be processed by providing an
1572 : : * input or output stream. In that event, we'll marshal data for the COPY.
1573 : : *
1574 : : * For other commands, the results are processed normally, depending on their
1575 : : * status and the status of a pipeline.
1576 : : *
1577 : : * When invoked from \watch, is_watch is true and min_rows is the value
1578 : : * of that option, or 0 if it wasn't set.
1579 : : *
1580 : : * Returns 1 on complete success, 0 on interrupt and -1 or errors. Possible
1581 : : * failure modes include purely client-side problems; check the transaction
1582 : : * status for the server-side opinion.
1583 : : *
1584 : : * Note that on a combined query, failure does not mean that nothing was
1585 : : * committed.
1586 : : */
1587 : : static int
1588 : 261163 : ExecQueryAndProcessResults(const char *query,
1589 : : double *elapsed_msec, bool *svpt_gone_p,
1590 : : int num_copy_from_stdin,
1591 : : bool is_watch, int min_rows,
1592 : : const printQueryOpt *opt, FILE *printQueryFout)
1593 : : {
1594 : 261163 : bool timing = pset.timing;
1595 : 261163 : bool success = false;
1596 : 261163 : bool return_early = false;
1597 : 261163 : bool end_pipeline = false;
1598 : : instr_time before,
1599 : : after;
1600 : : PGresult *result;
1601 : 261163 : FILE *gfile_fout = NULL;
1602 : 261163 : bool gfile_is_pipe = false;
1603 : :
1604 [ + + ]: 261163 : if (timing)
1605 : 2 : INSTR_TIME_SET_CURRENT(before);
1606 : : else
1607 : 261161 : INSTR_TIME_SET_ZERO(before);
1608 : :
1609 [ + + + + : 261163 : switch (pset.send_mode)
+ + + + +
+ + - ]
1610 : : {
1611 : 25 : case PSQL_SEND_EXTENDED_CLOSE:
1612 : 25 : success = PQsendClosePrepared(pset.db, pset.stmtName);
1613 [ + - + + ]: 25 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1614 : 12 : pset.piped_commands++;
1615 : 25 : break;
1616 : 67 : case PSQL_SEND_EXTENDED_PARSE:
1617 : 67 : success = PQsendPrepare(pset.db, pset.stmtName, query, 0, NULL);
1618 [ + - + + ]: 67 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1619 : 44 : pset.piped_commands++;
1620 : 67 : break;
1621 : 508 : case PSQL_SEND_EXTENDED_QUERY_PARAMS:
1622 : : Assert(pset.stmtName == NULL);
1623 : 1016 : success = PQsendQueryParams(pset.db, query,
1624 : : pset.bind_nparams, NULL,
1625 : 508 : (const char *const *) pset.bind_params,
1626 : : NULL, NULL, 0);
1627 [ + - + + ]: 508 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1628 : 433 : pset.piped_commands++;
1629 : 508 : break;
1630 : 80 : case PSQL_SEND_EXTENDED_QUERY_PREPARED:
1631 : : Assert(pset.stmtName != NULL);
1632 : 160 : success = PQsendQueryPrepared(pset.db, pset.stmtName,
1633 : : pset.bind_nparams,
1634 : 80 : (const char *const *) pset.bind_params,
1635 : : NULL, NULL, 0);
1636 [ + - + + ]: 80 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1637 : 32 : pset.piped_commands++;
1638 : 80 : break;
1639 : 225 : case PSQL_SEND_START_PIPELINE_MODE:
1640 : 225 : success = PQenterPipelineMode(pset.db);
1641 : 225 : break;
1642 : 225 : case PSQL_SEND_END_PIPELINE_MODE:
1643 : 225 : success = PQpipelineSync(pset.db);
1644 [ + + + - ]: 225 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1645 : : {
1646 : : /*
1647 : : * End of the pipeline, all queued commands need to be
1648 : : * processed.
1649 : : */
1650 : 221 : end_pipeline = true;
1651 : 221 : pset.piped_syncs++;
1652 : :
1653 : : /*
1654 : : * The server will send a ReadyForQuery after a Sync is
1655 : : * processed, flushing all the results back to the client.
1656 : : */
1657 : 221 : pset.available_results += pset.piped_commands;
1658 : 221 : pset.piped_commands = 0;
1659 : :
1660 : : /* We want to read all results */
1661 : 221 : pset.requested_results = pset.available_results + pset.piped_syncs;
1662 : : }
1663 : 225 : break;
1664 : 95 : case PSQL_SEND_PIPELINE_SYNC:
1665 : 95 : success = PQsendPipelineSync(pset.db);
1666 [ + - + - ]: 95 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1667 : : {
1668 : 95 : pset.piped_syncs++;
1669 : :
1670 : : /*
1671 : : * The server will send a ReadyForQuery after a Sync is
1672 : : * processed, flushing all the results back to the client.
1673 : : */
1674 : 95 : pset.available_results += pset.piped_commands;
1675 : 95 : pset.piped_commands = 0;
1676 : : }
1677 : 95 : break;
1678 : 12 : case PSQL_SEND_FLUSH:
1679 : 12 : success = PQflush(pset.db);
1680 : 12 : break;
1681 : 44 : case PSQL_SEND_FLUSH_REQUEST:
1682 : 44 : success = PQsendFlushRequest(pset.db);
1683 [ + - + - ]: 44 : if (success && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1684 : : {
1685 : : /*
1686 : : * With the flush request, all commands in the pipeline are
1687 : : * pushed and the server will flush the results back to the
1688 : : * client, making them available.
1689 : : */
1690 : 44 : pset.available_results += pset.piped_commands;
1691 : 44 : pset.piped_commands = 0;
1692 : : }
1693 : 44 : break;
1694 : 124 : case PSQL_SEND_GET_RESULTS:
1695 [ + + + + ]: 124 : if (pset.available_results == 0 && pset.piped_syncs == 0)
1696 : : {
1697 : : /*
1698 : : * If no sync or flush request were sent, PQgetResult() would
1699 : : * block as there are no results available. Forbid any
1700 : : * attempt to get pending results should we try to reach this
1701 : : * state.
1702 : : */
1703 : 16 : pg_log_info("No pending results to get");
1704 : 16 : success = false;
1705 : 16 : pset.requested_results = 0;
1706 : : }
1707 : : else
1708 : : {
1709 : 108 : success = true;
1710 : :
1711 : : /*
1712 : : * Cap requested_results to the maximum number of known
1713 : : * results.
1714 : : */
1715 [ + + ]: 108 : if (pset.requested_results == 0 ||
1716 [ - + ]: 44 : pset.requested_results > (pset.available_results + pset.piped_syncs))
1717 : 64 : pset.requested_results = pset.available_results + pset.piped_syncs;
1718 : : }
1719 : 124 : break;
1720 : 259758 : case PSQL_SEND_QUERY:
1721 [ + + ]: 259758 : if (PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1722 : : {
1723 : 76 : success = PQsendQueryParams(pset.db, query,
1724 : : 0, NULL, NULL, NULL, NULL, 0);
1725 [ + - ]: 76 : if (success)
1726 : 76 : pset.piped_commands++;
1727 : : }
1728 : : else
1729 : 259682 : success = PQsendQuery(pset.db, query);
1730 : 259758 : break;
1731 : : }
1732 : :
1733 [ + + ]: 261163 : if (!success)
1734 : : {
1735 : 32 : const char *error = PQerrorMessage(pset.db);
1736 : :
1737 [ + + ]: 32 : if (strlen(error))
1738 : 4 : pg_log_info("%s", error);
1739 : :
1740 : 32 : CheckConnection();
1741 : :
1742 : 32 : SetPipelineVariables();
1743 : :
1744 : 32 : return -1;
1745 : : }
1746 : :
1747 [ + + + - : 521933 : if (pset.requested_results == 0 && !end_pipeline &&
+ + ]
1748 : 260802 : PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1749 : : {
1750 : : /*
1751 : : * We are in a pipeline and have not reached the pipeline end, or
1752 : : * there was no request to read pipeline results. Update the psql
1753 : : * variables tracking the pipeline activity and exit.
1754 : : */
1755 : 961 : SetPipelineVariables();
1756 : 961 : return 1;
1757 : : }
1758 : :
1759 : : /*
1760 : : * Fetch the result in chunks if FETCH_COUNT is set, except when:
1761 : : *
1762 : : * * SHOW_ALL_RESULTS is false, since that requires us to complete the
1763 : : * query before we can tell if its results should be displayed.
1764 : : *
1765 : : * * We're doing \crosstab, which likewise needs to see all the rows at
1766 : : * once.
1767 : : *
1768 : : * * We're doing \gexec: we must complete the data fetch to make the
1769 : : * connection free for issuing the resulting commands.
1770 : : *
1771 : : * * We're doing \gset: only one result row is allowed anyway.
1772 : : *
1773 : : * * We're doing \watch: users probably don't want us to force use of the
1774 : : * pager for that, plus chunking could break the min_rows check.
1775 : : */
1776 [ + + + - ]: 260170 : if (pset.fetch_count > 0 && pset.show_all_results &&
1777 [ + - + + ]: 89 : !pset.crosstab_flag && !pset.gexec_flag &&
1778 [ + + + - ]: 85 : !pset.gset_prefix && !is_watch)
1779 : : {
1780 [ + + ]: 69 : if (!PQsetChunkedRowsMode(pset.db, pset.fetch_count))
1781 : 4 : pg_log_warning("fetching results in chunked mode failed");
1782 : : }
1783 : :
1784 : : /*
1785 : : * If SIGINT is sent while the query is processing, the interrupt will be
1786 : : * consumed. The user's intention, though, is to cancel the entire watch
1787 : : * process, so detect a sent cancellation request and exit in this case.
1788 : : */
1789 [ + + - + ]: 260170 : if (is_watch && cancel_pressed)
1790 : : {
1791 : 0 : ClearOrSaveAllResults();
1792 : 0 : return 0;
1793 : : }
1794 : :
1795 : : /*
1796 : : * If the caller didn't count the number of COPY FROM STDIN command(s) in
1797 : : * the query string, we must do so now.
1798 : : */
1799 [ + + ]: 260170 : if (num_copy_from_stdin < 0)
1800 : : {
1801 : : PsqlScanState scan_state;
1802 : : PQExpBuffer query_buf;
1803 : : promptStatus_t prompt_tmp;
1804 : : PsqlScanResult scan_result;
1805 : :
1806 : 2231 : scan_state = psql_scan_create(&psqlscan_callbacks);
1807 : 2231 : psql_scan_setup(scan_state, query, strlen(query),
1808 : 2231 : pset.encoding, standard_strings());
1809 : 2231 : query_buf = createPQExpBuffer();
1810 : :
1811 : : /*
1812 : : * A semicolon ends only one sub-command; keep scanning so that COPY
1813 : : * FROM STDIN commands past the first semicolon are counted too. The
1814 : : * count accumulates in scan_state across the psql_scan() calls.
1815 : : */
1816 : : do
1817 : : {
1818 : 3063 : scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
1819 [ + + ]: 3063 : } while (scan_result == PSCAN_SEMICOLON);
1820 : :
1821 : : /*
1822 : : * We expect the result now to be PSCAN_EOL. If it is PSCAN_BACKSLASH
1823 : : * or PSCAN_INCOMPLETE, the server will get a parse error and refuse
1824 : : * to execute any part of the command string, so don't expect any
1825 : : * PGRES_COPY_IN results. (This will mean that we don't attempt to
1826 : : * discard any following data, but this seems consistent with the
1827 : : * general contract of psql_scan_count_copy_from_stdin, which is that
1828 : : * it only promises to count syntactically-valid COPY commands.)
1829 : : */
1830 [ + + ]: 2231 : if (scan_result == PSCAN_EOL)
1831 : 2214 : num_copy_from_stdin = psql_scan_count_copy_from_stdin(scan_state);
1832 : : else
1833 : 17 : num_copy_from_stdin = 0;
1834 : :
1835 : 2231 : destroyPQExpBuffer(query_buf);
1836 : 2231 : psql_scan_destroy(scan_state);
1837 : : }
1838 : :
1839 : : /* first result */
1840 : 260170 : result = PQgetResult(pset.db);
1841 [ + + + - ]: 260170 : if (min_rows > 0 && PQntuples(result) < min_rows)
1842 : : {
1843 : 1 : return_early = true;
1844 : : }
1845 : :
1846 [ + + ]: 521854 : while (result != NULL)
1847 : : {
1848 : : ExecStatusType result_status;
1849 : 261700 : bool is_chunked_result = false;
1850 : 261700 : PGresult *next_result = NULL;
1851 : : bool last;
1852 : :
1853 [ + + ]: 261700 : if (!AcceptResult(result, false))
1854 : 31032 : {
1855 : : /*
1856 : : * Some error occurred, either a server-side failure or a failure
1857 : : * to submit the command string. Record that.
1858 : : */
1859 : 31044 : const char *error = PQresultErrorMessage(result);
1860 : :
1861 [ + + ]: 31044 : if (strlen(error))
1862 : 31023 : pg_log_info("%s", error);
1863 : :
1864 : 31044 : CheckConnection();
1865 [ + + ]: 31032 : if (!is_watch)
1866 : 31030 : SetResultVariables(result, false);
1867 : :
1868 : : /* keep the result status before clearing it */
1869 : 31032 : result_status = PQresultStatus(result);
1870 : 31032 : ClearOrSaveResult(result);
1871 : 31032 : success = false;
1872 : :
1873 [ + + ]: 31032 : if (result_status == PGRES_PIPELINE_ABORTED)
1874 : 20 : pg_log_info("Pipeline aborted, command did not run");
1875 : :
1876 : : /*
1877 : : * switch to next result
1878 : : */
1879 [ + + + - ]: 31032 : if (result_status == PGRES_COPY_BOTH ||
1880 [ - + ]: 31031 : result_status == PGRES_COPY_OUT ||
1881 : : result_status == PGRES_COPY_IN)
1882 : : {
1883 : : /*
1884 : : * For some obscure reason PQgetResult does *not* return a
1885 : : * NULL in copy cases despite the result having been cleared,
1886 : : * but keeps returning an "empty" result that we have to
1887 : : * ignore manually.
1888 : : */
1889 : 1 : result = NULL;
1890 : : }
1891 [ + + + + ]: 31031 : else if ((end_pipeline || pset.requested_results > 0)
1892 [ + - ]: 108 : && PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1893 : : {
1894 : : /*
1895 : : * Error within a pipeline. All commands are aborted until
1896 : : * the next synchronisation point. We need to consume all the
1897 : : * results until this synchronisation point, or stop when
1898 : : * there are no more result to discard.
1899 : : *
1900 : : * Checking the pipeline status is necessary for the case
1901 : : * where the connection was reset. The new connection is not
1902 : : * in any kind of pipeline state and thus has no result to
1903 : : * discard.
1904 : : */
1905 : 108 : result = discardAbortedPipelineResults();
1906 : : }
1907 : : else
1908 : 30923 : result = PQgetResult(pset.db);
1909 : :
1910 : : /*
1911 : : * Get current timing measure in case an error occurs
1912 : : */
1913 [ + + ]: 31032 : if (timing)
1914 : : {
1915 : 1 : INSTR_TIME_SET_CURRENT(after);
1916 : 1 : INSTR_TIME_SUBTRACT(after, before);
1917 : 1 : *elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
1918 : : }
1919 : :
1920 : 31032 : continue;
1921 : : }
1922 [ + + + + ]: 230656 : else if (svpt_gone_p && !*svpt_gone_p)
1923 : : {
1924 : : /*
1925 : : * Check if the user ran any command that would destroy our
1926 : : * internal savepoint: If the user did COMMIT AND CHAIN, RELEASE
1927 : : * or ROLLBACK, our savepoint is gone. If they issued a SAVEPOINT,
1928 : : * releasing ours would remove theirs.
1929 : : */
1930 : 230470 : const char *cmd = PQcmdStatus(result);
1931 : :
1932 : 687428 : *svpt_gone_p = (strcmp(cmd, "COMMIT") == 0 ||
1933 [ + + ]: 226488 : strcmp(cmd, "SAVEPOINT") == 0 ||
1934 [ + + + + ]: 682561 : strcmp(cmd, "RELEASE") == 0 ||
1935 [ + + ]: 456073 : strcmp(cmd, "ROLLBACK") == 0);
1936 : : }
1937 : :
1938 : 230656 : result_status = PQresultStatus(result);
1939 : :
1940 : : /* must handle COPY before changing the current result */
1941 : : Assert(result_status != PGRES_COPY_BOTH);
1942 [ + + + + ]: 230656 : if (result_status == PGRES_COPY_IN ||
1943 : : result_status == PGRES_COPY_OUT)
1944 : : {
1945 : 1186 : FILE *copy_stream = NULL;
1946 : :
1947 [ + + ]: 1186 : if (PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
1948 : : {
1949 : : /*
1950 : : * Running COPY within a pipeline can break the protocol
1951 : : * synchronisation in multiple ways, and psql shows its limits
1952 : : * when it comes to tracking this information.
1953 : : *
1954 : : * While in COPY mode, the backend process ignores additional
1955 : : * Sync messages and will not send the matching ReadyForQuery
1956 : : * expected by the frontend.
1957 : : *
1958 : : * Additionally, libpq automatically sends a Sync with the
1959 : : * Copy message, creating an unexpected synchronisation point.
1960 : : * A failure during COPY would leave the pipeline in an
1961 : : * aborted state while the backend would be in a clean state,
1962 : : * ready to process commands.
1963 : : *
1964 : : * Improving those issues would require modifications in how
1965 : : * libpq handles pipelines and COPY. Hence, for the time
1966 : : * being, we forbid the use of COPY within a pipeline,
1967 : : * aborting the connection to avoid an inconsistent state on
1968 : : * psql side if trying to use a COPY command.
1969 : : */
1970 : 4 : pg_log_info("COPY in a pipeline is not supported, aborting connection");
1971 : 4 : exit(EXIT_BADCONN);
1972 : : }
1973 : :
1974 : : /* Select data source or sink. */
1975 [ + + ]: 1182 : if (result_status == PGRES_COPY_OUT)
1976 : : {
1977 : : /*
1978 : : * For COPY OUT, direct the output to the default place
1979 : : * (probably a pager pipe) for \watch, or to pset.copyStream
1980 : : * for \copy, otherwise to pset.gfname if that's set,
1981 : : * otherwise to pset.queryFout.
1982 : : */
1983 [ - + ]: 501 : if (is_watch)
1984 : : {
1985 : : /* invoked by \watch */
1986 [ # # ]: 0 : copy_stream = printQueryFout ? printQueryFout : pset.queryFout;
1987 : : }
1988 [ + + ]: 501 : else if (pset.copyStream)
1989 : : {
1990 : : /* invoked by \copy */
1991 : 36 : copy_stream = pset.copyStream;
1992 : : }
1993 [ + + ]: 465 : else if (pset.gfname)
1994 : : {
1995 : : /* COPY followed by \g filename or \g |program */
1996 : 17 : success &= SetupGOutput(&gfile_fout, &gfile_is_pipe);
1997 [ + - ]: 17 : if (gfile_fout)
1998 : 17 : copy_stream = gfile_fout;
1999 : : }
2000 : : else
2001 : : {
2002 : : /* fall back to the generic query output stream */
2003 : 448 : copy_stream = pset.queryFout;
2004 : : }
2005 : : }
2006 : : else
2007 : : {
2008 [ - + ]: 681 : if (num_copy_from_stdin <= 0)
2009 : : {
2010 : : /*
2011 : : * We didn't send a COPY FROM STDIN command. The server
2012 : : * is broken or possibly malicious. Report and quit. (We
2013 : : * could instead send an empty COPY response, but it's not
2014 : : * clear that that's a better behavior; it would make it
2015 : : * harder to diagnose any such problem.)
2016 : : */
2017 : 0 : pg_log_info("unexpected COPY_IN result, aborting connection");
2018 : 0 : exit(EXIT_BADCONN);
2019 : : }
2020 : : /* Keep track of the number of remaining copy operations */
2021 : 681 : num_copy_from_stdin--;
2022 : :
2023 : : /*
2024 : : * For COPY IN, read from pset.copyStream if \copy set that,
2025 : : * otherwise from the current command source.
2026 : : */
2027 [ + + ]: 681 : if (pset.copyStream)
2028 : 47 : copy_stream = pset.copyStream;
2029 : : else
2030 : 634 : copy_stream = pset.cur_cmd_source;
2031 : : }
2032 : :
2033 : : /*
2034 : : * Even if the output stream could not be opened, we call
2035 : : * HandleCopyResult() with a NULL output stream to collect and
2036 : : * discard the COPY data.
2037 : : */
2038 : 1182 : success &= HandleCopyResult(&result, copy_stream);
2039 : : }
2040 : :
2041 : : /* If we have a chunked result, collect and print all chunks */
2042 [ + + ]: 230652 : if (result_status == PGRES_TUPLES_CHUNK)
2043 : : {
2044 [ + - ]: 44 : FILE *tuples_fout = printQueryFout ? printQueryFout : pset.queryFout;
2045 [ - + ]: 44 : printQueryOpt my_popt = opt ? *opt : pset.popt;
2046 : 44 : int64 total_tuples = 0;
2047 : 44 : bool is_pager = false;
2048 : 44 : int flush_error = 0;
2049 : :
2050 : : /* initialize print options for partial table output */
2051 : 44 : my_popt.topt.start_table = true;
2052 : 44 : my_popt.topt.stop_table = false;
2053 : 44 : my_popt.topt.prior_records = 0;
2054 : :
2055 : : /* open \g file if needed */
2056 : 44 : success &= SetupGOutput(&gfile_fout, &gfile_is_pipe);
2057 [ - + ]: 44 : if (gfile_fout)
2058 : 0 : tuples_fout = gfile_fout;
2059 : :
2060 : : /* force use of pager for any chunked resultset going to stdout */
2061 [ + - + - ]: 44 : if (success && tuples_fout == stdout)
2062 : : {
2063 : 44 : tuples_fout = PageOutput(INT_MAX, &(my_popt.topt));
2064 : 44 : is_pager = true;
2065 : : }
2066 : :
2067 : : do
2068 : : {
2069 : : /*
2070 : : * Display the current chunk of results, unless the output
2071 : : * stream stopped working or we got canceled. We skip use of
2072 : : * PrintQueryResult and go directly to printQuery, so that we
2073 : : * can pass the correct is_pager value and because we don't
2074 : : * want PrintQueryStatus to happen yet. Above, we rejected
2075 : : * use of chunking for all cases in which PrintQueryResult
2076 : : * would send the result to someplace other than printQuery.
2077 : : */
2078 [ + - + - : 60 : if (success && !flush_error && !cancel_pressed)
+ - ]
2079 : : {
2080 : 60 : printQuery(result, &my_popt, tuples_fout, is_pager, pset.logfile);
2081 : 60 : flush_error = fflush(tuples_fout);
2082 : : }
2083 : :
2084 : : /* after the first result set, disallow header decoration */
2085 : 60 : my_popt.topt.start_table = false;
2086 : :
2087 : : /* count tuples before dropping the result */
2088 : 60 : my_popt.topt.prior_records += PQntuples(result);
2089 : 60 : total_tuples += PQntuples(result);
2090 : :
2091 : 60 : ClearOrSaveResult(result);
2092 : :
2093 : : /* get the next result, loop if it's PGRES_TUPLES_CHUNK */
2094 : 60 : result = PQgetResult(pset.db);
2095 [ + + ]: 60 : } while (PQresultStatus(result) == PGRES_TUPLES_CHUNK);
2096 : :
2097 : : /* We expect an empty PGRES_TUPLES_OK, else there's a problem */
2098 [ + + ]: 44 : if (PQresultStatus(result) == PGRES_TUPLES_OK)
2099 : : {
2100 : : char buf[32];
2101 : :
2102 : : Assert(PQntuples(result) == 0);
2103 : :
2104 : : /* Display the footer using the empty result */
2105 [ + - + - : 40 : if (success && !flush_error && !cancel_pressed)
+ - ]
2106 : : {
2107 : 40 : my_popt.topt.stop_table = true;
2108 : 40 : printQuery(result, &my_popt, tuples_fout, is_pager, pset.logfile);
2109 : 40 : fflush(tuples_fout);
2110 : : }
2111 : :
2112 [ + - ]: 40 : if (is_pager)
2113 : 40 : ClosePager(tuples_fout);
2114 : :
2115 : : /*
2116 : : * It's possible the data is from a RETURNING clause, in which
2117 : : * case we need to print query status.
2118 : : */
2119 : 40 : PrintQueryStatus(result, printQueryFout);
2120 : :
2121 : : /*
2122 : : * We must do a fake SetResultVariables(), since we don't have
2123 : : * a PGresult corresponding to the whole query.
2124 : : */
2125 : 40 : SetVariable(pset.vars, "ERROR", "false");
2126 : 40 : SetVariable(pset.vars, "SQLSTATE", "00000");
2127 : 40 : snprintf(buf, sizeof(buf), INT64_FORMAT, total_tuples);
2128 : 40 : SetVariable(pset.vars, "ROW_COUNT", buf);
2129 : : /* Prevent SetResultVariables call below */
2130 : 40 : is_chunked_result = true;
2131 : :
2132 : : /* Clear the empty result so it isn't printed below */
2133 : 40 : ClearOrSaveResult(result);
2134 : 40 : result = NULL;
2135 : : }
2136 : : else
2137 : : {
2138 : : /* Probably an error report, so close the pager and print it */
2139 [ + - ]: 4 : if (is_pager)
2140 : 4 : ClosePager(tuples_fout);
2141 : :
2142 : 4 : success &= AcceptResult(result, true);
2143 : : /* SetResultVariables and ClearOrSaveResult happen below */
2144 : : }
2145 : : }
2146 : :
2147 [ + + ]: 230652 : if (result_status == PGRES_PIPELINE_SYNC)
2148 : : {
2149 : : /*
2150 : : * Sync response, decrease the sync and requested_results
2151 : : * counters. Guard against underflow: an error during Sync
2152 : : * processing on the server can cause the client-side counter to
2153 : : * drift.
2154 : : */
2155 [ + - ]: 289 : if (pset.piped_syncs > 0)
2156 : 289 : pset.piped_syncs--;
2157 [ + - ]: 289 : if (pset.requested_results > 0)
2158 : 289 : pset.requested_results--;
2159 : :
2160 : : /*
2161 : : * After a synchronisation point, reset success state to print
2162 : : * possible successful results that will be processed after this.
2163 : : */
2164 : 289 : success = true;
2165 : :
2166 : : /*
2167 : : * If all syncs were processed and pipeline end was requested,
2168 : : * exit pipeline mode.
2169 : : */
2170 [ + + + + ]: 289 : if (end_pipeline && pset.piped_syncs == 0)
2171 : 197 : success &= PQexitPipelineMode(pset.db);
2172 : : }
2173 [ + + + - ]: 230363 : else if (PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF &&
2174 : : result_status != PGRES_PIPELINE_SYNC)
2175 : : {
2176 : : /*
2177 : : * In a pipeline with a non-sync response? Decrease the result
2178 : : * counters.
2179 : : */
2180 [ + + ]: 442 : if (pset.available_results > 0)
2181 : 438 : pset.available_results--;
2182 [ + - ]: 442 : if (pset.requested_results > 0)
2183 : 442 : pset.requested_results--;
2184 : : }
2185 : :
2186 : : /*
2187 : : * Check PQgetResult() again. In the typical case of a single-command
2188 : : * string, it will return NULL. Otherwise, we'll have other results
2189 : : * to process. We need to do that to check whether this is the last.
2190 : : */
2191 [ + + ]: 230652 : if (PQpipelineStatus(pset.db) == PQ_PIPELINE_OFF)
2192 : 230118 : next_result = PQgetResult(pset.db);
2193 : : else
2194 : : {
2195 : : /*
2196 : : * In pipeline mode, a NULL result indicates the end of the
2197 : : * current query being processed. Call PQgetResult() once to
2198 : : * consume this state.
2199 : : */
2200 [ + + ]: 534 : if (result_status != PGRES_PIPELINE_SYNC)
2201 : : {
2202 : 442 : next_result = PQgetResult(pset.db);
2203 : : Assert(next_result == NULL);
2204 : : }
2205 : :
2206 : : /* Now, we can get the next result in the pipeline. */
2207 [ + + ]: 534 : if (pset.requested_results > 0)
2208 : 462 : next_result = PQgetResult(pset.db);
2209 : : }
2210 : :
2211 : 230652 : last = (next_result == NULL);
2212 : :
2213 : : /*
2214 : : * Update current timing measure.
2215 : : *
2216 : : * It will include the display of previous results, if any. This
2217 : : * cannot be helped because the server goes on processing further
2218 : : * queries anyway while the previous ones are being displayed. The
2219 : : * parallel execution of the client display hides the server time when
2220 : : * it is shorter.
2221 : : *
2222 : : * With combined queries, timing must be understood as an upper bound
2223 : : * of the time spent processing them.
2224 : : */
2225 [ + + ]: 230652 : if (timing)
2226 : : {
2227 : 1 : INSTR_TIME_SET_CURRENT(after);
2228 : 1 : INSTR_TIME_SUBTRACT(after, before);
2229 : 1 : *elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
2230 : : }
2231 : :
2232 : : /*
2233 : : * This may or may not print something depending on settings.
2234 : : *
2235 : : * A pipeline sync will have a non-NULL result but does not have
2236 : : * anything to print, thus ignore results in this case.
2237 : : */
2238 [ + + + + ]: 230652 : if (result != NULL && result_status != PGRES_PIPELINE_SYNC)
2239 : : {
2240 : : /*
2241 : : * If results need to be printed into the file specified by \g,
2242 : : * open it, unless we already did. Note that when pset.gfname is
2243 : : * set, the passed-in value of printQueryFout is not used for
2244 : : * tuple output, but it's still used for status output.
2245 : : */
2246 : 229839 : FILE *tuples_fout = printQueryFout;
2247 : :
2248 [ + + ]: 229839 : if (PQresultStatus(result) == PGRES_TUPLES_OK)
2249 : 97774 : success &= SetupGOutput(&gfile_fout, &gfile_is_pipe);
2250 [ + + ]: 229839 : if (gfile_fout)
2251 : 38 : tuples_fout = gfile_fout;
2252 [ + + ]: 229839 : if (success)
2253 : 229662 : success &= PrintQueryResult(result, last, opt,
2254 : : tuples_fout, printQueryFout);
2255 : : }
2256 : :
2257 : : /* set variables from last result, unless dealt with elsewhere */
2258 [ + + + + : 230652 : if (last && !is_watch && !is_chunked_result)
+ + ]
2259 : 229015 : SetResultVariables(result, success);
2260 : :
2261 : 230652 : ClearOrSaveResult(result);
2262 : 230652 : result = next_result;
2263 : :
2264 [ - + - - ]: 230652 : if (cancel_pressed && PQpipelineStatus(pset.db) == PQ_PIPELINE_OFF)
2265 : : {
2266 : : /*
2267 : : * Outside of a pipeline, drop the next result, as well as any
2268 : : * others not yet read.
2269 : : *
2270 : : * Within a pipeline, we can let the outer loop handle this as an
2271 : : * aborted pipeline, which will discard then all the results.
2272 : : */
2273 : 0 : ClearOrSaveResult(result);
2274 : 0 : ClearOrSaveAllResults();
2275 : 0 : break;
2276 : : }
2277 : : }
2278 : :
2279 : : /* close \g file if we opened it */
2280 : 260154 : CloseGOutput(gfile_fout, gfile_is_pipe);
2281 : :
2282 [ + + ]: 260154 : if (end_pipeline)
2283 : : {
2284 : : /*
2285 : : * Reset available/requested results. Normally these are already 0,
2286 : : * but an error generated by a Sync processing itself can leave some
2287 : : * of them behind. Consume them before exiting pipeline mode.
2288 : : */
2289 [ + + ]: 237 : while (pset.piped_syncs > 0)
2290 : : {
2291 : : PGresult *remaining;
2292 : :
2293 : 20 : remaining = PQgetResult(pset.db);
2294 : :
2295 [ - + ]: 20 : if (remaining == NULL)
2296 : : {
2297 [ # # ]: 0 : if (!ConnectionUp())
2298 : 0 : break;
2299 : 0 : continue;
2300 : : }
2301 [ + - ]: 20 : if (PQresultStatus(remaining) == PGRES_PIPELINE_SYNC)
2302 : 20 : pset.piped_syncs--;
2303 : 20 : PQclear(remaining);
2304 : : }
2305 : 217 : pset.piped_syncs = 0;
2306 : 217 : pset.piped_commands = 0;
2307 : 217 : pset.available_results = 0;
2308 : 217 : pset.requested_results = 0;
2309 : :
2310 [ + + ]: 217 : if (PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF)
2311 : 20 : PQexitPipelineMode(pset.db);
2312 : : }
2313 : : Assert(pset.requested_results == 0);
2314 : :
2315 : 260154 : SetPipelineVariables();
2316 : :
2317 : : /* may need this to recover from conn loss during COPY */
2318 [ - + ]: 260154 : if (!CheckConnection())
2319 : 0 : return -1;
2320 : :
2321 : : /*
2322 : : * If we were expecting COPY ... FROM STDIN, and we didn't get
2323 : : * PGRES_COPY_IN (presumably because the COPY failed server-side), and the
2324 : : * data is supposed to come from the current command source, we must eat
2325 : : * up the data in order to stay in sync with the command file's contents.
2326 : : * Repeat for the number of unfulfilled COPY commands.
2327 : : */
2328 [ + + ]: 260459 : while (num_copy_from_stdin > 0)
2329 : : {
2330 [ + + ]: 305 : if (pset.copyStream == NULL ||
2331 [ + + ]: 5 : pset.copyStream == pset.cur_cmd_source)
2332 : 304 : (void) handleCopyIn(NULL, /* no connection */
2333 : : pset.cur_cmd_source,
2334 : : false, /* XXX assume not binary */
2335 : : NULL); /* no result */
2336 : 305 : num_copy_from_stdin--;
2337 : : }
2338 : :
2339 [ + + + + ]: 260154 : if (cancel_pressed || return_early)
2340 : 2 : return 0;
2341 : :
2342 [ + + ]: 260152 : return success ? 1 : -1;
2343 : : }
2344 : :
2345 : :
2346 : : /*
2347 : : * Advance the given char pointer over white space and SQL comments.
2348 : : */
2349 : : static const char *
2350 : 72 : skip_white_space(const char *query)
2351 : : {
2352 : 72 : int cnestlevel = 0; /* slash-star comment nest level */
2353 : :
2354 [ + - ]: 88 : while (*query)
2355 : : {
2356 : 88 : int mblen = PQmblenBounded(query, pset.encoding);
2357 : :
2358 : : /*
2359 : : * Note: we assume the encoding is a superset of ASCII, so that for
2360 : : * example "query[0] == '/'" is meaningful. However, we do NOT assume
2361 : : * that the second and subsequent bytes of a multibyte character
2362 : : * couldn't look like ASCII characters; so it is critical to advance
2363 : : * by mblen, not 1, whenever we haven't exactly identified the
2364 : : * character we are skipping over.
2365 : : */
2366 [ + + ]: 88 : if (isspace((unsigned char) *query))
2367 : 16 : query += mblen;
2368 [ - + - - ]: 72 : else if (query[0] == '/' && query[1] == '*')
2369 : : {
2370 : 0 : cnestlevel++;
2371 : 0 : query += 2;
2372 : : }
2373 [ - + - - : 72 : else if (cnestlevel > 0 && query[0] == '*' && query[1] == '/')
- - ]
2374 : : {
2375 : 0 : cnestlevel--;
2376 : 0 : query += 2;
2377 : : }
2378 [ + - - + : 72 : else if (cnestlevel == 0 && query[0] == '-' && query[1] == '-')
- - ]
2379 : : {
2380 : 0 : query += 2;
2381 : :
2382 : : /*
2383 : : * We have to skip to end of line since any slash-star inside the
2384 : : * -- comment does NOT start a slash-star comment.
2385 : : */
2386 [ # # ]: 0 : while (*query)
2387 : : {
2388 [ # # ]: 0 : if (*query == '\n')
2389 : : {
2390 : 0 : query++;
2391 : 0 : break;
2392 : : }
2393 : 0 : query += PQmblenBounded(query, pset.encoding);
2394 : : }
2395 : : }
2396 [ - + ]: 72 : else if (cnestlevel > 0)
2397 : 0 : query += mblen;
2398 : : else
2399 : 72 : break; /* found first token */
2400 : : }
2401 : :
2402 : 72 : return query;
2403 : : }
2404 : :
2405 : :
2406 : : /*
2407 : : * Check whether a command is one of those for which we should NOT start
2408 : : * a new transaction block (ie, send a preceding BEGIN).
2409 : : *
2410 : : * These include the transaction control statements themselves, plus
2411 : : * certain statements that the backend disallows inside transaction blocks.
2412 : : */
2413 : : static bool
2414 : 56 : command_no_begin(const char *query)
2415 : : {
2416 : : int wordlen;
2417 : :
2418 : : /*
2419 : : * First we must advance over any whitespace and comments.
2420 : : */
2421 : 56 : query = skip_white_space(query);
2422 : :
2423 : : /*
2424 : : * Check word length (since "beginx" is not "begin").
2425 : : */
2426 : 56 : wordlen = 0;
2427 [ + + ]: 376 : while (isalpha((unsigned char) query[wordlen]))
2428 : 320 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2429 : :
2430 : : /*
2431 : : * Transaction control commands. These should include every keyword that
2432 : : * gives rise to a TransactionStmt in the backend grammar, except for the
2433 : : * savepoint-related commands.
2434 : : *
2435 : : * (We assume that START must be START TRANSACTION, since there is
2436 : : * presently no other "START foo" command.)
2437 : : */
2438 [ + + - + ]: 56 : if (wordlen == 5 && pg_strncasecmp(query, "abort", 5) == 0)
2439 : 0 : return true;
2440 [ + + + - ]: 56 : if (wordlen == 5 && pg_strncasecmp(query, "begin", 5) == 0)
2441 : 8 : return true;
2442 [ - + - - ]: 48 : if (wordlen == 5 && pg_strncasecmp(query, "start", 5) == 0)
2443 : 0 : return true;
2444 [ + + - + ]: 48 : if (wordlen == 6 && pg_strncasecmp(query, "commit", 6) == 0)
2445 : 0 : return true;
2446 [ - + - - ]: 48 : if (wordlen == 3 && pg_strncasecmp(query, "end", 3) == 0)
2447 : 0 : return true;
2448 [ - + - - ]: 48 : if (wordlen == 8 && pg_strncasecmp(query, "rollback", 8) == 0)
2449 : 0 : return true;
2450 [ - + - - ]: 48 : if (wordlen == 7 && pg_strncasecmp(query, "prepare", 7) == 0)
2451 : : {
2452 : : /* PREPARE TRANSACTION is a TC command, PREPARE foo is not */
2453 : 0 : query += wordlen;
2454 : :
2455 : 0 : query = skip_white_space(query);
2456 : :
2457 : 0 : wordlen = 0;
2458 [ # # ]: 0 : while (isalpha((unsigned char) query[wordlen]))
2459 : 0 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2460 : :
2461 [ # # # # ]: 0 : if (wordlen == 11 && pg_strncasecmp(query, "transaction", 11) == 0)
2462 : 0 : return true;
2463 : 0 : return false;
2464 : : }
2465 : :
2466 : : /*
2467 : : * Commands not allowed within transactions. The statements checked for
2468 : : * here should be exactly those that call PreventInTransactionBlock() in
2469 : : * the backend.
2470 : : */
2471 [ + + - + ]: 48 : if (wordlen == 6 && pg_strncasecmp(query, "vacuum", 6) == 0)
2472 : 0 : return true;
2473 [ - + - - ]: 48 : if (wordlen == 7 && pg_strncasecmp(query, "cluster", 7) == 0)
2474 : : {
2475 : : /* CLUSTER with any arguments is allowed in transactions */
2476 : 0 : query += wordlen;
2477 : :
2478 : 0 : query = skip_white_space(query);
2479 : :
2480 [ # # ]: 0 : if (isalpha((unsigned char) query[0]))
2481 : 0 : return false; /* has additional words */
2482 : 0 : return true; /* it's CLUSTER without arguments */
2483 : : }
2484 : :
2485 [ + + + + ]: 48 : if (wordlen == 6 && pg_strncasecmp(query, "create", 6) == 0)
2486 : : {
2487 : 8 : query += wordlen;
2488 : :
2489 : 8 : query = skip_white_space(query);
2490 : :
2491 : 8 : wordlen = 0;
2492 [ + + ]: 48 : while (isalpha((unsigned char) query[wordlen]))
2493 : 40 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2494 : :
2495 [ - + - - ]: 8 : if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
2496 : 0 : return true;
2497 [ - + - - ]: 8 : if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
2498 : 0 : return true;
2499 : :
2500 : : /* CREATE [UNIQUE] INDEX CONCURRENTLY isn't allowed in xacts */
2501 [ - + - - ]: 8 : if (wordlen == 6 && pg_strncasecmp(query, "unique", 6) == 0)
2502 : : {
2503 : 0 : query += wordlen;
2504 : :
2505 : 0 : query = skip_white_space(query);
2506 : :
2507 : 0 : wordlen = 0;
2508 [ # # ]: 0 : while (isalpha((unsigned char) query[wordlen]))
2509 : 0 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2510 : : }
2511 : :
2512 [ + - - + ]: 8 : if (wordlen == 5 && pg_strncasecmp(query, "index", 5) == 0)
2513 : : {
2514 : 0 : query += wordlen;
2515 : :
2516 : 0 : query = skip_white_space(query);
2517 : :
2518 : 0 : wordlen = 0;
2519 [ # # ]: 0 : while (isalpha((unsigned char) query[wordlen]))
2520 : 0 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2521 : :
2522 [ # # # # ]: 0 : if (wordlen == 12 && pg_strncasecmp(query, "concurrently", 12) == 0)
2523 : 0 : return true;
2524 : : }
2525 : :
2526 : 8 : return false;
2527 : : }
2528 : :
2529 [ - + - - ]: 40 : if (wordlen == 5 && pg_strncasecmp(query, "alter", 5) == 0)
2530 : : {
2531 : 0 : query += wordlen;
2532 : :
2533 : 0 : query = skip_white_space(query);
2534 : :
2535 : 0 : wordlen = 0;
2536 [ # # ]: 0 : while (isalpha((unsigned char) query[wordlen]))
2537 : 0 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2538 : :
2539 : : /* ALTER SYSTEM isn't allowed in xacts */
2540 [ # # # # ]: 0 : if (wordlen == 6 && pg_strncasecmp(query, "system", 6) == 0)
2541 : 0 : return true;
2542 : :
2543 : 0 : return false;
2544 : : }
2545 : :
2546 : : /*
2547 : : * Note: these tests will match DROP SYSTEM and REINDEX TABLESPACE, which
2548 : : * aren't really valid commands so we don't care much. The other four
2549 : : * possible matches are correct.
2550 : : */
2551 [ + + - + : 40 : if ((wordlen == 4 && pg_strncasecmp(query, "drop", 4) == 0) ||
- + ]
2552 [ # # ]: 0 : (wordlen == 7 && pg_strncasecmp(query, "reindex", 7) == 0))
2553 : : {
2554 : 4 : query += wordlen;
2555 : :
2556 : 4 : query = skip_white_space(query);
2557 : :
2558 : 4 : wordlen = 0;
2559 [ + + ]: 24 : while (isalpha((unsigned char) query[wordlen]))
2560 : 20 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2561 : :
2562 [ - + - - ]: 4 : if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
2563 : 0 : return true;
2564 [ - + - - ]: 4 : if (wordlen == 6 && pg_strncasecmp(query, "system", 6) == 0)
2565 : 0 : return true;
2566 [ - + - - ]: 4 : if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
2567 : 0 : return true;
2568 [ + - + - : 8 : if (wordlen == 5 && (pg_strncasecmp(query, "index", 5) == 0 ||
+ - ]
2569 : 4 : pg_strncasecmp(query, "table", 5) == 0))
2570 : : {
2571 : 4 : query += wordlen;
2572 : 4 : query = skip_white_space(query);
2573 : 4 : wordlen = 0;
2574 [ + + ]: 16 : while (isalpha((unsigned char) query[wordlen]))
2575 : 12 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2576 : :
2577 : : /*
2578 : : * REINDEX [ TABLE | INDEX ] CONCURRENTLY are not allowed in
2579 : : * xacts.
2580 : : */
2581 [ - + - - ]: 4 : if (wordlen == 12 && pg_strncasecmp(query, "concurrently", 12) == 0)
2582 : 0 : return true;
2583 : : }
2584 : :
2585 : : /* DROP INDEX CONCURRENTLY isn't allowed in xacts */
2586 [ - + - - ]: 4 : if (wordlen == 5 && pg_strncasecmp(query, "index", 5) == 0)
2587 : : {
2588 : 0 : query += wordlen;
2589 : :
2590 : 0 : query = skip_white_space(query);
2591 : :
2592 : 0 : wordlen = 0;
2593 [ # # ]: 0 : while (isalpha((unsigned char) query[wordlen]))
2594 : 0 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2595 : :
2596 [ # # # # ]: 0 : if (wordlen == 12 && pg_strncasecmp(query, "concurrently", 12) == 0)
2597 : 0 : return true;
2598 : :
2599 : 0 : return false;
2600 : : }
2601 : :
2602 : 4 : return false;
2603 : : }
2604 : :
2605 : : /* DISCARD ALL isn't allowed in xacts, but other variants are allowed. */
2606 [ - + - - ]: 36 : if (wordlen == 7 && pg_strncasecmp(query, "discard", 7) == 0)
2607 : : {
2608 : 0 : query += wordlen;
2609 : :
2610 : 0 : query = skip_white_space(query);
2611 : :
2612 : 0 : wordlen = 0;
2613 [ # # ]: 0 : while (isalpha((unsigned char) query[wordlen]))
2614 : 0 : wordlen += PQmblenBounded(&query[wordlen], pset.encoding);
2615 : :
2616 [ # # # # ]: 0 : if (wordlen == 3 && pg_strncasecmp(query, "all", 3) == 0)
2617 : 0 : return true;
2618 : 0 : return false;
2619 : : }
2620 : :
2621 : 36 : return false;
2622 : : }
2623 : :
2624 : :
2625 : : /*
2626 : : * addQueryComment
2627 : : *
2628 : : * Reset buf and insert a comment holding label. The comment will show up
2629 : : * in -E output and in the server log.
2630 : : *
2631 : : * If it's safe, we attempt to translate the label string.
2632 : : * (addQueryComment is marked as a gettext trigger, so this requires no
2633 : : * special effort at call sites.)
2634 : : */
2635 : : void
2636 : 31595 : addQueryComment(PQExpBuffer buf, const char *label)
2637 : : {
2638 : : #if defined(ENABLE_NLS)
2639 : 31595 : const char *server_enc = PQparameterStatus(pset.db, "server_encoding");
2640 : 31595 : int client_enc = PQclientEncoding(pset.db);
2641 : :
2642 : : /*
2643 : : * We must skip translation if it would cause the server to reject the
2644 : : * query due to an encoding conversion/verification failure. For now it
2645 : : * seems sufficient to handle only the case of equal client and server
2646 : : * encodings: then the server just verifies the string in that encoding,
2647 : : * and we can run the same check here. It's necessary to check for this
2648 : : * because we can't be 100% sure which encoding gettext() thinks it should
2649 : : * produce. If it is indeed different from our client encoding, the
2650 : : * result may look like junk to a human, but it won't cause an error.
2651 : : */
2652 [ + - + - ]: 63190 : if (server_enc != NULL &&
2653 : 31595 : pg_char_to_encoding(server_enc) == client_enc)
2654 : : {
2655 : 31595 : const char *translated = _(label);
2656 : 31595 : int len = strlen(translated);
2657 : :
2658 [ + - ]: 31595 : if (pg_encoding_verifymbstr(client_enc, translated, len) == len)
2659 : 31595 : label = translated;
2660 : : }
2661 : : #endif
2662 : :
2663 : 31595 : printfPQExpBuffer(buf, "/* %s */\n", label);
2664 : 31595 : }
2665 : :
2666 : :
2667 : : /*
2668 : : * Test if the current user is a database superuser.
2669 : : */
2670 : : bool
2671 : 70 : is_superuser(void)
2672 : : {
2673 : : const char *val;
2674 : :
2675 [ - + ]: 70 : if (!pset.db)
2676 : 0 : return false;
2677 : :
2678 : 70 : val = PQparameterStatus(pset.db, "is_superuser");
2679 : :
2680 [ + - + - ]: 70 : if (val && strcmp(val, "on") == 0)
2681 : 70 : return true;
2682 : :
2683 : 0 : return false;
2684 : : }
2685 : :
2686 : :
2687 : : /*
2688 : : * Test if the current session uses standard string literals.
2689 : : */
2690 : : bool
2691 : 542728 : standard_strings(void)
2692 : : {
2693 : : const char *val;
2694 : :
2695 [ - + ]: 542728 : if (!pset.db)
2696 : 0 : return false;
2697 : :
2698 : 542728 : val = PQparameterStatus(pset.db, "standard_conforming_strings");
2699 : :
2700 [ + - + - ]: 542728 : if (val && strcmp(val, "on") == 0)
2701 : 542728 : return true;
2702 : :
2703 : 0 : return false;
2704 : : }
2705 : :
2706 : :
2707 : : /*
2708 : : * Return the session user of the current connection.
2709 : : */
2710 : : const char *
2711 : 0 : session_username(void)
2712 : : {
2713 : : const char *val;
2714 : :
2715 [ # # ]: 0 : if (!pset.db)
2716 : 0 : return NULL;
2717 : :
2718 : 0 : val = PQparameterStatus(pset.db, "session_authorization");
2719 [ # # ]: 0 : if (val)
2720 : 0 : return val;
2721 : : else
2722 : 0 : return PQuser(pset.db);
2723 : : }
2724 : :
2725 : : /*
2726 : : * Return the value of option for keyword in the current connection.
2727 : : *
2728 : : * The caller is responsible for freeing the result value allocated.
2729 : : */
2730 : : char *
2731 : 11469 : get_conninfo_value(const char *keyword)
2732 : : {
2733 : : PQconninfoOption *opts;
2734 : 11469 : PQconninfoOption *serviceopt = NULL;
2735 : 11469 : char *res = NULL;
2736 : :
2737 [ - + ]: 11469 : if (pset.db == NULL)
2738 : 0 : return NULL;
2739 : :
2740 : 11469 : opts = PQconninfo(pset.db);
2741 [ - + ]: 11469 : if (opts == NULL)
2742 : 0 : return NULL;
2743 : :
2744 [ + - ]: 11469 : for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
2745 : : {
2746 [ + - ]: 11469 : if (strcmp(opt->keyword, keyword) == 0)
2747 : : {
2748 : 11469 : serviceopt = opt;
2749 : 11469 : break;
2750 : : }
2751 : : }
2752 : :
2753 : : /* Take a copy of the value, as it is freed by PQconninfoFree(). */
2754 [ + - + + ]: 11469 : if (serviceopt && serviceopt->val != NULL)
2755 : 12 : res = pg_strdup(serviceopt->val);
2756 : 11469 : PQconninfoFree(opts);
2757 : :
2758 : 11469 : return res;
2759 : : }
2760 : :
2761 : : /*
2762 : : * expand_tilde
2763 : : *
2764 : : * substitute '~' with HOME or '~username' with username's home dir
2765 : : *
2766 : : */
2767 : : void
2768 : 107 : expand_tilde(char **filename)
2769 : : {
2770 [ + - + + ]: 107 : if (!filename || !(*filename))
2771 : 12 : return;
2772 : :
2773 : : /*
2774 : : * WIN32 doesn't use tilde expansion for file names. Also, it uses tilde
2775 : : * for short versions of long file names, though the tilde is usually
2776 : : * toward the end, not at the beginning.
2777 : : */
2778 : : #ifndef WIN32
2779 : :
2780 : : /* try tilde expansion */
2781 [ - + ]: 95 : if (**filename == '~')
2782 : : {
2783 : : char *fn;
2784 : : char oldp,
2785 : : *p;
2786 : : struct passwd *pw;
2787 : : char home[MAXPGPATH];
2788 : :
2789 : 0 : fn = *filename;
2790 : 0 : *home = '\0';
2791 : :
2792 : 0 : p = fn + 1;
2793 [ # # # # ]: 0 : while (*p != '/' && *p != '\0')
2794 : 0 : p++;
2795 : :
2796 : 0 : oldp = *p;
2797 : 0 : *p = '\0';
2798 : :
2799 [ # # ]: 0 : if (*(fn + 1) == '\0')
2800 : 0 : get_home_path(home); /* ~ or ~/ only */
2801 [ # # ]: 0 : else if ((pw = getpwnam(fn + 1)) != NULL)
2802 : 0 : strlcpy(home, pw->pw_dir, sizeof(home)); /* ~user */
2803 : :
2804 : 0 : *p = oldp;
2805 [ # # ]: 0 : if (strlen(home) != 0)
2806 : : {
2807 : : char *newfn;
2808 : :
2809 : 0 : newfn = psprintf("%s%s", home, p);
2810 : 0 : free(fn);
2811 : 0 : *filename = newfn;
2812 : : }
2813 : : }
2814 : : #endif
2815 : : }
2816 : :
2817 : : /*
2818 : : * Checks if connection string starts with either of the valid URI prefix
2819 : : * designators.
2820 : : *
2821 : : * Returns the URI prefix length, 0 if the string doesn't contain a URI prefix.
2822 : : *
2823 : : * XXX This is a duplicate of the eponymous libpq function.
2824 : : */
2825 : : static int
2826 : 27 : uri_prefix_length(const char *connstr)
2827 : : {
2828 : : /* The connection URI must start with either of the following designators: */
2829 : : static const char uri_designator[] = "postgresql://";
2830 : : static const char short_uri_designator[] = "postgres://";
2831 : :
2832 [ - + ]: 27 : if (strncmp(connstr, uri_designator,
2833 : : sizeof(uri_designator) - 1) == 0)
2834 : 0 : return sizeof(uri_designator) - 1;
2835 : :
2836 [ - + ]: 27 : if (strncmp(connstr, short_uri_designator,
2837 : : sizeof(short_uri_designator) - 1) == 0)
2838 : 0 : return sizeof(short_uri_designator) - 1;
2839 : :
2840 : 27 : return 0;
2841 : : }
2842 : :
2843 : : /*
2844 : : * Reset state related to extended query protocol
2845 : : *
2846 : : * Clean up any state related to bind parameters, statement name and
2847 : : * PSQL_SEND_MODE. This needs to be called after processing a query or when
2848 : : * running a new meta-command that uses the extended query protocol, like
2849 : : * \parse, \bind, etc.
2850 : : */
2851 : : void
2852 : 261889 : clean_extended_state(void)
2853 : : {
2854 : : int i;
2855 : :
2856 [ + + + + : 261889 : switch (pset.send_mode)
- ]
2857 : : {
2858 : 25 : case PSQL_SEND_EXTENDED_CLOSE: /* \close_prepared */
2859 : 25 : free(pset.stmtName);
2860 : 25 : break;
2861 : 67 : case PSQL_SEND_EXTENDED_PARSE: /* \parse */
2862 : 67 : free(pset.stmtName);
2863 : 67 : break;
2864 : 644 : case PSQL_SEND_EXTENDED_QUERY_PARAMS: /* \bind */
2865 : : case PSQL_SEND_EXTENDED_QUERY_PREPARED: /* \bind_named */
2866 [ + + ]: 1199 : for (i = 0; i < pset.bind_nparams; i++)
2867 : 555 : free(pset.bind_params[i]);
2868 : 644 : free(pset.bind_params);
2869 : 644 : free(pset.stmtName);
2870 : 644 : pset.bind_params = NULL;
2871 : 644 : break;
2872 : 261153 : case PSQL_SEND_QUERY:
2873 : : case PSQL_SEND_START_PIPELINE_MODE: /* \startpipeline */
2874 : : case PSQL_SEND_END_PIPELINE_MODE: /* \endpipeline */
2875 : : case PSQL_SEND_PIPELINE_SYNC: /* \syncpipeline */
2876 : : case PSQL_SEND_FLUSH: /* \flush */
2877 : : case PSQL_SEND_GET_RESULTS: /* \getresults */
2878 : : case PSQL_SEND_FLUSH_REQUEST: /* \flushrequest */
2879 : 261153 : break;
2880 : : }
2881 : :
2882 : 261889 : pset.stmtName = NULL;
2883 : 261889 : pset.send_mode = PSQL_SEND_QUERY;
2884 : 261889 : }
2885 : :
2886 : : /*
2887 : : * Recognized connection string either starts with a valid URI prefix or
2888 : : * contains a "=" in it.
2889 : : *
2890 : : * Must be consistent with parse_connection_string: anything for which this
2891 : : * returns true should at least look like it's parseable by that routine.
2892 : : *
2893 : : * XXX This is a duplicate of the eponymous libpq function.
2894 : : */
2895 : : bool
2896 : 27 : recognized_connection_string(const char *connstr)
2897 : : {
2898 [ + - + + ]: 27 : return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL;
2899 : : }
|