-#include <config.h>
-#include <c.h>
+/*
+ * psql - the PostgreSQL interactive terminal
+ *
+ * Copyright 2000 by PostgreSQL Global Development Group
+ *
+ * $Header: /cvsroot/pgsql/src/bin/psql/mainloop.c,v 1.42 2001/10/28 06:25:58 momjian Exp $
+ */
+#include "postgres_fe.h"
#include "mainloop.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <pqexpbuffer.h>
+#include "pqexpbuffer.h"
#include "settings.h"
#include "prompt.h"
#include "common.h"
#include "command.h"
+#ifndef WIN32
+#include <setjmp.h>
+sigjmp_buf main_loop_jmp;
+#endif
-/* MainLoop()
+/*
* Main processing loop for reading lines of input
* and sending them to the backend.
*
* This loop is re-entrant. May be called by \i command
* which reads input from a file.
+ *
+ * FIXME: rewrite this whole thing with flex
*/
int
-MainLoop(PsqlSettings *pset, FILE *source)
+MainLoop(FILE *source)
{
- PQExpBuffer query_buf; /* buffer for query being accumulated */
- char *line; /* current line of input */
- char *xcomment; /* start of extended comment */
- int len; /* length of the line */
- int successResult = EXIT_SUCCESS;
- backslashResult slashCmdStatus;
-
- bool eof = false; /* end of our command input? */
- bool success;
- char in_quote; /* == 0 for no in_quote */
- bool was_bslash; /* backslash */
- int paren_level;
- unsigned int query_start;
-
- int i, prevlen, thislen;
-
- /* Save the prior command source */
- FILE *prev_cmd_source;
- bool prev_cmd_interactive;
-
- bool die_on_error;
- const char *interpol_char;
-
-
- /* Save old settings */
- prev_cmd_source = pset->cur_cmd_source;
- prev_cmd_interactive = pset->cur_cmd_interactive;
-
- /* Establish new source */
- pset->cur_cmd_source = source;
- pset->cur_cmd_interactive = ((source == stdin) && !pset->notty);
-
-
- query_buf = createPQExpBuffer();
- if (!query_buf) {
- perror("createPQExpBuffer");
- exit(EXIT_FAILURE);
- }
-
- xcomment = NULL;
- in_quote = 0;
- paren_level = 0;
- slashCmdStatus = CMD_UNKNOWN; /* set default */
-
-
- /* main loop to get queries and execute them */
- while (!eof)
- {
- if (slashCmdStatus == CMD_NEWEDIT)
+ PQExpBuffer query_buf; /* buffer for query being accumulated */
+ PQExpBuffer previous_buf; /* if there isn't anything in the new
+ * buffer yet, use this one for \e, etc. */
+ char *line; /* current line of input */
+ int len; /* length of the line */
+ volatile int successResult = EXIT_SUCCESS;
+ volatile backslashResult slashCmdStatus;
+
+ bool success;
+ volatile char in_quote; /* == 0 for no in_quote */
+ volatile bool in_xcomment; /* in extended comment */
+ volatile int xcdepth;
+ volatile int paren_level;
+ unsigned int query_start;
+ volatile int count_eof = 0;
+ const char *var;
+ volatile unsigned int bslash_count = 0;
+
+ int i,
+ prevlen,
+ thislen;
+
+ /* Save the prior command source */
+ FILE *prev_cmd_source;
+ bool prev_cmd_interactive;
+
+ unsigned int prev_lineno;
+ volatile bool die_on_error = false;
+
+
+ /* Save old settings */
+ prev_cmd_source = pset.cur_cmd_source;
+ prev_cmd_interactive = pset.cur_cmd_interactive;
+
+ /* Establish new source */
+ pset.cur_cmd_source = source;
+ pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
+
+
+ query_buf = createPQExpBuffer();
+ previous_buf = createPQExpBuffer();
+ if (!query_buf || !previous_buf)
{
- /*
- * just returned from editing the line? then just copy to the
- * input buffer
- */
- line = strdup(query_buf->data);
- resetPQExpBuffer(query_buf);
- /* reset parsing state since we are rescanning whole query */
- xcomment = NULL;
- in_quote = 0;
- paren_level = 0;
- }
- else
- {
- /*
- * otherwise, set interactive prompt if necessary
- * and get another line
- */
- if (pset->cur_cmd_interactive)
- {
- int prompt_status;
-
- if (in_quote && in_quote == '\'')
- prompt_status = PROMPT_SINGLEQUOTE;
- else if (in_quote && in_quote == '"')
- prompt_status= PROMPT_DOUBLEQUOTE;
- else if (xcomment != NULL)
- prompt_status = PROMPT_COMMENT;
- else if (query_buf->len > 0)
- prompt_status = PROMPT_CONTINUE;
- else
- prompt_status = PROMPT_READY;
-
- line = gets_interactive(get_prompt(pset, prompt_status));
- }
- else
- line = gets_fromFile(source);
- }
-
-
- /* Setting these will not have effect until next line */
- die_on_error = GetVariableBool(pset->vars, "die_on_error");
- interpol_char = GetVariable(pset->vars, "sql_interpol");;
-
-
- /*
- * query_buf holds query already accumulated. line is the malloc'd
- * new line of input (note it must be freed before looping around!)
- * query_start is the next command start location within the line.
- */
-
- /* No more input. Time to quit, or \i done */
- if (line == NULL || (!pset->cur_cmd_interactive && *line == '\0'))
- {
- if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet"))
- puts("EOF");
- eof = true;
- continue;
+ psql_error("out of memory\n");
+ exit(EXIT_FAILURE);
}
- /* not currently inside an extended comment? */
- if (xcomment)
- xcomment = line;
+ in_xcomment = false;
+ in_quote = 0;
+ paren_level = 0;
+ slashCmdStatus = CMD_UNKNOWN; /* set default */
+ prev_lineno = pset.lineno;
+ pset.lineno = 0;
- /* strip trailing backslashes, they don't have a clear meaning */
- while (1) {
- char * cp = strrchr(line, '\\');
- if (cp && (*(cp + 1) == '\0'))
- *cp = '\0';
- else
- break;
- }
-
-
- /* echo back if input is from file and flag is set */
- if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo"))
- fprintf(stderr, "%s\n", line);
-
-
- /* interpolate variables into SQL */
- len = strlen(line);
- thislen = PQmblen(line);
-
- for (i = 0; line[i]; i += (thislen = PQmblen(&line[i])) ) {
- if (interpol_char && interpol_char[0] != '\0' && interpol_char[0] == line[i]) {
- size_t in_length, out_length;
- const char * value;
- char * new;
- bool closer; /* did we have a closing delimiter or just an end of line? */
-
- in_length = strcspn(&line[i+thislen], interpol_char);
- closer = line[i + thislen + in_length] == line[i];
- line[i + thislen + in_length] = '\0';
- value = interpolate_var(&line[i + thislen], pset);
- out_length = strlen(value);
-
- new = malloc(len + out_length - (in_length + (closer ? 2 : 1)) + 1);
- if (!new) {
- perror("malloc");
- exit(EXIT_FAILURE);
+ /* main loop to get queries and execute them */
+ while (1)
+ {
+#ifndef WIN32
+
+ /*
+ * Welcome code for Control-C
+ */
+ if (cancel_pressed)
+ {
+ if (!pset.cur_cmd_interactive)
+ {
+ /*
+ * You get here if you stopped a script with Ctrl-C and a
+ * query cancel was issued. In that case we don't do the
+ * longjmp, so the query routine can finish nicely.
+ */
+ successResult = EXIT_USER;
+ break;
+ }
+
+ cancel_pressed = false;
}
- new[0] = '\0';
- strncat(new, line, i);
- strcat(new, value);
- if (closer)
- strcat(new, line + i + 2 + in_length);
-
- free(line);
- line = new;
- i += out_length;
- }
- }
-
- /* nothing left on line? then ignore */
- if (line[0] == '\0') {
- free(line);
- continue;
- }
-
- slashCmdStatus = CMD_UNKNOWN;
-
- len = strlen(line);
- query_start = 0;
+ if (sigsetjmp(main_loop_jmp, 1) != 0)
+ {
+ /* got here with longjmp */
+
+ if (pset.cur_cmd_interactive)
+ {
+ fputc('\n', stdout);
+ resetPQExpBuffer(query_buf);
+
+ /* reset parsing state */
+ in_xcomment = false;
+ in_quote = 0;
+ paren_level = 0;
+ count_eof = 0;
+ slashCmdStatus = CMD_UNKNOWN;
+ }
+ else
+ {
+ successResult = EXIT_USER;
+ break;
+ }
+ }
- /*
- * Parse line, looking for command separators.
- *
- * The current character is at line[i], the prior character at
- * line[i - prevlen], the next character at line[i + thislen].
- */
- prevlen = 0;
- thislen = (len > 0) ? PQmblen(line) : 0;
-
-#define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i))
-
- success = true;
- for (i = 0; i < len; ADVANCE_1) {
- if (!success && die_on_error)
- break;
-
-
- /* was the previous character a backslash? */
- if (i > 0 && line[i - prevlen] == '\\')
- was_bslash = true;
- else
- was_bslash = false;
-
-
- /* in quote? */
- if (in_quote) {
- /* end of quote */
- if (line[i] == in_quote && !was_bslash)
- in_quote = '\0';
- }
-
- /* start of quote */
- else if (line[i] == '\'' || line[i] == '"')
- in_quote = line[i];
-
- /* in extended comment? */
- else if (xcomment != NULL) {
- if (line[i] == '*' && line[i + thislen] == '/') {
- xcomment = NULL;
- ADVANCE_1;
+ /*
+ * establish the control-C handler only after main_loop_jmp is
+ * ready
+ */
+ pqsignal(SIGINT, handle_sigint); /* control-C => cancel */
+#endif /* not WIN32 */
+
+ if (slashCmdStatus == CMD_NEWEDIT)
+ {
+ /*
+ * just returned from editing the line? then just copy to the
+ * input buffer
+ */
+ line = xstrdup(query_buf->data);
+ resetPQExpBuffer(query_buf);
+ /* reset parsing state since we are rescanning whole line */
+ in_xcomment = false;
+ in_quote = 0;
+ paren_level = 0;
+ slashCmdStatus = CMD_UNKNOWN;
}
- }
-
- /* start of extended comment? */
- else if (line[i] == '/' && line[i + thislen] == '*') {
- xcomment = &line[i];
- ADVANCE_1;
- }
-
- /* single-line comment? truncate line */
- else if ((line[i] == '-' && line[i + thislen] == '-') ||
- (line[i] == '/' && line[i + thislen] == '/'))
- {
- line[i] = '\0'; /* remove comment */
- break;
- }
-
- /* count nested parentheses */
- else if (line[i] == '(')
- paren_level++;
-
- else if (line[i] == ')' && paren_level > 0)
- paren_level--;
-
- /* semicolon? then send query */
- else if (line[i] == ';' && !was_bslash && paren_level==0) {
- line[i] = '\0';
- /* is there anything else on the line? */
- if (line[query_start + strspn(line + query_start, " \t")]!='\0') {
- /* insert a cosmetic newline, if this is not the first line in the buffer */
- if (query_buf->len > 0)
- appendPQExpBufferChar(query_buf, '\n');
- /* append the line to the query buffer */
- appendPQExpBufferStr(query_buf, line + query_start);
+ else
+ {
+ fflush(stdout);
+
+ /*
+ * otherwise, set interactive prompt if necessary and get
+ * another line
+ */
+ if (pset.cur_cmd_interactive)
+ {
+ int prompt_status;
+
+ if (in_quote && in_quote == '\'')
+ prompt_status = PROMPT_SINGLEQUOTE;
+ else if (in_quote && in_quote == '"')
+ prompt_status = PROMPT_DOUBLEQUOTE;
+ else if (in_xcomment)
+ prompt_status = PROMPT_COMMENT;
+ else if (paren_level)
+ prompt_status = PROMPT_PAREN;
+ else if (query_buf->len > 0)
+ prompt_status = PROMPT_CONTINUE;
+ else
+ prompt_status = PROMPT_READY;
+
+ line = gets_interactive(get_prompt(prompt_status));
+ }
+ else
+ line = gets_fromFile(source);
}
- /* execute query */
- success = SendQuery(pset, query_buf->data);
-
- resetPQExpBuffer(query_buf);
- query_start = i + thislen;
- }
- /* backslash command */
- else if (was_bslash) {
- const char * end_of_cmd = NULL;
+ /* Setting this will not have effect until next line. */
+ die_on_error = GetVariableBool(pset.vars, "ON_ERROR_STOP");
+
+ /*
+ * query_buf holds query already accumulated. line is the
+ * malloc'd new line of input (note it must be freed before
+ * looping around!) query_start is the next command start location
+ * within the line.
+ */
+
+ /* No more input. Time to quit, or \i done */
+ if (line == NULL)
+ {
+ if (pset.cur_cmd_interactive)
+ {
+ bool getout = true;
+
+ /* This tries to mimic bash's IGNOREEOF feature. */
+ const char *val = GetVariable(pset.vars, "IGNOREEOF");
+
+ if (val)
+ {
+ long int maxeof;
+ char *endptr;
+
+ if (*val == '\0')
+ maxeof = 10;
+ else
+ {
+ maxeof = strtol(val, &endptr, 0);
+ if (*endptr != '\0') /* string not valid as a
+ * number */
+ maxeof = 10;
+ }
+
+ if (count_eof++ != maxeof)
+ getout = false; /* not quite there yet */
+ }
+
+ if (getout)
+ {
+ if (QUIET())
+ putc('\n', stdout);
+ else
+ puts("\\q");
+ break;
+ }
+ else
+ {
+ if (!QUIET())
+ printf(gettext("Use \"\\q\" to leave %s.\n"), pset.progname);
+ continue;
+ }
+ }
+ else
+/* not interactive */
+ break;
+ }
+ else
+ count_eof = 0;
- line[i - prevlen] = '\0'; /* overwrites backslash */
+ pset.lineno++;
- /* is there anything else on the line? */
- if (line[query_start + strspn(line + query_start, " \t")]!='\0') {
- /* insert a cosmetic newline, if this is not the first line in the buffer */
- if (query_buf->len > 0)
- appendPQExpBufferChar(query_buf, '\n');
- /* append the line to the query buffer */
- appendPQExpBufferStr(query_buf, line + query_start);
+ /* nothing left on line? then ignore */
+ if (line[0] == '\0' && !in_quote)
+ {
+ free(line);
+ continue;
}
- /* handle backslash command */
-
- slashCmdStatus = HandleSlashCmds(pset, &line[i], query_buf, &end_of_cmd);
+ /* echo back if flag is set */
+ var = GetVariable(pset.vars, "ECHO");
+ if (!pset.cur_cmd_interactive && var && strcmp(var, "all") == 0)
+ puts(line);
+ fflush(stdout);
+
+ len = strlen(line);
+ query_start = 0;
+
+ /*
+ * Parse line, looking for command separators.
+ *
+ * The current character is at line[i], the prior character at line[i
+ * - prevlen], the next character at line[i + thislen].
+ */
+#define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i, pset.encoding))
+
+ success = true;
+ for (i = 0, prevlen = 0, thislen = (len > 0) ? PQmblen(line, pset.encoding) : 0;
+ i < len;
+ ADVANCE_1)
+ {
+ /* was the previous character a backslash? */
+ bool was_bslash = (i > 0 && line[i - prevlen] == '\\');
+
+ if (was_bslash)
+ bslash_count++;
+ else
+ bslash_count = 0;
+
+ rescan:
+
+ /*
+ * It is important to place the in_* test routines before the
+ * in_* detection routines. i.e. we have to test if we are in
+ * a quote before testing for comments. bjm 2000-06-30
+ */
+
+ /* in quote? */
+ if (in_quote)
+ {
+ /* end of quote */
+ if (line[i] == in_quote && bslash_count % 2 == 0)
+ in_quote = '\0';
+ }
+
+ /* in extended comment? */
+ else if (in_xcomment)
+ {
+ if (line[i] == '*' && line[i + thislen] == '/')
+ {
+ if (xcdepth > 0)
+ xcdepth--;
+ else
+ {
+ in_xcomment = false;
+ ADVANCE_1;
+ }
+ }
+ else if (line[i] == '/' && line[i + thislen] == '*')
+ xcdepth++;
+ }
+
+ /* start of extended comment? */
+ else if (line[i] == '/' && line[i + thislen] == '*')
+ {
+ xcdepth = 0;
+ in_xcomment = true;
+ ADVANCE_1;
+ }
+
+ /* start of quote */
+ else if (!was_bslash &&
+ (line[i] == '\'' || line[i] == '"'))
+ in_quote = line[i];
+
+
+ /* single-line comment? truncate line */
+ else if (line[i] == '-' && line[i + thislen] == '-')
+ {
+ line[i] = '\0'; /* remove comment */
+ break;
+ }
+
+ /* count nested parentheses */
+ else if (line[i] == '(')
+ paren_level++;
+
+ else if (line[i] == ')' && paren_level > 0)
+ paren_level--;
+
+ /* colon -> substitute variable */
+ /* we need to be on the watch for the '::' operator */
+ else if (line[i] == ':' && !was_bslash
+ && strspn(line + i + thislen, VALID_VARIABLE_CHARS) > 0
+ && !(prevlen > 0 && line[i - prevlen] == ':')
+ )
+ {
+ size_t in_length,
+ out_length;
+ const char *value;
+ char *new;
+ char after; /* the character after the
+ * variable name will be
+ * temporarily overwritten */
+
+ in_length = strspn(&line[i + thislen], VALID_VARIABLE_CHARS);
+ after = line[i + thislen + in_length];
+ line[i + thislen + in_length] = '\0';
+
+ /*
+ * if the variable doesn't exist we'll leave the string as
+ * is
+ */
+ value = GetVariable(pset.vars, &line[i + thislen]);
+ if (value)
+ {
+ out_length = strlen(value);
+
+ new = malloc(len + out_length - (1 + in_length) + 1);
+ if (!new)
+ {
+ psql_error("out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sprintf(new, "%.*s%s%c", i, line, value, after);
+ if (after)
+ strcat(new, line + i + 1 + in_length + 1);
+
+ free(line);
+ line = new;
+ len = strlen(new);
+
+ goto rescan; /* reparse the just substituted */
+ }
+ else
+ {
+ /* restore overwritten character */
+ line[i + thislen + in_length] = after;
+ /* move on ... */
+ }
+ }
+
+ /* semicolon? then send query */
+ else if (line[i] == ';' && !was_bslash && !paren_level)
+ {
+ line[i] = '\0';
+ /* is there anything else on the line? */
+ if (line[query_start + strspn(line + query_start, " \t\n\r")] != '\0')
+ {
+ /*
+ * insert a cosmetic newline, if this is not the first
+ * line in the buffer
+ */
+ if (query_buf->len > 0)
+ appendPQExpBufferChar(query_buf, '\n');
+ /* append the line to the query buffer */
+ appendPQExpBufferStr(query_buf, line + query_start);
+ appendPQExpBufferChar(query_buf, ';');
+ }
+
+ /* execute query */
+ success = SendQuery(query_buf->data);
+ slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
+
+ resetPQExpBuffer(previous_buf);
+ appendPQExpBufferStr(previous_buf, query_buf->data);
+ resetPQExpBuffer(query_buf);
+ query_start = i + thislen;
+ }
+
+ /*
+ * if you have a burning need to send a semicolon or colon to
+ * the backend ...
+ */
+ else if (was_bslash && (line[i] == ';' || line[i] == ':'))
+ {
+ /* remove the backslash */
+ memmove(line + i - prevlen, line + i, len - i + 1);
+ len--;
+ }
+
+ /* backslash command */
+ else if (was_bslash)
+ {
+ const char *end_of_cmd = NULL;
+
+ paren_level = 0;
+ line[i - prevlen] = '\0'; /* overwrites backslash */
+
+ /* is there anything else on the line for the command? */
+ if (line[query_start + strspn(line + query_start, " \t\n\r")] != '\0')
+ {
+ /*
+ * insert a cosmetic newline, if this is not the first
+ * line in the buffer
+ */
+ if (query_buf->len > 0)
+ appendPQExpBufferChar(query_buf, '\n');
+ /* append the line to the query buffer */
+ appendPQExpBufferStr(query_buf, line + query_start);
+ }
+
+ /* handle backslash command */
+ slashCmdStatus = HandleSlashCmds(&line[i],
+ query_buf->len > 0 ? query_buf : previous_buf,
+ &end_of_cmd);
+
+ success = slashCmdStatus != CMD_ERROR;
+
+ if ((slashCmdStatus == CMD_SEND || slashCmdStatus == CMD_NEWEDIT) &&
+ query_buf->len == 0)
+ {
+ /* copy previous buffer to current for for handling */
+ appendPQExpBufferStr(query_buf, previous_buf->data);
+ }
+
+ if (slashCmdStatus == CMD_SEND)
+ {
+ success = SendQuery(query_buf->data);
+ query_start = i + thislen;
+
+ resetPQExpBuffer(previous_buf);
+ appendPQExpBufferStr(previous_buf, query_buf->data);
+ resetPQExpBuffer(query_buf);
+ }
+
+ /* process anything left after the backslash command */
+ i += end_of_cmd - &line[i];
+ query_start = i;
+ }
+
+
+ /* stop the script after error */
+ if (!success && die_on_error)
+ break;
+
+ } /* for (line) */
+
+
+ if (slashCmdStatus == CMD_TERMINATE)
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
- success = slashCmdStatus != CMD_ERROR;
- if (slashCmdStatus == CMD_SEND) {
- success = SendQuery(pset, query_buf->data);
- resetPQExpBuffer(query_buf);
- query_start = i + thislen;
+ /* Put the rest of the line in the query buffer. */
+ if (in_quote || line[query_start + strspn(line + query_start, " \t\n\r")] != '\0')
+ {
+ if (query_buf->len > 0)
+ appendPQExpBufferChar(query_buf, '\n');
+ appendPQExpBufferStr(query_buf, line + query_start);
}
- /* is there anything left after the backslash command? */
- if (end_of_cmd) {
- i += end_of_cmd - &line[i];
- query_start = i;
- }
- else
- break;
- }
- }
-
+ free(line);
- if (!success && die_on_error && !pset->cur_cmd_interactive) {
- successResult = EXIT_USER;
- break;
- }
+ /* In single line mode, send off the query if any */
+ if (query_buf->data[0] != '\0' && GetVariableBool(pset.vars, "SINGLELINE"))
+ {
+ success = SendQuery(query_buf->data);
+ slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
+ resetPQExpBuffer(previous_buf);
+ appendPQExpBufferStr(previous_buf, query_buf->data);
+ resetPQExpBuffer(query_buf);
+ }
- if (slashCmdStatus == CMD_TERMINATE) {
- successResult = EXIT_SUCCESS;
- break;
- }
+ if (!success && die_on_error && !pset.cur_cmd_interactive)
+ {
+ successResult = EXIT_USER;
+ break;
+ }
- /* Put the rest of the line in the query buffer. */
- if (line[query_start + strspn(line + query_start, " \t")]!='\0') {
- if (query_buf->len > 0)
- appendPQExpBufferChar(query_buf, '\n');
- appendPQExpBufferStr(query_buf, line + query_start);
- }
- free(line);
+ /* Have we lost the db connection? */
+ if (pset.db == NULL && !pset.cur_cmd_interactive)
+ {
+ successResult = EXIT_BADCONN;
+ break;
+ }
+ } /* while !endoffile/session */
+ /*
+ * Process query at the end of file without a semicolon
+ */
+ if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
+ successResult == EXIT_SUCCESS)
+ {
+ success = SendQuery(query_buf->data);
- /* In single line mode, send off the query if any */
- if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline")) {
- success = SendQuery(pset, query_buf->data);
- resetPQExpBuffer(query_buf);
+ if (!success && die_on_error)
+ successResult = EXIT_USER;
+ else if (pset.db == NULL)
+ successResult = EXIT_BADCONN;
}
-
- /* Have we lost the db connection? */
- if (pset->db == NULL && !pset->cur_cmd_interactive) {
- successResult = EXIT_BADCONN;
- break;
- }
- } /* while */
+ /*
+ * Reset SIGINT handler because main_loop_jmp will be invalid as soon
+ * as we exit this routine. If there is an outer MainLoop instance,
+ * it will re-enable ^C catching as soon as it gets back to the top of
+ * its loop and resets main_loop_jmp to point to itself.
+ */
+#ifndef WIN32
+ pqsignal(SIGINT, SIG_DFL);
+#endif
- destroyPQExpBuffer(query_buf);
+ destroyPQExpBuffer(query_buf);
+ destroyPQExpBuffer(previous_buf);
- pset->cur_cmd_source = prev_cmd_source;
- pset->cur_cmd_interactive = prev_cmd_interactive;
+ pset.cur_cmd_source = prev_cmd_source;
+ pset.cur_cmd_interactive = prev_cmd_interactive;
+ pset.lineno = prev_lineno;
- return successResult;
+ return successResult;
} /* MainLoop() */
-