LCOV - code coverage report
Current view: top level - src/bin/psql - mainloop.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 64.0 % 258 165
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 1 1
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/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         9374 : 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         9374 :     volatile int successResult = EXIT_SUCCESS;
      48         9374 :     volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
      49         9374 :     volatile promptStatus_t prompt_status = PROMPT_READY;
      50         9374 :     volatile bool need_redisplay = false;
      51         9374 :     volatile int count_eof = 0;
      52         9374 :     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         9374 :     prev_cmd_source = pset.cur_cmd_source;
      59         9374 :     prev_cmd_interactive = pset.cur_cmd_interactive;
      60         9374 :     prev_lineno = pset.lineno;
      61              :     /* pset.stmt_lineno does not need to be saved and restored */
      62              : 
      63              :     /* Establish new source */
      64         9374 :     pset.cur_cmd_source = source;
      65         9374 :     pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
      66         9374 :     pset.lineno = 0;
      67         9374 :     pset.stmt_lineno = 1;
      68              : 
      69              :     /* Create working state */
      70         9374 :     scan_state = psql_scan_create(&psqlscan_callbacks);
      71         9374 :     cond_stack = conditional_stack_create();
      72         9374 :     psql_scan_set_passthrough(scan_state, cond_stack);
      73              : 
      74         9374 :     query_buf = createPQExpBuffer();
      75         9374 :     previous_buf = createPQExpBuffer();
      76         9374 :     history_buf = createPQExpBuffer();
      77         9374 :     if (PQExpBufferBroken(query_buf) ||
      78         9374 :         PQExpBufferBroken(previous_buf) ||
      79         9374 :         PQExpBufferBroken(history_buf))
      80            0 :         pg_fatal("out of memory");
      81              : 
      82              :     /* main loop to get queries and execute them */
      83       477078 :     while (successResult == EXIT_SUCCESS)
      84              :     {
      85              :         /*
      86              :          * Clean up after a previous Control-C
      87              :          */
      88       477013 :         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       477013 :         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       477013 :         fflush(stdout);
     145              : 
     146              :         /*
     147              :          * get another line
     148              :          */
     149       477013 :         if (pset.cur_cmd_interactive)
     150              :         {
     151              :             /* May need to reset prompt, eg after \r command */
     152           67 :             if (query_buf->len == 0)
     153           65 :                 prompt_status = PROMPT_READY;
     154              :             /* If query buffer came from \e, redisplay it with a prompt */
     155           67 :             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           67 :             line = gets_interactive(get_prompt(prompt_status, cond_stack),
     167              :                                     query_buf);
     168              :         }
     169              :         else
     170              :         {
     171       476946 :             line = gets_fromFile(source);
     172       476946 :             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       477013 :         if (line == NULL)
     183              :         {
     184         9115 :             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         9115 :             break;
     199              :         }
     200              : 
     201       467898 :         count_eof = 0;
     202              : 
     203       467898 :         pset.lineno++;
     204              : 
     205              :         /* ignore UTF-8 Unicode byte-order mark */
     206       467898 :         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       467898 :         if (pset.lineno == 1 && !pset.cur_cmd_interactive &&
     211         9317 :             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       467898 :         if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
     223              :         {
     224        74749 :             free(line);
     225        74749 :             continue;
     226              :         }
     227              : 
     228              :         /* Recognize "help", "quit", "exit" only in interactive mode */
     229       393149 :         if (pset.cur_cmd_interactive)
     230              :         {
     231           61 :             char       *first_word = line;
     232           61 :             char       *rest_of_line = NULL;
     233           61 :             bool        found_help = false;
     234           61 :             bool        found_exit_or_quit = false;
     235           61 :             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           61 :             if (pg_strncasecmp(first_word, "help", 4) == 0)
     244              :             {
     245            0 :                 rest_of_line = first_word + 4;
     246            0 :                 found_help = true;
     247              :             }
     248           61 :             else if (pg_strncasecmp(first_word, "exit", 4) == 0 ||
     249           61 :                      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           61 :             else if (strncmp(first_word, "\\q", 2) == 0)
     255              :             {
     256            3 :                 rest_of_line = first_word + 2;
     257            3 :                 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           61 :             if (rest_of_line != NULL)
     267              :             {
     268              :                 /*
     269              :                  * Ignore unless rest of line is whitespace, plus maybe one
     270              :                  * semicolon
     271              :                  */
     272            3 :                 while (isspace((unsigned char) *rest_of_line))
     273            0 :                     ++rest_of_line;
     274            3 :                 if (*rest_of_line == ';')
     275            0 :                     ++rest_of_line;
     276            3 :                 while (isspace((unsigned char) *rest_of_line))
     277            0 :                     ++rest_of_line;
     278            3 :                 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           61 :             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           61 :             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           61 :             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       393149 :         if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
     361              :         {
     362       328843 :             puts(line);
     363       328843 :             fflush(stdout);
     364              :         }
     365              : 
     366              :         /* insert newlines into query buffer between source lines */
     367       393149 :         if (query_buf->len > 0)
     368              :         {
     369       122568 :             appendPQExpBufferChar(query_buf, '\n');
     370       122568 :             added_nl_pos = query_buf->len;
     371              :         }
     372              :         else
     373       270581 :             added_nl_pos = -1;  /* flag we didn't add one */
     374              : 
     375              :         /* Setting this will not have effect until next line. */
     376       393149 :         die_on_error = pset.on_error_stop;
     377              : 
     378              :         /*
     379              :          * Parse line, looking for command separators.
     380              :          */
     381       393149 :         psql_scan_setup(scan_state, line, strlen(line),
     382       393149 :                         pset.encoding, standard_strings());
     383       393149 :         success = true;
     384       393149 :         line_saved_in_history = false;
     385              : 
     386       604015 :         while (success || !die_on_error)
     387              :         {
     388              :             PsqlScanResult scan_result;
     389       603950 :             promptStatus_t prompt_tmp = prompt_status;
     390              :             size_t      pos_in_query;
     391              :             char       *tmp_line;
     392              : 
     393       603950 :             pos_in_query = query_buf->len;
     394       603950 :             scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
     395       603950 :             prompt_status = prompt_tmp;
     396              : 
     397       603950 :             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       603950 :             tmp_line = query_buf->data + pos_in_query;
     407     13734145 :             while (*tmp_line != '\0')
     408              :             {
     409     13130195 :                 if (*(tmp_line++) == '\n')
     410           90 :                     pset.stmt_lineno++;
     411              :             }
     412              : 
     413       603950 :             if (scan_result == PSCAN_EOL)
     414        72498 :                 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       603950 :             if (scan_result == PSCAN_SEMICOLON ||
     421        72498 :                 (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       182773 :                 if (pset.cur_cmd_interactive && !line_saved_in_history)
     430              :                 {
     431            8 :                     pg_append_history(line, history_buf);
     432            8 :                     pg_send_history(history_buf);
     433            8 :                     line_saved_in_history = true;
     434              :                 }
     435              : 
     436              :                 /* execute query unless we're in an inactive \if branch */
     437       365537 :                 if (conditional_active(cond_stack))
     438              :                 {
     439       182767 :                     success = SendQuery(query_buf->data);
     440       182758 :                     slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
     441       182758 :                     pset.stmt_lineno = 1;
     442              : 
     443              :                     /* transfer query to previous_buf by pointer-swapping */
     444              :                     {
     445       182758 :                         PQExpBuffer swap_buf = previous_buf;
     446              : 
     447       182758 :                         previous_buf = query_buf;
     448       182758 :                         query_buf = swap_buf;
     449              :                     }
     450       182758 :                     resetPQExpBuffer(query_buf);
     451              : 
     452       182758 :                     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            6 :                     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            6 :                     success = true;
     462            6 :                     slashCmdStatus = PSQL_CMD_SEND;
     463            6 :                     pset.stmt_lineno = 1;
     464              :                     /* note that query_buf doesn't change state */
     465              :                 }
     466              :             }
     467       421177 :             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        28287 :                 if (query_buf->len == added_nl_pos)
     481              :                 {
     482           84 :                     query_buf->data[--query_buf->len] = '\0';
     483           84 :                     pg_send_history(history_buf);
     484              :                 }
     485        28287 :                 added_nl_pos = -1;
     486              : 
     487              :                 /* save backslash command in history */
     488        28287 :                 if (pset.cur_cmd_interactive && !line_saved_in_history)
     489              :                 {
     490           51 :                     pg_append_history(line, history_buf);
     491           51 :                     pg_send_history(history_buf);
     492           51 :                     line_saved_in_history = true;
     493              :                 }
     494              : 
     495              :                 /* execute backslash command */
     496        28287 :                 slashCmdStatus = HandleSlashCmds(scan_state,
     497              :                                                  cond_stack,
     498              :                                                  query_buf,
     499              :                                                  previous_buf);
     500              : 
     501        28285 :                 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        28285 :                 pset.stmt_lineno = 1;
     509              : 
     510        28285 :                 if (slashCmdStatus == PSQL_CMD_SEND)
     511              :                 {
     512              :                     /* should not see this in inactive branch */
     513              :                     Assert(conditional_active(cond_stack));
     514              : 
     515         1496 :                     success = SendQuery(query_buf->data);
     516              : 
     517              :                     /* transfer query to previous_buf by pointer-swapping */
     518              :                     {
     519         1492 :                         PQExpBuffer swap_buf = previous_buf;
     520              : 
     521         1492 :                         previous_buf = query_buf;
     522         1492 :                         query_buf = swap_buf;
     523              :                     }
     524         1492 :                     resetPQExpBuffer(query_buf);
     525              : 
     526              :                     /* flush any paren nesting info after forced send */
     527         1492 :                     psql_scan_reset(scan_state);
     528              :                 }
     529        26789 :                 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        26789 :                 else if (slashCmdStatus == PSQL_CMD_TERMINATE)
     552       393069 :                     break;
     553              :             }
     554              : 
     555              :             /* fall out of loop if lexer reached EOL */
     556       603756 :             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       393134 :         if (pset.cur_cmd_interactive)
     569              :         {
     570           61 :             if (!line_saved_in_history)
     571            2 :                 pg_append_history(line, history_buf);
     572           61 :             if (query_buf->len == 0)
     573           59 :                 pg_send_history(history_buf);
     574              :         }
     575              : 
     576       393134 :         psql_scan_finish(scan_state);
     577       393134 :         free(line);
     578              : 
     579       393134 :         if (slashCmdStatus == PSQL_CMD_TERMINATE)
     580              :         {
     581          179 :             successResult = EXIT_SUCCESS;
     582          179 :             break;
     583              :         }
     584              : 
     585       392955 :         if (!pset.cur_cmd_interactive)
     586              :         {
     587       392897 :             if (!success && die_on_error)
     588           65 :                 successResult = EXIT_USER;
     589              :             /* Have we lost the db connection? */
     590       392832 :             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         9359 :     if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
     601         5613 :         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         5613 :         if (conditional_active(cond_stack))
     612              :         {
     613         5613 :             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         5612 :         if (!success && die_on_error)
     623           48 :             successResult = EXIT_USER;
     624         5564 :         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         9358 :     if (slashCmdStatus != PSQL_CMD_TERMINATE &&
     633         9179 :         successResult != EXIT_USER &&
     634         9066 :         !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         9358 :     sigint_interrupt_enabled = false;
     649              : 
     650         9358 :     destroyPQExpBuffer(query_buf);
     651         9358 :     destroyPQExpBuffer(previous_buf);
     652         9358 :     destroyPQExpBuffer(history_buf);
     653              : 
     654         9358 :     psql_scan_destroy(scan_state);
     655         9358 :     conditional_stack_destroy(cond_stack);
     656              : 
     657         9358 :     pset.cur_cmd_source = prev_cmd_source;
     658         9358 :     pset.cur_cmd_interactive = prev_cmd_interactive;
     659         9358 :     pset.lineno = prev_lineno;
     660              : 
     661         9358 :     return successResult;
     662              : }                               /* MainLoop() */
        

Generated by: LCOV version 2.0-1