Line data Source code
1 : /*
2 : * psql - the PostgreSQL interactive terminal
3 : *
4 : * Copyright (c) 2000-2017, PostgreSQL Global Development Group
5 : *
6 : * src/bin/psql/mainloop.c
7 : */
8 : #include "postgres_fe.h"
9 : #include "mainloop.h"
10 :
11 : #include "command.h"
12 : #include "common.h"
13 : #include "input.h"
14 : #include "prompt.h"
15 : #include "settings.h"
16 :
17 : #include "mb/pg_wchar.h"
18 :
19 :
20 : /* callback functions for our flex lexer */
21 : const PsqlScanCallbacks psqlscan_callbacks = {
22 : psql_get_variable,
23 : psql_error
24 : };
25 :
26 :
27 : /*
28 : * Main processing loop for reading lines of input
29 : * and sending them to the backend.
30 : *
31 : * This loop is re-entrant. May be called by \i command
32 : * which reads input from a file.
33 : */
34 : int
35 180 : MainLoop(FILE *source)
36 : {
37 : PsqlScanState scan_state; /* lexer working state */
38 : ConditionalStack cond_stack; /* \if status stack */
39 : volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
40 : volatile PQExpBuffer previous_buf; /* if there isn't anything in the new
41 : * buffer yet, use this one for \e,
42 : * etc. */
43 : PQExpBuffer history_buf; /* earlier lines of a multi-line command, not
44 : * yet saved to readline history */
45 : char *line; /* current line of input */
46 : int added_nl_pos;
47 : bool success;
48 : bool line_saved_in_history;
49 180 : volatile int successResult = EXIT_SUCCESS;
50 180 : volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
51 180 : volatile promptStatus_t prompt_status = PROMPT_READY;
52 180 : volatile int count_eof = 0;
53 180 : volatile bool die_on_error = false;
54 : FILE *prev_cmd_source;
55 : bool prev_cmd_interactive;
56 : uint64 prev_lineno;
57 :
58 : /* Save the prior command source */
59 180 : prev_cmd_source = pset.cur_cmd_source;
60 180 : prev_cmd_interactive = pset.cur_cmd_interactive;
61 180 : prev_lineno = pset.lineno;
62 : /* pset.stmt_lineno does not need to be saved and restored */
63 :
64 : /* Establish new source */
65 180 : pset.cur_cmd_source = source;
66 180 : pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
67 180 : pset.lineno = 0;
68 180 : pset.stmt_lineno = 1;
69 :
70 : /* Create working state */
71 180 : scan_state = psql_scan_create(&psqlscan_callbacks);
72 180 : cond_stack = conditional_stack_create();
73 180 : psql_scan_set_passthrough(scan_state, (void *) cond_stack);
74 :
75 180 : query_buf = createPQExpBuffer();
76 180 : previous_buf = createPQExpBuffer();
77 180 : history_buf = createPQExpBuffer();
78 360 : if (PQExpBufferBroken(query_buf) ||
79 360 : PQExpBufferBroken(previous_buf) ||
80 180 : PQExpBufferBroken(history_buf))
81 : {
82 0 : psql_error("out of memory\n");
83 0 : exit(EXIT_FAILURE);
84 : }
85 :
86 : /* main loop to get queries and execute them */
87 58687 : while (successResult == EXIT_SUCCESS)
88 : {
89 : /*
90 : * Clean up after a previous Control-C
91 : */
92 58507 : if (cancel_pressed)
93 : {
94 0 : if (!pset.cur_cmd_interactive)
95 : {
96 : /*
97 : * You get here if you stopped a script with Ctrl-C.
98 : */
99 0 : successResult = EXIT_USER;
100 0 : break;
101 : }
102 :
103 0 : cancel_pressed = false;
104 : }
105 :
106 : /*
107 : * Establish longjmp destination for exiting from wait-for-input. We
108 : * must re-do this each time through the loop for safety, since the
109 : * jmpbuf might get changed during command execution.
110 : */
111 58507 : if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
112 : {
113 : /* got here with longjmp */
114 :
115 : /* reset parsing state */
116 0 : psql_scan_finish(scan_state);
117 0 : psql_scan_reset(scan_state);
118 0 : resetPQExpBuffer(query_buf);
119 0 : resetPQExpBuffer(history_buf);
120 0 : count_eof = 0;
121 0 : slashCmdStatus = PSQL_CMD_UNKNOWN;
122 0 : prompt_status = PROMPT_READY;
123 0 : pset.stmt_lineno = 1;
124 0 : cancel_pressed = false;
125 :
126 0 : if (pset.cur_cmd_interactive)
127 : {
128 0 : putc('\n', stdout);
129 :
130 : /*
131 : * if interactive user is in an \if block, then Ctrl-C will
132 : * exit from the innermost \if.
133 : */
134 0 : if (!conditional_stack_empty(cond_stack))
135 : {
136 0 : psql_error("\\if: escaped\n");
137 0 : conditional_stack_pop(cond_stack);
138 : }
139 : }
140 : else
141 : {
142 0 : successResult = EXIT_USER;
143 0 : break;
144 : }
145 : }
146 :
147 58507 : fflush(stdout);
148 :
149 : /*
150 : * get another line
151 : */
152 58507 : if (pset.cur_cmd_interactive)
153 : {
154 : /* May need to reset prompt, eg after \r command */
155 0 : if (query_buf->len == 0)
156 0 : prompt_status = PROMPT_READY;
157 0 : line = gets_interactive(get_prompt(prompt_status, cond_stack),
158 : query_buf);
159 : }
160 : else
161 : {
162 58507 : line = gets_fromFile(source);
163 58507 : if (!line && ferror(source))
164 0 : successResult = EXIT_FAILURE;
165 : }
166 :
167 : /*
168 : * query_buf holds query already accumulated. line is the malloc'd
169 : * new line of input (note it must be freed before looping around!)
170 : */
171 :
172 : /* No more input. Time to quit, or \i done */
173 58507 : if (line == NULL)
174 : {
175 180 : if (pset.cur_cmd_interactive)
176 : {
177 : /* This tries to mimic bash's IGNOREEOF feature. */
178 0 : count_eof++;
179 :
180 0 : if (count_eof < pset.ignoreeof)
181 : {
182 0 : if (!pset.quiet)
183 0 : printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
184 0 : continue;
185 : }
186 :
187 0 : puts(pset.quiet ? "" : "\\q");
188 : }
189 180 : break;
190 : }
191 :
192 58327 : count_eof = 0;
193 :
194 58327 : pset.lineno++;
195 :
196 : /* ignore UTF-8 Unicode byte-order mark */
197 58327 : if (pset.lineno == 1 && pset.encoding == PG_UTF8 && strncmp(line, "\xef\xbb\xbf", 3) == 0)
198 0 : memmove(line, line + 3, strlen(line + 3) + 1);
199 :
200 : /* Detect attempts to run custom-format dumps as SQL scripts */
201 58506 : if (pset.lineno == 1 && !pset.cur_cmd_interactive &&
202 179 : strncmp(line, "PGDMP", 5) == 0)
203 : {
204 0 : free(line);
205 0 : puts(_("The input is a PostgreSQL custom-format dump.\n"
206 : "Use the pg_restore command-line client to restore this dump to a database.\n"));
207 0 : fflush(stdout);
208 0 : successResult = EXIT_FAILURE;
209 0 : break;
210 : }
211 :
212 : /* no further processing of empty lines, unless within a literal */
213 58327 : if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
214 : {
215 11252 : free(line);
216 11252 : continue;
217 : }
218 :
219 : /* A request for help? Be friendly and give them some guidance */
220 47075 : if (pset.cur_cmd_interactive && query_buf->len == 0 &&
221 0 : pg_strncasecmp(line, "help", 4) == 0 &&
222 0 : (line[4] == '\0' || line[4] == ';' || isspace((unsigned char) line[4])))
223 : {
224 0 : free(line);
225 0 : puts(_("You are using psql, the command-line interface to PostgreSQL."));
226 0 : printf(_("Type: \\copyright for distribution terms\n"
227 : " \\h for help with SQL commands\n"
228 : " \\? for help with psql commands\n"
229 : " \\g or terminate with semicolon to execute query\n"
230 : " \\q to quit\n"));
231 :
232 0 : fflush(stdout);
233 0 : continue;
234 : }
235 :
236 : /* echo back if flag is set, unless interactive */
237 47075 : if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
238 : {
239 47073 : puts(line);
240 47073 : fflush(stdout);
241 : }
242 :
243 : /* insert newlines into query buffer between source lines */
244 47075 : if (query_buf->len > 0)
245 : {
246 14406 : appendPQExpBufferChar(query_buf, '\n');
247 14406 : added_nl_pos = query_buf->len;
248 : }
249 : else
250 32669 : added_nl_pos = -1; /* flag we didn't add one */
251 :
252 : /* Setting this will not have effect until next line. */
253 47075 : die_on_error = pset.on_error_stop;
254 :
255 : /*
256 : * Parse line, looking for command separators.
257 : */
258 47075 : psql_scan_setup(scan_state, line, strlen(line),
259 47075 : pset.encoding, standard_strings());
260 47075 : success = true;
261 47075 : line_saved_in_history = false;
262 :
263 119124 : while (success || !die_on_error)
264 : {
265 : PsqlScanResult scan_result;
266 72049 : promptStatus_t prompt_tmp = prompt_status;
267 : size_t pos_in_query;
268 : char *tmp_line;
269 :
270 72049 : pos_in_query = query_buf->len;
271 72049 : scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
272 72049 : prompt_status = prompt_tmp;
273 :
274 72049 : if (PQExpBufferBroken(query_buf))
275 : {
276 0 : psql_error("out of memory\n");
277 0 : exit(EXIT_FAILURE);
278 : }
279 :
280 : /*
281 : * Increase statement line number counter for each linebreak added
282 : * to the query buffer by the last psql_scan() call. There only
283 : * will be ones to add when navigating to a statement in
284 : * readline's history containing newlines.
285 : */
286 72049 : tmp_line = query_buf->data + pos_in_query;
287 1717410 : while (*tmp_line != '\0')
288 : {
289 1573312 : if (*(tmp_line++) == '\n')
290 0 : pset.stmt_lineno++;
291 : }
292 :
293 72049 : if (scan_result == PSCAN_EOL)
294 7209 : pset.stmt_lineno++;
295 :
296 : /*
297 : * Send command if semicolon found, or if end of line and we're in
298 : * single-line mode.
299 : */
300 72049 : if (scan_result == PSCAN_SEMICOLON ||
301 7209 : (scan_result == PSCAN_EOL && pset.singleline))
302 : {
303 : /*
304 : * Save line in history. We use history_buf to accumulate
305 : * multi-line queries into a single history entry. Note that
306 : * history accumulation works on input lines, so it doesn't
307 : * matter whether the query will be ignored due to \if.
308 : */
309 24189 : if (pset.cur_cmd_interactive && !line_saved_in_history)
310 : {
311 0 : pg_append_history(line, history_buf);
312 0 : pg_send_history(history_buf);
313 0 : line_saved_in_history = true;
314 : }
315 :
316 : /* execute query unless we're in an inactive \if branch */
317 48378 : if (conditional_active(cond_stack))
318 : {
319 24188 : success = SendQuery(query_buf->data);
320 24188 : slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
321 24188 : pset.stmt_lineno = 1;
322 :
323 : /* transfer query to previous_buf by pointer-swapping */
324 : {
325 24188 : PQExpBuffer swap_buf = previous_buf;
326 :
327 24188 : previous_buf = query_buf;
328 24188 : query_buf = swap_buf;
329 : }
330 24188 : resetPQExpBuffer(query_buf);
331 :
332 24188 : added_nl_pos = -1;
333 : /* we need not do psql_scan_reset() here */
334 : }
335 : else
336 : {
337 : /* if interactive, warn about non-executed query */
338 1 : if (pset.cur_cmd_interactive)
339 0 : psql_error("query ignored; use \\endif or Ctrl-C to exit current \\if block\n");
340 : /* fake an OK result for purposes of loop checks */
341 1 : success = true;
342 1 : slashCmdStatus = PSQL_CMD_SEND;
343 1 : pset.stmt_lineno = 1;
344 : /* note that query_buf doesn't change state */
345 : }
346 : }
347 47860 : else if (scan_result == PSCAN_BACKSLASH)
348 : {
349 : /* handle backslash command */
350 :
351 : /*
352 : * If we added a newline to query_buf, and nothing else has
353 : * been inserted in query_buf by the lexer, then strip off the
354 : * newline again. This avoids any change to query_buf when a
355 : * line contains only a backslash command. Also, in this
356 : * situation we force out any previous lines as a separate
357 : * history entry; we don't want SQL and backslash commands
358 : * intermixed in history if at all possible.
359 : */
360 785 : if (query_buf->len == added_nl_pos)
361 : {
362 12 : query_buf->data[--query_buf->len] = '\0';
363 12 : pg_send_history(history_buf);
364 : }
365 785 : added_nl_pos = -1;
366 :
367 : /* save backslash command in history */
368 785 : if (pset.cur_cmd_interactive && !line_saved_in_history)
369 : {
370 0 : pg_append_history(line, history_buf);
371 0 : pg_send_history(history_buf);
372 0 : line_saved_in_history = true;
373 : }
374 :
375 : /* execute backslash command */
376 785 : slashCmdStatus = HandleSlashCmds(scan_state,
377 : cond_stack,
378 : query_buf,
379 : previous_buf);
380 :
381 785 : success = slashCmdStatus != PSQL_CMD_ERROR;
382 :
383 : /*
384 : * Resetting stmt_lineno after a backslash command isn't
385 : * always appropriate, but it's what we've done historically
386 : * and there have been few complaints.
387 : */
388 785 : pset.stmt_lineno = 1;
389 :
390 785 : if (slashCmdStatus == PSQL_CMD_SEND)
391 : {
392 : /* should not see this in inactive branch */
393 56 : Assert(conditional_active(cond_stack));
394 :
395 56 : success = SendQuery(query_buf->data);
396 :
397 : /* transfer query to previous_buf by pointer-swapping */
398 : {
399 56 : PQExpBuffer swap_buf = previous_buf;
400 :
401 56 : previous_buf = query_buf;
402 56 : query_buf = swap_buf;
403 : }
404 56 : resetPQExpBuffer(query_buf);
405 :
406 : /* flush any paren nesting info after forced send */
407 56 : psql_scan_reset(scan_state);
408 : }
409 729 : else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
410 : {
411 : /* should not see this in inactive branch */
412 0 : Assert(conditional_active(cond_stack));
413 : /* rescan query_buf as new input */
414 0 : psql_scan_finish(scan_state);
415 0 : free(line);
416 0 : line = pg_strdup(query_buf->data);
417 0 : resetPQExpBuffer(query_buf);
418 : /* reset parsing state since we are rescanning whole line */
419 0 : psql_scan_reset(scan_state);
420 0 : psql_scan_setup(scan_state, line, strlen(line),
421 0 : pset.encoding, standard_strings());
422 0 : line_saved_in_history = false;
423 0 : prompt_status = PROMPT_READY;
424 : }
425 729 : else if (slashCmdStatus == PSQL_CMD_TERMINATE)
426 47075 : break;
427 : }
428 :
429 : /* fall out of loop if lexer reached EOL */
430 72049 : if (scan_result == PSCAN_INCOMPLETE ||
431 : scan_result == PSCAN_EOL)
432 : break;
433 : }
434 :
435 : /* Add line to pending history if we didn't execute anything yet */
436 47075 : if (pset.cur_cmd_interactive && !line_saved_in_history)
437 0 : pg_append_history(line, history_buf);
438 :
439 47075 : psql_scan_finish(scan_state);
440 47075 : free(line);
441 :
442 47075 : if (slashCmdStatus == PSQL_CMD_TERMINATE)
443 : {
444 0 : successResult = EXIT_SUCCESS;
445 0 : break;
446 : }
447 :
448 47075 : if (!pset.cur_cmd_interactive)
449 : {
450 47075 : if (!success && die_on_error)
451 0 : successResult = EXIT_USER;
452 : /* Have we lost the db connection? */
453 47075 : else if (!pset.db)
454 0 : successResult = EXIT_BADCONN;
455 : }
456 : } /* while !endoffile/session */
457 :
458 : /*
459 : * Process query at the end of file without a semicolon
460 : */
461 181 : if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
462 1 : successResult == EXIT_SUCCESS)
463 : {
464 : /* save query in history */
465 1 : if (pset.cur_cmd_interactive)
466 0 : pg_send_history(history_buf);
467 :
468 : /* execute query unless we're in an inactive \if branch */
469 1 : if (conditional_active(cond_stack))
470 : {
471 1 : success = SendQuery(query_buf->data);
472 : }
473 : else
474 : {
475 0 : if (pset.cur_cmd_interactive)
476 0 : psql_error("query ignored; use \\endif or Ctrl-C to exit current \\if block\n");
477 0 : success = true;
478 : }
479 :
480 1 : if (!success && die_on_error)
481 0 : successResult = EXIT_USER;
482 1 : else if (pset.db == NULL)
483 0 : successResult = EXIT_BADCONN;
484 : }
485 :
486 : /*
487 : * Check for unbalanced \if-\endifs unless user explicitly quit, or the
488 : * script is erroring out
489 : */
490 360 : if (slashCmdStatus != PSQL_CMD_TERMINATE &&
491 360 : successResult != EXIT_USER &&
492 180 : !conditional_stack_empty(cond_stack))
493 : {
494 0 : psql_error("reached EOF without finding closing \\endif(s)\n");
495 0 : if (die_on_error && !pset.cur_cmd_interactive)
496 0 : successResult = EXIT_USER;
497 : }
498 :
499 : /*
500 : * Let's just make real sure the SIGINT handler won't try to use
501 : * sigint_interrupt_jmp after we exit this routine. If there is an outer
502 : * MainLoop instance, it will reset sigint_interrupt_jmp to point to
503 : * itself at the top of its loop, before any further interactive input
504 : * happens.
505 : */
506 180 : sigint_interrupt_enabled = false;
507 :
508 180 : destroyPQExpBuffer(query_buf);
509 180 : destroyPQExpBuffer(previous_buf);
510 180 : destroyPQExpBuffer(history_buf);
511 :
512 180 : psql_scan_destroy(scan_state);
513 180 : conditional_stack_destroy(cond_stack);
514 :
515 180 : pset.cur_cmd_source = prev_cmd_source;
516 180 : pset.cur_cmd_interactive = prev_cmd_interactive;
517 180 : pset.lineno = prev_lineno;
518 :
519 180 : return successResult;
520 : } /* MainLoop() */
|