summaryrefslogtreecommitdiff
path: root/src/bin/psql/mainloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/mainloop.c')
-rw-r--r--src/bin/psql/mainloop.c615
1 files changed, 326 insertions, 289 deletions
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index 2f38ffbcff..560488fff4 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -26,343 +26,380 @@
int
MainLoop(PsqlSettings *pset, 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;
+ 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;
+ 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;
+ int i,
+ prevlen,
+ thislen;
- /* Save the prior command source */
- FILE *prev_cmd_source;
- bool prev_cmd_interactive;
+ /* Save the prior command source */
+ FILE *prev_cmd_source;
+ bool prev_cmd_interactive;
- bool die_on_error;
- const char *interpol_char;
+ 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;
+ /* 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);
+ /* 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);
- }
+ query_buf = createPQExpBuffer();
+ if (!query_buf)
+ {
+ perror("createPQExpBuffer");
+ exit(EXIT_FAILURE);
+ }
- xcomment = NULL;
- in_quote = 0;
- paren_level = 0;
- slashCmdStatus = CMD_UNKNOWN; /* set default */
+ 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)
+ /* main loop to get queries and execute them */
+ while (!eof)
{
- /*
- * 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;
+ if (slashCmdStatus == CMD_NEWEDIT)
+ {
+
+ /*
+ * 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
- prompt_status = PROMPT_READY;
-
- line = gets_interactive(get_prompt(pset, prompt_status));
- }
- else
- line = gets_fromFile(source);
- }
+ {
+
+ /*
+ * 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");;
+ /* 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.
- */
+ /*
+ * 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;
- }
+ /* 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;
+ }
- /* not currently inside an extended comment? */
- if (xcomment)
- xcomment = line;
+ /* not currently inside an extended comment? */
+ if (xcomment)
+ xcomment = line;
- /* 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;
- }
+ /* strip trailing backslashes, they don't have a clear meaning */
+ while (1)
+ {
+ char *cp = strrchr(line, '\\');
-
- /* 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);
+ if (cp && (*(cp + 1) == '\0'))
+ *cp = '\0';
+ else
+ break;
}
- 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;
- }
- }
+ /* 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);
+ }
+
+ 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;
- }
+ /* nothing left on line? then ignore */
+ if (line[0] == '\0')
+ {
+ free(line);
+ continue;
+ }
- slashCmdStatus = CMD_UNKNOWN;
+ slashCmdStatus = CMD_UNKNOWN;
- len = strlen(line);
- query_start = 0;
+ 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].
- */
- prevlen = 0;
- thislen = (len > 0) ? PQmblen(line) : 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].
+ */
+ 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;
- }
- }
-
- /* 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);
+ 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;
+ }
+ }
+
+ /* 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);
+ }
+
+ /* 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;
+
+ line[i - prevlen] = '\0'; /* overwrites backslash */
+
+ /* 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);
+ }
+
+ /* handle backslash command */
+
+ slashCmdStatus = HandleSlashCmds(pset, &line[i], query_buf, &end_of_cmd);
+
+ success = slashCmdStatus != CMD_ERROR;
+
+ if (slashCmdStatus == CMD_SEND)
+ {
+ success = SendQuery(pset, query_buf->data);
+ resetPQExpBuffer(query_buf);
+ query_start = i + thislen;
+ }
+
+ /* is there anything left after the backslash command? */
+ if (end_of_cmd)
+ {
+ i += end_of_cmd - &line[i];
+ query_start = i;
+ }
+ else
+ break;
+ }
}
- /* 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;
-
- line[i - prevlen] = '\0'; /* overwrites backslash */
- /* 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);
+ if (!success && die_on_error && !pset->cur_cmd_interactive)
+ {
+ successResult = EXIT_USER;
+ break;
}
- /* handle backslash command */
- slashCmdStatus = HandleSlashCmds(pset, &line[i], query_buf, &end_of_cmd);
-
- success = slashCmdStatus != CMD_ERROR;
-
- if (slashCmdStatus == CMD_SEND) {
- success = SendQuery(pset, query_buf->data);
- resetPQExpBuffer(query_buf);
- query_start = i + thislen;
+ if (slashCmdStatus == CMD_TERMINATE)
+ {
+ successResult = EXIT_SUCCESS;
+ break;
}
- /* is there anything left after the backslash command? */
- if (end_of_cmd) {
- i += end_of_cmd - &line[i];
- query_start = i;
- }
- else
- 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);
+ }
- if (slashCmdStatus == CMD_TERMINATE) {
- successResult = EXIT_SUCCESS;
- break;
- }
-
+ free(line);
- /* 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);
+ /* 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);
+ }
- /* 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);
- }
-
-
- /* Have we lost the db connection? */
- if (pset->db == NULL && !pset->cur_cmd_interactive) {
- successResult = EXIT_BADCONN;
- break;
- }
- } /* while */
+ /* Have we lost the db connection? */
+ if (pset->db == NULL && !pset->cur_cmd_interactive)
+ {
+ successResult = EXIT_BADCONN;
+ break;
+ }
+ } /* while */
- destroyPQExpBuffer(query_buf);
+ destroyPQExpBuffer(query_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;
- return successResult;
+ return successResult;
} /* MainLoop() */
-