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

Generated by: LCOV version 1.14