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

Generated by: LCOV version 2.0-1