LCOV - code coverage report
Current view: top level - src/bin/psql - common.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 75.4 % 1014 765
Test Date: 2026-06-03 23:16:13 Functions: 92.7 % 41 38
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1