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

Generated by: LCOV version 2.0-1