2
* psql - the PostgreSQL interactive terminal
4
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
6
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.66 2005-01-01 05:43:08 momjian Exp $
8
#include "postgres_fe.h"
11
#include "pqexpbuffer.h"
22
sigjmp_buf main_loop_jmp;
27
* Main processing loop for reading lines of input
28
* and sending them to the backend.
30
* This loop is re-entrant. May be called by \i command
31
* which reads input from a file.
34
MainLoop(FILE *source)
36
PsqlScanState scan_state; /* lexer working state */
37
PQExpBuffer query_buf; /* buffer for query being accumulated */
38
PQExpBuffer previous_buf; /* if there isn't anything in the new
39
* buffer yet, use this one for \e, etc. */
40
char *line; /* current line of input */
43
volatile int successResult = EXIT_SUCCESS;
44
volatile backslashResult slashCmdStatus = CMD_UNKNOWN;
45
volatile promptStatus_t prompt_status = PROMPT_READY;
46
volatile int count_eof = 0;
47
volatile bool die_on_error = false;
49
/* Save the prior command source */
50
FILE *prev_cmd_source;
51
bool prev_cmd_interactive;
52
unsigned int prev_lineno;
54
/* Save old settings */
55
prev_cmd_source = pset.cur_cmd_source;
56
prev_cmd_interactive = pset.cur_cmd_interactive;
57
prev_lineno = pset.lineno;
59
/* Establish new source */
60
pset.cur_cmd_source = source;
61
pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
64
/* Create working state */
65
scan_state = psql_scan_create();
67
query_buf = createPQExpBuffer();
68
previous_buf = createPQExpBuffer();
69
if (!query_buf || !previous_buf)
71
psql_error("out of memory\n");
75
/* main loop to get queries and execute them */
76
while (successResult == EXIT_SUCCESS)
79
* Welcome code for Control-C
83
if (!pset.cur_cmd_interactive)
86
* You get here if you stopped a script with Ctrl-C and a
87
* query cancel was issued. In that case we don't do the
88
* longjmp, so the query routine can finish nicely.
90
successResult = EXIT_USER;
94
cancel_pressed = false;
98
if (sigsetjmp(main_loop_jmp, 1) != 0)
100
/* got here with longjmp */
102
/* reset parsing state */
103
resetPQExpBuffer(query_buf);
104
psql_scan_finish(scan_state);
105
psql_scan_reset(scan_state);
107
slashCmdStatus = CMD_UNKNOWN;
108
prompt_status = PROMPT_READY;
110
if (pset.cur_cmd_interactive)
114
successResult = EXIT_USER;
120
* establish the control-C handler only after main_loop_jmp is
123
pqsignal(SIGINT, handle_sigint); /* control-C => cancel */
126
setup_cancel_handler();
131
if (slashCmdStatus == CMD_NEWEDIT)
134
* just returned from editing the line? then just copy to the
137
line = pg_strdup(query_buf->data);
138
/* reset parsing state since we are rescanning whole line */
139
resetPQExpBuffer(query_buf);
140
psql_scan_reset(scan_state);
141
slashCmdStatus = CMD_UNKNOWN;
142
prompt_status = PROMPT_READY;
146
* otherwise, get another line
148
else if (pset.cur_cmd_interactive)
150
/* May need to reset prompt, eg after \r command */
151
if (query_buf->len == 0)
152
prompt_status = PROMPT_READY;
153
line = gets_interactive(get_prompt(prompt_status));
156
line = gets_fromFile(source);
159
* query_buf holds query already accumulated. line is the
160
* malloc'd new line of input (note it must be freed before
164
/* No more input. Time to quit, or \i done */
167
if (pset.cur_cmd_interactive)
169
/* This tries to mimic bash's IGNOREEOF feature. */
172
if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10, false))
175
printf(gettext("Use \"\\q\" to leave %s.\n"), pset.progname);
179
puts(QUIET() ? "" : "\\q");
188
/* nothing left on line? then ignore */
189
if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
195
/* echo back if flag is set */
196
if (!pset.cur_cmd_interactive &&
197
VariableEquals(pset.vars, "ECHO", "all"))
201
/* insert newlines into query buffer between source lines */
202
if (query_buf->len > 0)
204
appendPQExpBufferChar(query_buf, '\n');
205
added_nl_pos = query_buf->len;
208
added_nl_pos = -1; /* flag we didn't add one */
210
/* Setting this will not have effect until next line. */
211
die_on_error = GetVariableBool(pset.vars, "ON_ERROR_STOP");
214
* Parse line, looking for command separators.
216
psql_scan_setup(scan_state, line, strlen(line));
219
while (success || !die_on_error)
221
PsqlScanResult scan_result;
222
promptStatus_t prompt_tmp = prompt_status;
224
scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
225
prompt_status = prompt_tmp;
228
* Send command if semicolon found, or if end of line and
229
* we're in single-line mode.
231
if (scan_result == PSCAN_SEMICOLON ||
232
(scan_result == PSCAN_EOL &&
233
GetVariableBool(pset.vars, "SINGLELINE")))
236
success = SendQuery(query_buf->data);
237
slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
239
resetPQExpBuffer(previous_buf);
240
appendPQExpBufferStr(previous_buf, query_buf->data);
241
resetPQExpBuffer(query_buf);
243
/* we need not do psql_scan_reset() here */
245
else if (scan_result == PSCAN_BACKSLASH)
247
/* handle backslash command */
250
* If we added a newline to query_buf, and nothing else
251
* has been inserted in query_buf by the lexer, then strip
252
* off the newline again. This avoids any change to
253
* query_buf when a line contains only a backslash
256
if (query_buf->len == added_nl_pos)
257
query_buf->data[--query_buf->len] = '\0';
260
slashCmdStatus = HandleSlashCmds(scan_state,
262
query_buf : previous_buf);
264
success = slashCmdStatus != CMD_ERROR;
266
if ((slashCmdStatus == CMD_SEND || slashCmdStatus == CMD_NEWEDIT) &&
269
/* copy previous buffer to current for handling */
270
appendPQExpBufferStr(query_buf, previous_buf->data);
273
if (slashCmdStatus == CMD_SEND)
275
success = SendQuery(query_buf->data);
277
resetPQExpBuffer(previous_buf);
278
appendPQExpBufferStr(previous_buf, query_buf->data);
279
resetPQExpBuffer(query_buf);
281
/* flush any paren nesting info after forced send */
282
psql_scan_reset(scan_state);
285
if (slashCmdStatus == CMD_TERMINATE)
289
/* fall out of loop if lexer reached EOL */
290
if (scan_result == PSCAN_INCOMPLETE ||
291
scan_result == PSCAN_EOL)
295
psql_scan_finish(scan_state);
298
if (slashCmdStatus == CMD_TERMINATE)
300
successResult = EXIT_SUCCESS;
304
if (!pset.cur_cmd_interactive)
306
if (!success && die_on_error)
307
successResult = EXIT_USER;
308
/* Have we lost the db connection? */
310
successResult = EXIT_BADCONN;
312
} /* while !endoffile/session */
315
* Process query at the end of file without a semicolon
317
if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
318
successResult == EXIT_SUCCESS)
320
success = SendQuery(query_buf->data);
322
if (!success && die_on_error)
323
successResult = EXIT_USER;
324
else if (pset.db == NULL)
325
successResult = EXIT_BADCONN;
329
* Reset SIGINT handler because main_loop_jmp will be invalid as soon
330
* as we exit this routine. If there is an outer MainLoop instance,
331
* it will re-enable ^C catching as soon as it gets back to the top of
332
* its loop and resets main_loop_jmp to point to itself.
335
pqsignal(SIGINT, SIG_DFL);
338
destroyPQExpBuffer(query_buf);
339
destroyPQExpBuffer(previous_buf);
341
psql_scan_destroy(scan_state);
343
pset.cur_cmd_source = prev_cmd_source;
344
pset.cur_cmd_interactive = prev_cmd_interactive;
345
pset.lineno = prev_lineno;
347
return successResult;