Code review for patch to show definition of index columns in \d on index.
[PostgreSQL.git] / src / bin / psql / mainloop.c
blob8a238284d7f805b586669952f88f198e34f5c041
1 /*
2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2009, PostgreSQL Global Development Group
6 * $PostgreSQL$
7 */
8 #include "postgres_fe.h"
9 #include "mainloop.h"
12 #include "command.h"
13 #include "common.h"
14 #include "input.h"
15 #include "settings.h"
19 * Main processing loop for reading lines of input
20 * and sending them to the backend.
22 * This loop is re-entrant. May be called by \i command
23 * which reads input from a file.
25 int
26 MainLoop(FILE *source)
28 PsqlScanState scan_state; /* lexer working state */
29 volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
30 volatile PQExpBuffer previous_buf; /* if there isn't anything in the new
31 * buffer yet, use this one for \e,
32 * etc. */
33 PQExpBuffer history_buf; /* earlier lines of a multi-line command, not
34 * yet saved to readline history */
35 char *line; /* current line of input */
36 int added_nl_pos;
37 bool success;
38 bool line_saved_in_history;
39 volatile int successResult = EXIT_SUCCESS;
40 volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
41 volatile promptStatus_t prompt_status = PROMPT_READY;
42 volatile int count_eof = 0;
43 volatile bool die_on_error = false;
45 /* Save the prior command source */
46 FILE *prev_cmd_source;
47 bool prev_cmd_interactive;
48 uint64 prev_lineno;
50 /* Save old settings */
51 prev_cmd_source = pset.cur_cmd_source;
52 prev_cmd_interactive = pset.cur_cmd_interactive;
53 prev_lineno = pset.lineno;
55 /* Establish new source */
56 pset.cur_cmd_source = source;
57 pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
58 pset.lineno = 0;
60 /* Create working state */
61 scan_state = psql_scan_create();
63 query_buf = createPQExpBuffer();
64 previous_buf = createPQExpBuffer();
65 history_buf = createPQExpBuffer();
66 if (PQExpBufferBroken(query_buf) ||
67 PQExpBufferBroken(previous_buf) ||
68 PQExpBufferBroken(history_buf))
70 psql_error("out of memory\n");
71 exit(EXIT_FAILURE);
74 /* main loop to get queries and execute them */
75 while (successResult == EXIT_SUCCESS)
78 * Clean up after a previous Control-C
80 if (cancel_pressed)
82 if (!pset.cur_cmd_interactive)
85 * You get here if you stopped a script with Ctrl-C.
87 successResult = EXIT_USER;
88 break;
91 cancel_pressed = false;
95 * Establish longjmp destination for exiting from wait-for-input. We
96 * must re-do this each time through the loop for safety, since the
97 * jmpbuf might get changed during command execution.
99 if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
101 /* got here with longjmp */
103 /* reset parsing state */
104 psql_scan_finish(scan_state);
105 psql_scan_reset(scan_state);
106 resetPQExpBuffer(query_buf);
107 resetPQExpBuffer(history_buf);
108 count_eof = 0;
109 slashCmdStatus = PSQL_CMD_UNKNOWN;
110 prompt_status = PROMPT_READY;
111 cancel_pressed = false;
113 if (pset.cur_cmd_interactive)
114 putc('\n', stdout);
115 else
117 successResult = EXIT_USER;
118 break;
122 fflush(stdout);
125 * get another line
127 if (pset.cur_cmd_interactive)
129 /* May need to reset prompt, eg after \r command */
130 if (query_buf->len == 0)
131 prompt_status = PROMPT_READY;
132 line = gets_interactive(get_prompt(prompt_status));
134 else
136 line = gets_fromFile(source);
137 if (!line && ferror(source))
138 successResult = EXIT_FAILURE;
142 * query_buf holds query already accumulated. line is the malloc'd
143 * new line of input (note it must be freed before looping around!)
146 /* No more input. Time to quit, or \i done */
147 if (line == NULL)
149 if (pset.cur_cmd_interactive)
151 /* This tries to mimic bash's IGNOREEOF feature. */
152 count_eof++;
154 if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10, false))
156 if (!pset.quiet)
157 printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
158 continue;
161 puts(pset.quiet ? "" : "\\q");
163 break;
166 count_eof = 0;
168 pset.lineno++;
170 /* nothing left on line? then ignore */
171 if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
173 free(line);
174 continue;
177 /* A request for help? Be friendly and give them some guidance */
178 if (pset.cur_cmd_interactive && query_buf->len == 0 &&
179 pg_strncasecmp(line, "help", 4) == 0 &&
180 (line[4] == '\0' || line[4] == ';' || isspace((unsigned char) line[4])))
182 free(line);
183 puts(_("You are using psql, the command-line interface to PostgreSQL."));
184 printf(_("Type: \\copyright for distribution terms\n"
185 " \\h for help with SQL commands\n"
186 " \\? for help with psql commands\n"
187 " \\g or terminate with semicolon to execute query\n"
188 " \\q to quit\n"));
190 fflush(stdout);
191 continue;
194 /* echo back if flag is set */
195 if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
196 puts(line);
197 fflush(stdout);
199 /* insert newlines into query buffer between source lines */
200 if (query_buf->len > 0)
202 appendPQExpBufferChar(query_buf, '\n');
203 added_nl_pos = query_buf->len;
205 else
206 added_nl_pos = -1; /* flag we didn't add one */
208 /* Setting this will not have effect until next line. */
209 die_on_error = pset.on_error_stop;
212 * Parse line, looking for command separators.
214 psql_scan_setup(scan_state, line, strlen(line));
215 success = true;
216 line_saved_in_history = false;
218 while (success || !die_on_error)
220 PsqlScanResult scan_result;
221 promptStatus_t prompt_tmp = prompt_status;
223 scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
224 prompt_status = prompt_tmp;
226 if (PQExpBufferBroken(query_buf))
228 psql_error("out of memory\n");
229 exit(EXIT_FAILURE);
233 * Send command if semicolon found, or if end of line and we're in
234 * single-line mode.
236 if (scan_result == PSCAN_SEMICOLON ||
237 (scan_result == PSCAN_EOL && pset.singleline))
240 * Save query in history. We use history_buf to accumulate
241 * multi-line queries into a single history entry.
243 if (pset.cur_cmd_interactive && !line_saved_in_history)
245 pg_append_history(line, history_buf);
246 pg_send_history(history_buf);
247 line_saved_in_history = true;
250 /* execute query */
251 success = SendQuery(query_buf->data);
252 slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
254 /* transfer query to previous_buf by pointer-swapping */
256 PQExpBuffer swap_buf = previous_buf;
258 previous_buf = query_buf;
259 query_buf = swap_buf;
261 resetPQExpBuffer(query_buf);
263 added_nl_pos = -1;
264 /* we need not do psql_scan_reset() here */
266 else if (scan_result == PSCAN_BACKSLASH)
268 /* handle backslash command */
271 * If we added a newline to query_buf, and nothing else has
272 * been inserted in query_buf by the lexer, then strip off the
273 * newline again. This avoids any change to query_buf when a
274 * line contains only a backslash command. Also, in this
275 * situation we force out any previous lines as a separate
276 * history entry; we don't want SQL and backslash commands
277 * intermixed in history if at all possible.
279 if (query_buf->len == added_nl_pos)
281 query_buf->data[--query_buf->len] = '\0';
282 pg_send_history(history_buf);
284 added_nl_pos = -1;
286 /* save backslash command in history */
287 if (pset.cur_cmd_interactive && !line_saved_in_history)
289 pg_append_history(line, history_buf);
290 pg_send_history(history_buf);
291 line_saved_in_history = true;
294 /* execute backslash command */
295 slashCmdStatus = HandleSlashCmds(scan_state,
296 query_buf->len > 0 ?
297 query_buf : previous_buf);
299 success = slashCmdStatus != PSQL_CMD_ERROR;
301 if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) &&
302 query_buf->len == 0)
304 /* copy previous buffer to current for handling */
305 appendPQExpBufferStr(query_buf, previous_buf->data);
308 if (slashCmdStatus == PSQL_CMD_SEND)
310 success = SendQuery(query_buf->data);
312 /* transfer query to previous_buf by pointer-swapping */
314 PQExpBuffer swap_buf = previous_buf;
316 previous_buf = query_buf;
317 query_buf = swap_buf;
319 resetPQExpBuffer(query_buf);
321 /* flush any paren nesting info after forced send */
322 psql_scan_reset(scan_state);
324 else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
326 /* rescan query_buf as new input */
327 psql_scan_finish(scan_state);
328 free(line);
329 line = pg_strdup(query_buf->data);
330 resetPQExpBuffer(query_buf);
331 /* reset parsing state since we are rescanning whole line */
332 psql_scan_reset(scan_state);
333 psql_scan_setup(scan_state, line, strlen(line));
334 line_saved_in_history = false;
335 prompt_status = PROMPT_READY;
337 else if (slashCmdStatus == PSQL_CMD_TERMINATE)
338 break;
341 /* fall out of loop if lexer reached EOL */
342 if (scan_result == PSCAN_INCOMPLETE ||
343 scan_result == PSCAN_EOL)
344 break;
347 /* Add line to pending history if we didn't execute anything yet */
348 if (pset.cur_cmd_interactive && !line_saved_in_history)
349 pg_append_history(line, history_buf);
351 psql_scan_finish(scan_state);
352 free(line);
354 if (slashCmdStatus == PSQL_CMD_TERMINATE)
356 successResult = EXIT_SUCCESS;
357 break;
360 if (!pset.cur_cmd_interactive)
362 if (!success && die_on_error)
363 successResult = EXIT_USER;
364 /* Have we lost the db connection? */
365 else if (!pset.db)
366 successResult = EXIT_BADCONN;
368 } /* while !endoffile/session */
371 * Process query at the end of file without a semicolon
373 if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
374 successResult == EXIT_SUCCESS)
376 /* save query in history */
377 if (pset.cur_cmd_interactive)
378 pg_send_history(history_buf);
380 /* execute query */
381 success = SendQuery(query_buf->data);
383 if (!success && die_on_error)
384 successResult = EXIT_USER;
385 else if (pset.db == NULL)
386 successResult = EXIT_BADCONN;
390 * Let's just make real sure the SIGINT handler won't try to use
391 * sigint_interrupt_jmp after we exit this routine. If there is an outer
392 * MainLoop instance, it will reset sigint_interrupt_jmp to point to
393 * itself at the top of its loop, before any further interactive input
394 * happens.
396 sigint_interrupt_enabled = false;
398 destroyPQExpBuffer(query_buf);
399 destroyPQExpBuffer(previous_buf);
400 destroyPQExpBuffer(history_buf);
402 psql_scan_destroy(scan_state);
404 pset.cur_cmd_source = prev_cmd_source;
405 pset.cur_cmd_interactive = prev_cmd_interactive;
406 pset.lineno = prev_lineno;
408 return successResult;
409 } /* MainLoop() */