LCOV - code coverage report
Current view: top level - src/bin/psql - mainloop.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 158 257 61.5 %
Date: 2020-06-03 11:07:14 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * psql - the PostgreSQL interactive terminal
       3             :  *
       4             :  * Copyright (c) 2000-2020, PostgreSQL Global Development Group
       5             :  *
       6             :  * src/bin/psql/mainloop.c
       7             :  */
       8             : #include "postgres_fe.h"
       9             : 
      10             : #include "command.h"
      11             : #include "common.h"
      12             : #include "common/logging.h"
      13             : #include "input.h"
      14             : #include "mainloop.h"
      15             : #include "mb/pg_wchar.h"
      16             : #include "prompt.h"
      17             : #include "settings.h"
      18             : 
      19             : /* callback functions for our flex lexer */
      20             : const PsqlScanCallbacks psqlscan_callbacks = {
      21             :     psql_get_variable,
      22             : };
      23             : 
      24             : 
      25             : /*
      26             :  * Main processing loop for reading lines of input
      27             :  *  and sending them to the backend.
      28             :  *
      29             :  * This loop is re-entrant. May be called by \i command
      30             :  *  which reads input from a file.
      31             :  */
      32             : int
      33        3506 : MainLoop(FILE *source)
      34             : {
      35             :     PsqlScanState scan_state;   /* lexer working state */
      36             :     ConditionalStack cond_stack;    /* \if status stack */
      37             :     volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
      38             :     volatile PQExpBuffer previous_buf;  /* if there isn't anything in the new
      39             :                                          * buffer yet, use this one for \e,
      40             :                                          * etc. */
      41             :     PQExpBuffer history_buf;    /* earlier lines of a multi-line command, not
      42             :                                  * yet saved to readline history */
      43             :     char       *line;           /* current line of input */
      44             :     int         added_nl_pos;
      45             :     bool        success;
      46             :     bool        line_saved_in_history;
      47        3506 :     volatile int successResult = EXIT_SUCCESS;
      48        3506 :     volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
      49        3506 :     volatile promptStatus_t prompt_status = PROMPT_READY;
      50        3506 :     volatile bool need_redisplay = false;
      51        3506 :     volatile int count_eof = 0;
      52        3506 :     volatile bool die_on_error = false;
      53             :     FILE       *prev_cmd_source;
      54             :     bool        prev_cmd_interactive;
      55             :     uint64      prev_lineno;
      56             : 
      57             :     /* Save the prior command source */
      58        3506 :     prev_cmd_source = pset.cur_cmd_source;
      59        3506 :     prev_cmd_interactive = pset.cur_cmd_interactive;
      60        3506 :     prev_lineno = pset.lineno;
      61             :     /* pset.stmt_lineno does not need to be saved and restored */
      62             : 
      63             :     /* Establish new source */
      64        3506 :     pset.cur_cmd_source = source;
      65        3506 :     pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
      66        3506 :     pset.lineno = 0;
      67        3506 :     pset.stmt_lineno = 1;
      68             : 
      69             :     /* Create working state */
      70        3506 :     scan_state = psql_scan_create(&psqlscan_callbacks);
      71        3506 :     cond_stack = conditional_stack_create();
      72        3506 :     psql_scan_set_passthrough(scan_state, (void *) cond_stack);
      73             : 
      74        3506 :     query_buf = createPQExpBuffer();
      75        3506 :     previous_buf = createPQExpBuffer();
      76        3506 :     history_buf = createPQExpBuffer();
      77        3506 :     if (PQExpBufferBroken(query_buf) ||
      78        3506 :         PQExpBufferBroken(previous_buf) ||
      79        3506 :         PQExpBufferBroken(history_buf))
      80             :     {
      81           0 :         pg_log_error("out of memory");
      82           0 :         exit(EXIT_FAILURE);
      83             :     }
      84             : 
      85             :     /* main loop to get queries and execute them */
      86      372512 :     while (successResult == EXIT_SUCCESS)
      87             :     {
      88             :         /*
      89             :          * Clean up after a previous Control-C
      90             :          */
      91      372496 :         if (cancel_pressed)
      92             :         {
      93           0 :             if (!pset.cur_cmd_interactive)
      94             :             {
      95             :                 /*
      96             :                  * You get here if you stopped a script with Ctrl-C.
      97             :                  */
      98           0 :                 successResult = EXIT_USER;
      99           0 :                 break;
     100             :             }
     101             : 
     102           0 :             cancel_pressed = false;
     103             :         }
     104             : 
     105             :         /*
     106             :          * Establish longjmp destination for exiting from wait-for-input. We
     107             :          * must re-do this each time through the loop for safety, since the
     108             :          * jmpbuf might get changed during command execution.
     109             :          */
     110      372496 :         if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
     111             :         {
     112             :             /* got here with longjmp */
     113             : 
     114             :             /* reset parsing state */
     115           0 :             psql_scan_finish(scan_state);
     116           0 :             psql_scan_reset(scan_state);
     117           0 :             resetPQExpBuffer(query_buf);
     118           0 :             resetPQExpBuffer(history_buf);
     119           0 :             count_eof = 0;
     120           0 :             slashCmdStatus = PSQL_CMD_UNKNOWN;
     121           0 :             prompt_status = PROMPT_READY;
     122           0 :             need_redisplay = false;
     123           0 :             pset.stmt_lineno = 1;
     124           0 :             cancel_pressed = false;
     125             : 
     126           0 :             if (pset.cur_cmd_interactive)
     127             :             {
     128           0 :                 putc('\n', stdout);
     129             : 
     130             :                 /*
     131             :                  * if interactive user is in an \if block, then Ctrl-C will
     132             :                  * exit from the innermost \if.
     133             :                  */
     134           0 :                 if (!conditional_stack_empty(cond_stack))
     135             :                 {
     136           0 :                     pg_log_error("\\if: escaped");
     137           0 :                     conditional_stack_pop(cond_stack);
     138             :                 }
     139             :             }
     140             :             else
     141             :             {
     142           0 :                 successResult = EXIT_USER;
     143           0 :                 break;
     144             :             }
     145             :         }
     146             : 
     147      372496 :         fflush(stdout);
     148             : 
     149             :         /*
     150             :          * get another line
     151             :          */
     152      372496 :         if (pset.cur_cmd_interactive)
     153             :         {
     154             :             /* May need to reset prompt, eg after \r command */
     155          18 :             if (query_buf->len == 0)
     156          18 :                 prompt_status = PROMPT_READY;
     157             :             /* If query buffer came from \e, redisplay it with a prompt */
     158          18 :             if (need_redisplay)
     159             :             {
     160           0 :                 if (query_buf->len > 0)
     161             :                 {
     162           0 :                     fputs(get_prompt(PROMPT_READY, cond_stack), stdout);
     163           0 :                     fputs(query_buf->data, stdout);
     164           0 :                     fflush(stdout);
     165             :                 }
     166           0 :                 need_redisplay = false;
     167             :             }
     168             :             /* Now we can fetch a line */
     169          18 :             line = gets_interactive(get_prompt(prompt_status, cond_stack),
     170             :                                     query_buf);
     171             :         }
     172             :         else
     173             :         {
     174      372478 :             line = gets_fromFile(source);
     175      372478 :             if (!line && ferror(source))
     176           0 :                 successResult = EXIT_FAILURE;
     177             :         }
     178             : 
     179             :         /*
     180             :          * query_buf holds query already accumulated.  line is the malloc'd
     181             :          * new line of input (note it must be freed before looping around!)
     182             :          */
     183             : 
     184             :         /* No more input.  Time to quit, or \i done */
     185      372496 :         if (line == NULL)
     186             :         {
     187        3474 :             if (pset.cur_cmd_interactive)
     188             :             {
     189             :                 /* This tries to mimic bash's IGNOREEOF feature. */
     190           0 :                 count_eof++;
     191             : 
     192           0 :                 if (count_eof < pset.ignoreeof)
     193             :                 {
     194           0 :                     if (!pset.quiet)
     195           0 :                         printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
     196           0 :                     continue;
     197             :                 }
     198             : 
     199           0 :                 puts(pset.quiet ? "" : "\\q");
     200             :             }
     201        3474 :             break;
     202             :         }
     203             : 
     204      369022 :         count_eof = 0;
     205             : 
     206      369022 :         pset.lineno++;
     207             : 
     208             :         /* ignore UTF-8 Unicode byte-order mark */
     209      369022 :         if (pset.lineno == 1 && pset.encoding == PG_UTF8 && strncmp(line, "\xef\xbb\xbf", 3) == 0)
     210           0 :             memmove(line, line + 3, strlen(line + 3) + 1);
     211             : 
     212             :         /* Detect attempts to run custom-format dumps as SQL scripts */
     213      369022 :         if (pset.lineno == 1 && !pset.cur_cmd_interactive &&
     214        3334 :             strncmp(line, "PGDMP", 5) == 0)
     215             :         {
     216           0 :             free(line);
     217           0 :             puts(_("The input is a PostgreSQL custom-format dump.\n"
     218             :                    "Use the pg_restore command-line client to restore this dump to a database.\n"));
     219           0 :             fflush(stdout);
     220           0 :             successResult = EXIT_FAILURE;
     221           0 :             break;
     222             :         }
     223             : 
     224             :         /* no further processing of empty lines, unless within a literal */
     225      369022 :         if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
     226             :         {
     227       68046 :             free(line);
     228       68046 :             continue;
     229             :         }
     230             : 
     231             :         /* Recognize "help", "quit", "exit" only in interactive mode */
     232      300976 :         if (pset.cur_cmd_interactive)
     233             :         {
     234          14 :             char       *first_word = line;
     235          14 :             char       *rest_of_line = NULL;
     236          14 :             bool        found_help = false;
     237          14 :             bool        found_exit_or_quit = false;
     238          14 :             bool        found_q = false;
     239             : 
     240             :             /*
     241             :              * The assistance words, help/exit/quit, must have no whitespace
     242             :              * before them, and only whitespace after, with an optional
     243             :              * semicolon.  This prevents indented use of these words, perhaps
     244             :              * as identifiers, from invoking the assistance behavior.
     245             :              */
     246          14 :             if (pg_strncasecmp(first_word, "help", 4) == 0)
     247             :             {
     248           0 :                 rest_of_line = first_word + 4;
     249           0 :                 found_help = true;
     250             :             }
     251          14 :             else if (pg_strncasecmp(first_word, "exit", 4) == 0 ||
     252          14 :                      pg_strncasecmp(first_word, "quit", 4) == 0)
     253             :             {
     254           0 :                 rest_of_line = first_word + 4;
     255           0 :                 found_exit_or_quit = true;
     256             :             }
     257          14 :             else if (strncmp(first_word, "\\q", 2) == 0)
     258             :             {
     259           2 :                 rest_of_line = first_word + 2;
     260           2 :                 found_q = true;
     261             :             }
     262             : 
     263             :             /*
     264             :              * If we found a command word, check whether the rest of the line
     265             :              * contains only whitespace plus maybe one semicolon.  If not,
     266             :              * ignore the command word after all.  These commands are only for
     267             :              * compatibility with other SQL clients and are not documented.
     268             :              */
     269          14 :             if (rest_of_line != NULL)
     270             :             {
     271             :                 /*
     272             :                  * Ignore unless rest of line is whitespace, plus maybe one
     273             :                  * semicolon
     274             :                  */
     275           2 :                 while (isspace((unsigned char) *rest_of_line))
     276           0 :                     ++rest_of_line;
     277           2 :                 if (*rest_of_line == ';')
     278           0 :                     ++rest_of_line;
     279           2 :                 while (isspace((unsigned char) *rest_of_line))
     280           0 :                     ++rest_of_line;
     281           2 :                 if (*rest_of_line != '\0')
     282             :                 {
     283           0 :                     found_help = false;
     284           0 :                     found_exit_or_quit = false;
     285             :                 }
     286             :             }
     287             : 
     288             :             /*
     289             :              * "help" is only a command when the query buffer is empty, but we
     290             :              * emit a one-line message even when it isn't to help confused
     291             :              * users.  The text is still added to the query buffer in that
     292             :              * case.
     293             :              */
     294          14 :             if (found_help)
     295             :             {
     296           0 :                 if (query_buf->len != 0)
     297             : #ifndef WIN32
     298           0 :                     puts(_("Use \\? for help or press control-C to clear the input buffer."));
     299             : #else
     300             :                     puts(_("Use \\? for help."));
     301             : #endif
     302             :                 else
     303             :                 {
     304           0 :                     puts(_("You are using psql, the command-line interface to PostgreSQL."));
     305           0 :                     printf(_("Type:  \\copyright for distribution terms\n"
     306             :                              "       \\h for help with SQL commands\n"
     307             :                              "       \\? for help with psql commands\n"
     308             :                              "       \\g or terminate with semicolon to execute query\n"
     309             :                              "       \\q to quit\n"));
     310           0 :                     free(line);
     311           0 :                     fflush(stdout);
     312           0 :                     continue;
     313             :                 }
     314             :             }
     315             : 
     316             :             /*
     317             :              * "quit" and "exit" are only commands when the query buffer is
     318             :              * empty, but we emit a one-line message even when it isn't to
     319             :              * help confused users.  The text is still added to the query
     320             :              * buffer in that case.
     321             :              */
     322          14 :             if (found_exit_or_quit)
     323             :             {
     324           0 :                 if (query_buf->len != 0)
     325             :                 {
     326           0 :                     if (prompt_status == PROMPT_READY ||
     327           0 :                         prompt_status == PROMPT_CONTINUE ||
     328           0 :                         prompt_status == PROMPT_PAREN)
     329           0 :                         puts(_("Use \\q to quit."));
     330             :                     else
     331             : #ifndef WIN32
     332           0 :                         puts(_("Use control-D to quit."));
     333             : #else
     334             :                         puts(_("Use control-C to quit."));
     335             : #endif
     336             :                 }
     337             :                 else
     338             :                 {
     339             :                     /* exit app */
     340           0 :                     free(line);
     341           0 :                     fflush(stdout);
     342           0 :                     successResult = EXIT_SUCCESS;
     343           0 :                     break;
     344             :                 }
     345             :             }
     346             : 
     347             :             /*
     348             :              * If they typed "\q" in a place where "\q" is not active, supply
     349             :              * a hint.  The text is still added to the query buffer.
     350             :              */
     351          14 :             if (found_q && query_buf->len != 0 &&
     352           0 :                 prompt_status != PROMPT_READY &&
     353           0 :                 prompt_status != PROMPT_CONTINUE &&
     354           0 :                 prompt_status != PROMPT_PAREN)
     355             : #ifndef WIN32
     356           0 :                 puts(_("Use control-D to quit."));
     357             : #else
     358             :                 puts(_("Use control-C to quit."));
     359             : #endif
     360             :         }
     361             : 
     362             :         /* echo back if flag is set, unless interactive */
     363      300976 :         if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
     364             :         {
     365      295412 :             puts(line);
     366      295412 :             fflush(stdout);
     367             :         }
     368             : 
     369             :         /* insert newlines into query buffer between source lines */
     370      300976 :         if (query_buf->len > 0)
     371             :         {
     372       92460 :             appendPQExpBufferChar(query_buf, '\n');
     373       92460 :             added_nl_pos = query_buf->len;
     374             :         }
     375             :         else
     376      208516 :             added_nl_pos = -1;  /* flag we didn't add one */
     377             : 
     378             :         /* Setting this will not have effect until next line. */
     379      300976 :         die_on_error = pset.on_error_stop;
     380             : 
     381             :         /*
     382             :          * Parse line, looking for command separators.
     383             :          */
     384      300976 :         psql_scan_setup(scan_state, line, strlen(line),
     385      300976 :                         pset.encoding, standard_strings());
     386      300976 :         success = true;
     387      300976 :         line_saved_in_history = false;
     388             : 
     389      462402 :         while (success || !die_on_error)
     390             :         {
     391             :             PsqlScanResult scan_result;
     392      462386 :             promptStatus_t prompt_tmp = prompt_status;
     393             :             size_t      pos_in_query;
     394             :             char       *tmp_line;
     395             : 
     396      462386 :             pos_in_query = query_buf->len;
     397      462386 :             scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
     398      462386 :             prompt_status = prompt_tmp;
     399             : 
     400      462386 :             if (PQExpBufferBroken(query_buf))
     401             :             {
     402           0 :                 pg_log_error("out of memory");
     403           0 :                 exit(EXIT_FAILURE);
     404             :             }
     405             : 
     406             :             /*
     407             :              * Increase statement line number counter for each linebreak added
     408             :              * to the query buffer by the last psql_scan() call. There only
     409             :              * will be ones to add when navigating to a statement in
     410             :              * readline's history containing newlines.
     411             :              */
     412      462386 :             tmp_line = query_buf->data + pos_in_query;
     413    11200302 :             while (*tmp_line != '\0')
     414             :             {
     415    10737916 :                 if (*(tmp_line++) == '\n')
     416         120 :                     pset.stmt_lineno++;
     417             :             }
     418             : 
     419      462386 :             if (scan_result == PSCAN_EOL)
     420       44382 :                 pset.stmt_lineno++;
     421             : 
     422             :             /*
     423             :              * Send command if semicolon found, or if end of line and we're in
     424             :              * single-line mode.
     425             :              */
     426      462386 :             if (scan_result == PSCAN_SEMICOLON ||
     427       44382 :                 (scan_result == PSCAN_EOL && pset.singleline))
     428             :             {
     429             :                 /*
     430             :                  * Save line in history.  We use history_buf to accumulate
     431             :                  * multi-line queries into a single history entry.  Note that
     432             :                  * history accumulation works on input lines, so it doesn't
     433             :                  * matter whether the query will be ignored due to \if.
     434             :                  */
     435      156020 :                 if (pset.cur_cmd_interactive && !line_saved_in_history)
     436             :                 {
     437           0 :                     pg_append_history(line, history_buf);
     438           0 :                     pg_send_history(history_buf);
     439           0 :                     line_saved_in_history = true;
     440             :                 }
     441             : 
     442             :                 /* execute query unless we're in an inactive \if branch */
     443      312034 :                 if (conditional_active(cond_stack))
     444             :                 {
     445      156016 :                     success = SendQuery(query_buf->data);
     446      156010 :                     slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
     447      156010 :                     pset.stmt_lineno = 1;
     448             : 
     449             :                     /* transfer query to previous_buf by pointer-swapping */
     450             :                     {
     451      156010 :                         PQExpBuffer swap_buf = previous_buf;
     452             : 
     453      156010 :                         previous_buf = query_buf;
     454      156010 :                         query_buf = swap_buf;
     455             :                     }
     456      156010 :                     resetPQExpBuffer(query_buf);
     457             : 
     458      156010 :                     added_nl_pos = -1;
     459             :                     /* we need not do psql_scan_reset() here */
     460             :                 }
     461             :                 else
     462             :                 {
     463             :                     /* if interactive, warn about non-executed query */
     464           4 :                     if (pset.cur_cmd_interactive)
     465           0 :                         pg_log_error("query ignored; use \\endif or Ctrl-C to exit current \\if block");
     466             :                     /* fake an OK result for purposes of loop checks */
     467           4 :                     success = true;
     468           4 :                     slashCmdStatus = PSQL_CMD_SEND;
     469           4 :                     pset.stmt_lineno = 1;
     470             :                     /* note that query_buf doesn't change state */
     471             :                 }
     472             :             }
     473      306366 :             else if (scan_result == PSCAN_BACKSLASH)
     474             :             {
     475             :                 /* handle backslash command */
     476             : 
     477             :                 /*
     478             :                  * If we added a newline to query_buf, and nothing else has
     479             :                  * been inserted in query_buf by the lexer, then strip off the
     480             :                  * newline again.  This avoids any change to query_buf when a
     481             :                  * line contains only a backslash command.  Also, in this
     482             :                  * situation we force out any previous lines as a separate
     483             :                  * history entry; we don't want SQL and backslash commands
     484             :                  * intermixed in history if at all possible.
     485             :                  */
     486        5422 :                 if (query_buf->len == added_nl_pos)
     487             :                 {
     488          66 :                     query_buf->data[--query_buf->len] = '\0';
     489          66 :                     pg_send_history(history_buf);
     490             :                 }
     491        5422 :                 added_nl_pos = -1;
     492             : 
     493             :                 /* save backslash command in history */
     494        5422 :                 if (pset.cur_cmd_interactive && !line_saved_in_history)
     495             :                 {
     496          14 :                     pg_append_history(line, history_buf);
     497          14 :                     pg_send_history(history_buf);
     498          14 :                     line_saved_in_history = true;
     499             :                 }
     500             : 
     501             :                 /* execute backslash command */
     502        5422 :                 slashCmdStatus = HandleSlashCmds(scan_state,
     503             :                                                  cond_stack,
     504             :                                                  query_buf,
     505             :                                                  previous_buf);
     506             : 
     507        5422 :                 success = slashCmdStatus != PSQL_CMD_ERROR;
     508             : 
     509             :                 /*
     510             :                  * Resetting stmt_lineno after a backslash command isn't
     511             :                  * always appropriate, but it's what we've done historically
     512             :                  * and there have been few complaints.
     513             :                  */
     514        5422 :                 pset.stmt_lineno = 1;
     515             : 
     516        5422 :                 if (slashCmdStatus == PSQL_CMD_SEND)
     517             :                 {
     518             :                     /* should not see this in inactive branch */
     519             :                     Assert(conditional_active(cond_stack));
     520             : 
     521         368 :                     success = SendQuery(query_buf->data);
     522             : 
     523             :                     /* transfer query to previous_buf by pointer-swapping */
     524             :                     {
     525         368 :                         PQExpBuffer swap_buf = previous_buf;
     526             : 
     527         368 :                         previous_buf = query_buf;
     528         368 :                         query_buf = swap_buf;
     529             :                     }
     530         368 :                     resetPQExpBuffer(query_buf);
     531             : 
     532             :                     /* flush any paren nesting info after forced send */
     533         368 :                     psql_scan_reset(scan_state);
     534             :                 }
     535        5054 :                 else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
     536             :                 {
     537             :                     /* should not see this in inactive branch */
     538             :                     Assert(conditional_active(cond_stack));
     539             :                     /* ensure what came back from editing ends in a newline */
     540           0 :                     if (query_buf->len > 0 &&
     541           0 :                         query_buf->data[query_buf->len - 1] != '\n')
     542           0 :                         appendPQExpBufferChar(query_buf, '\n');
     543             :                     /* rescan query_buf as new input */
     544           0 :                     psql_scan_finish(scan_state);
     545           0 :                     free(line);
     546           0 :                     line = pg_strdup(query_buf->data);
     547           0 :                     resetPQExpBuffer(query_buf);
     548             :                     /* reset parsing state since we are rescanning whole line */
     549           0 :                     psql_scan_reset(scan_state);
     550           0 :                     psql_scan_setup(scan_state, line, strlen(line),
     551           0 :                                     pset.encoding, standard_strings());
     552           0 :                     line_saved_in_history = false;
     553           0 :                     prompt_status = PROMPT_READY;
     554             :                     /* we'll want to redisplay after parsing what we have */
     555           0 :                     need_redisplay = true;
     556             :                 }
     557        5054 :                 else if (slashCmdStatus == PSQL_CMD_TERMINATE)
     558      300954 :                     break;
     559             :             }
     560             : 
     561             :             /* fall out of loop if lexer reached EOL */
     562      462370 :             if (scan_result == PSCAN_INCOMPLETE ||
     563             :                 scan_result == PSCAN_EOL)
     564             :                 break;
     565             :         }
     566             : 
     567             :         /* Add line to pending history if we didn't execute anything yet */
     568      300970 :         if (pset.cur_cmd_interactive && !line_saved_in_history)
     569           0 :             pg_append_history(line, history_buf);
     570             : 
     571      300970 :         psql_scan_finish(scan_state);
     572      300970 :         free(line);
     573             : 
     574      300970 :         if (slashCmdStatus == PSQL_CMD_TERMINATE)
     575             :         {
     576          10 :             successResult = EXIT_SUCCESS;
     577          10 :             break;
     578             :         }
     579             : 
     580      300960 :         if (!pset.cur_cmd_interactive)
     581             :         {
     582      300948 :             if (!success && die_on_error)
     583          16 :                 successResult = EXIT_USER;
     584             :             /* Have we lost the db connection? */
     585      300932 :             else if (!pset.db)
     586           0 :                 successResult = EXIT_BADCONN;
     587             :         }
     588             :     }                           /* while !endoffile/session */
     589             : 
     590             :     /*
     591             :      * If we have a non-semicolon-terminated query at the end of file, we
     592             :      * process it unless the input source is interactive --- in that case it
     593             :      * seems better to go ahead and quit.  Also skip if this is an error exit.
     594             :      */
     595        3500 :     if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
     596        1248 :         successResult == EXIT_SUCCESS)
     597             :     {
     598             :         /* save query in history */
     599             :         /* currently unneeded since we don't use this block if interactive */
     600             : #ifdef NOT_USED
     601             :         if (pset.cur_cmd_interactive)
     602             :             pg_send_history(history_buf);
     603             : #endif
     604             : 
     605             :         /* execute query unless we're in an inactive \if branch */
     606        1248 :         if (conditional_active(cond_stack))
     607             :         {
     608        1248 :             success = SendQuery(query_buf->data);
     609             :         }
     610             :         else
     611             :         {
     612           0 :             if (pset.cur_cmd_interactive)
     613           0 :                 pg_log_error("query ignored; use \\endif or Ctrl-C to exit current \\if block");
     614           0 :             success = true;
     615             :         }
     616             : 
     617        1248 :         if (!success && die_on_error)
     618          16 :             successResult = EXIT_USER;
     619        1232 :         else if (pset.db == NULL)
     620           0 :             successResult = EXIT_BADCONN;
     621             :     }
     622             : 
     623             :     /*
     624             :      * Check for unbalanced \if-\endifs unless user explicitly quit, or the
     625             :      * script is erroring out
     626             :      */
     627        3500 :     if (slashCmdStatus != PSQL_CMD_TERMINATE &&
     628        3490 :         successResult != EXIT_USER &&
     629        3458 :         !conditional_stack_empty(cond_stack))
     630             :     {
     631           0 :         pg_log_error("reached EOF without finding closing \\endif(s)");
     632           0 :         if (die_on_error && !pset.cur_cmd_interactive)
     633           0 :             successResult = EXIT_USER;
     634             :     }
     635             : 
     636             :     /*
     637             :      * Let's just make real sure the SIGINT handler won't try to use
     638             :      * sigint_interrupt_jmp after we exit this routine.  If there is an outer
     639             :      * MainLoop instance, it will reset sigint_interrupt_jmp to point to
     640             :      * itself at the top of its loop, before any further interactive input
     641             :      * happens.
     642             :      */
     643        3500 :     sigint_interrupt_enabled = false;
     644             : 
     645        3500 :     destroyPQExpBuffer(query_buf);
     646        3500 :     destroyPQExpBuffer(previous_buf);
     647        3500 :     destroyPQExpBuffer(history_buf);
     648             : 
     649        3500 :     psql_scan_destroy(scan_state);
     650        3500 :     conditional_stack_destroy(cond_stack);
     651             : 
     652        3500 :     pset.cur_cmd_source = prev_cmd_source;
     653        3500 :     pset.cur_cmd_interactive = prev_cmd_interactive;
     654        3500 :     pset.lineno = prev_lineno;
     655             : 
     656        3500 :     return successResult;
     657             : }                               /* MainLoop() */

Generated by: LCOV version 1.13