diff options
Diffstat (limited to 'src/bin/psql/mainloop.c')
-rw-r--r-- | src/bin/psql/mainloop.c | 615 |
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() */ - |