1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2021, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/mainloop.c
7  */
8 #include "postgres_fe.h"
9 
10 #include "command.h"
11 #include "common.h"
12 #include "common/logging.h"
13 #include "input.h"
14 #include "mainloop.h"
15 #include "mb/pg_wchar.h"
16 #include "prompt.h"
17 #include "settings.h"
18 
19 /* callback functions for our flex lexer */
20 const PsqlScanCallbacks psqlscan_callbacks = {
21 	psql_get_variable,
22 };
23 
24 
25 /*
26  * Main processing loop for reading lines of input
27  *	and sending them to the backend.
28  *
29  * This loop is re-entrant. May be called by \i command
30  *	which reads input from a file.
31  */
32 int
MainLoop(FILE * source)33 MainLoop(FILE *source)
34 {
35 	PsqlScanState scan_state;	/* lexer working state */
36 	ConditionalStack cond_stack;	/* \if status stack */
37 	volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
38 	volatile PQExpBuffer previous_buf;	/* if there isn't anything in the new
39 										 * buffer yet, use this one for \e,
40 										 * etc. */
41 	PQExpBuffer history_buf;	/* earlier lines of a multi-line command, not
42 								 * yet saved to readline history */
43 	char	   *line;			/* current line of input */
44 	int			added_nl_pos;
45 	bool		success;
46 	bool		line_saved_in_history;
47 	volatile int successResult = EXIT_SUCCESS;
48 	volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
49 	volatile promptStatus_t prompt_status = PROMPT_READY;
50 	volatile bool need_redisplay = false;
51 	volatile int count_eof = 0;
52 	volatile bool die_on_error = false;
53 	FILE	   *prev_cmd_source;
54 	bool		prev_cmd_interactive;
55 	uint64		prev_lineno;
56 
57 	/* Save the prior command source */
58 	prev_cmd_source = pset.cur_cmd_source;
59 	prev_cmd_interactive = pset.cur_cmd_interactive;
60 	prev_lineno = pset.lineno;
61 	/* pset.stmt_lineno does not need to be saved and restored */
62 
63 	/* Establish new source */
64 	pset.cur_cmd_source = source;
65 	pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
66 	pset.lineno = 0;
67 	pset.stmt_lineno = 1;
68 
69 	/* Create working state */
70 	scan_state = psql_scan_create(&psqlscan_callbacks);
71 	cond_stack = conditional_stack_create();
72 	psql_scan_set_passthrough(scan_state, (void *) cond_stack);
73 
74 	query_buf = createPQExpBuffer();
75 	previous_buf = createPQExpBuffer();
76 	history_buf = createPQExpBuffer();
77 	if (PQExpBufferBroken(query_buf) ||
78 		PQExpBufferBroken(previous_buf) ||
79 		PQExpBufferBroken(history_buf))
80 	{
81 		pg_log_error("out of memory");
82 		exit(EXIT_FAILURE);
83 	}
84 
85 	/* main loop to get queries and execute them */
86 	while (successResult == EXIT_SUCCESS)
87 	{
88 		/*
89 		 * Clean up after a previous Control-C
90 		 */
91 		if (cancel_pressed)
92 		{
93 			if (!pset.cur_cmd_interactive)
94 			{
95 				/*
96 				 * You get here if you stopped a script with Ctrl-C.
97 				 */
98 				successResult = EXIT_USER;
99 				break;
100 			}
101 
102 			cancel_pressed = false;
103 		}
104 
105 		/*
106 		 * Establish longjmp destination for exiting from wait-for-input. We
107 		 * must re-do this each time through the loop for safety, since the
108 		 * jmpbuf might get changed during command execution.
109 		 */
110 		if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
111 		{
112 			/* got here with longjmp */
113 
114 			/* reset parsing state */
115 			psql_scan_finish(scan_state);
116 			psql_scan_reset(scan_state);
117 			resetPQExpBuffer(query_buf);
118 			resetPQExpBuffer(history_buf);
119 			count_eof = 0;
120 			slashCmdStatus = PSQL_CMD_UNKNOWN;
121 			prompt_status = PROMPT_READY;
122 			need_redisplay = false;
123 			pset.stmt_lineno = 1;
124 			cancel_pressed = false;
125 
126 			if (pset.cur_cmd_interactive)
127 			{
128 				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 				if (!conditional_stack_empty(cond_stack))
135 				{
136 					pg_log_error("\\if: escaped");
137 					conditional_stack_pop(cond_stack);
138 				}
139 			}
140 			else
141 			{
142 				successResult = EXIT_USER;
143 				break;
144 			}
145 		}
146 
147 		fflush(stdout);
148 
149 		/*
150 		 * get another line
151 		 */
152 		if (pset.cur_cmd_interactive)
153 		{
154 			/* May need to reset prompt, eg after \r command */
155 			if (query_buf->len == 0)
156 				prompt_status = PROMPT_READY;
157 			/* If query buffer came from \e, redisplay it with a prompt */
158 			if (need_redisplay)
159 			{
160 				if (query_buf->len > 0)
161 				{
162 					fputs(get_prompt(PROMPT_READY, cond_stack), stdout);
163 					fputs(query_buf->data, stdout);
164 					fflush(stdout);
165 				}
166 				need_redisplay = false;
167 			}
168 			/* Now we can fetch a line */
169 			line = gets_interactive(get_prompt(prompt_status, cond_stack),
170 									query_buf);
171 		}
172 		else
173 		{
174 			line = gets_fromFile(source);
175 			if (!line && ferror(source))
176 				successResult = EXIT_FAILURE;
177 		}
178 
179 		/*
180 		 * query_buf holds query already accumulated.  line is the malloc'd
181 		 * new line of input (note it must be freed before looping around!)
182 		 */
183 
184 		/* No more input.  Time to quit, or \i done */
185 		if (line == NULL)
186 		{
187 			if (pset.cur_cmd_interactive)
188 			{
189 				/* This tries to mimic bash's IGNOREEOF feature. */
190 				count_eof++;
191 
192 				if (count_eof < pset.ignoreeof)
193 				{
194 					if (!pset.quiet)
195 						printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
196 					continue;
197 				}
198 
199 				puts(pset.quiet ? "" : "\\q");
200 			}
201 			break;
202 		}
203 
204 		count_eof = 0;
205 
206 		pset.lineno++;
207 
208 		/* ignore UTF-8 Unicode byte-order mark */
209 		if (pset.lineno == 1 && pset.encoding == PG_UTF8 && strncmp(line, "\xef\xbb\xbf", 3) == 0)
210 			memmove(line, line + 3, strlen(line + 3) + 1);
211 
212 		/* Detect attempts to run custom-format dumps as SQL scripts */
213 		if (pset.lineno == 1 && !pset.cur_cmd_interactive &&
214 			strncmp(line, "PGDMP", 5) == 0)
215 		{
216 			free(line);
217 			puts(_("The input is a PostgreSQL custom-format dump.\n"
218 				   "Use the pg_restore command-line client to restore this dump to a database.\n"));
219 			fflush(stdout);
220 			successResult = EXIT_FAILURE;
221 			break;
222 		}
223 
224 		/* no further processing of empty lines, unless within a literal */
225 		if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
226 		{
227 			free(line);
228 			continue;
229 		}
230 
231 		/* Recognize "help", "quit", "exit" only in interactive mode */
232 		if (pset.cur_cmd_interactive)
233 		{
234 			char	   *first_word = line;
235 			char	   *rest_of_line = NULL;
236 			bool		found_help = false;
237 			bool		found_exit_or_quit = false;
238 			bool		found_q = false;
239 
240 			/*
241 			 * The assistance words, help/exit/quit, must have no whitespace
242 			 * before them, and only whitespace after, with an optional
243 			 * semicolon.  This prevents indented use of these words, perhaps
244 			 * as identifiers, from invoking the assistance behavior.
245 			 */
246 			if (pg_strncasecmp(first_word, "help", 4) == 0)
247 			{
248 				rest_of_line = first_word + 4;
249 				found_help = true;
250 			}
251 			else if (pg_strncasecmp(first_word, "exit", 4) == 0 ||
252 					 pg_strncasecmp(first_word, "quit", 4) == 0)
253 			{
254 				rest_of_line = first_word + 4;
255 				found_exit_or_quit = true;
256 			}
257 			else if (strncmp(first_word, "\\q", 2) == 0)
258 			{
259 				rest_of_line = first_word + 2;
260 				found_q = true;
261 			}
262 
263 			/*
264 			 * If we found a command word, check whether the rest of the line
265 			 * contains only whitespace plus maybe one semicolon.  If not,
266 			 * ignore the command word after all.  These commands are only for
267 			 * compatibility with other SQL clients and are not documented.
268 			 */
269 			if (rest_of_line != NULL)
270 			{
271 				/*
272 				 * Ignore unless rest of line is whitespace, plus maybe one
273 				 * semicolon
274 				 */
275 				while (isspace((unsigned char) *rest_of_line))
276 					++rest_of_line;
277 				if (*rest_of_line == ';')
278 					++rest_of_line;
279 				while (isspace((unsigned char) *rest_of_line))
280 					++rest_of_line;
281 				if (*rest_of_line != '\0')
282 				{
283 					found_help = false;
284 					found_exit_or_quit = false;
285 				}
286 			}
287 
288 			/*
289 			 * "help" is only a command when the query buffer is empty, but we
290 			 * emit a one-line message even when it isn't to help confused
291 			 * users.  The text is still added to the query buffer in that
292 			 * case.
293 			 */
294 			if (found_help)
295 			{
296 				if (query_buf->len != 0)
297 #ifndef WIN32
298 					puts(_("Use \\? for help or press control-C to clear the input buffer."));
299 #else
300 					puts(_("Use \\? for help."));
301 #endif
302 				else
303 				{
304 					puts(_("You are using psql, the command-line interface to PostgreSQL."));
305 					printf(_("Type:  \\copyright for distribution terms\n"
306 							 "       \\h for help with SQL commands\n"
307 							 "       \\? for help with psql commands\n"
308 							 "       \\g or terminate with semicolon to execute query\n"
309 							 "       \\q to quit\n"));
310 					free(line);
311 					fflush(stdout);
312 					continue;
313 				}
314 			}
315 
316 			/*
317 			 * "quit" and "exit" are only commands when the query buffer is
318 			 * empty, but we emit a one-line message even when it isn't to
319 			 * help confused users.  The text is still added to the query
320 			 * buffer in that case.
321 			 */
322 			if (found_exit_or_quit)
323 			{
324 				if (query_buf->len != 0)
325 				{
326 					if (prompt_status == PROMPT_READY ||
327 						prompt_status == PROMPT_CONTINUE ||
328 						prompt_status == PROMPT_PAREN)
329 						puts(_("Use \\q to quit."));
330 					else
331 #ifndef WIN32
332 						puts(_("Use control-D to quit."));
333 #else
334 						puts(_("Use control-C to quit."));
335 #endif
336 				}
337 				else
338 				{
339 					/* exit app */
340 					free(line);
341 					fflush(stdout);
342 					successResult = EXIT_SUCCESS;
343 					break;
344 				}
345 			}
346 
347 			/*
348 			 * If they typed "\q" in a place where "\q" is not active, supply
349 			 * a hint.  The text is still added to the query buffer.
350 			 */
351 			if (found_q && query_buf->len != 0 &&
352 				prompt_status != PROMPT_READY &&
353 				prompt_status != PROMPT_CONTINUE &&
354 				prompt_status != PROMPT_PAREN)
355 #ifndef WIN32
356 				puts(_("Use control-D to quit."));
357 #else
358 				puts(_("Use control-C to quit."));
359 #endif
360 		}
361 
362 		/* echo back if flag is set, unless interactive */
363 		if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
364 		{
365 			puts(line);
366 			fflush(stdout);
367 		}
368 
369 		/* insert newlines into query buffer between source lines */
370 		if (query_buf->len > 0)
371 		{
372 			appendPQExpBufferChar(query_buf, '\n');
373 			added_nl_pos = query_buf->len;
374 		}
375 		else
376 			added_nl_pos = -1;	/* flag we didn't add one */
377 
378 		/* Setting this will not have effect until next line. */
379 		die_on_error = pset.on_error_stop;
380 
381 		/*
382 		 * Parse line, looking for command separators.
383 		 */
384 		psql_scan_setup(scan_state, line, strlen(line),
385 						pset.encoding, standard_strings());
386 		success = true;
387 		line_saved_in_history = false;
388 
389 		while (success || !die_on_error)
390 		{
391 			PsqlScanResult scan_result;
392 			promptStatus_t prompt_tmp = prompt_status;
393 			size_t		pos_in_query;
394 			char	   *tmp_line;
395 
396 			pos_in_query = query_buf->len;
397 			scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
398 			prompt_status = prompt_tmp;
399 
400 			if (PQExpBufferBroken(query_buf))
401 			{
402 				pg_log_error("out of memory");
403 				exit(EXIT_FAILURE);
404 			}
405 
406 			/*
407 			 * Increase statement line number counter for each linebreak added
408 			 * to the query buffer by the last psql_scan() call. There only
409 			 * will be ones to add when navigating to a statement in
410 			 * readline's history containing newlines.
411 			 */
412 			tmp_line = query_buf->data + pos_in_query;
413 			while (*tmp_line != '\0')
414 			{
415 				if (*(tmp_line++) == '\n')
416 					pset.stmt_lineno++;
417 			}
418 
419 			if (scan_result == PSCAN_EOL)
420 				pset.stmt_lineno++;
421 
422 			/*
423 			 * Send command if semicolon found, or if end of line and we're in
424 			 * single-line mode.
425 			 */
426 			if (scan_result == PSCAN_SEMICOLON ||
427 				(scan_result == PSCAN_EOL && pset.singleline))
428 			{
429 				/*
430 				 * Save line in history.  We use history_buf to accumulate
431 				 * multi-line queries into a single history entry.  Note that
432 				 * history accumulation works on input lines, so it doesn't
433 				 * matter whether the query will be ignored due to \if.
434 				 */
435 				if (pset.cur_cmd_interactive && !line_saved_in_history)
436 				{
437 					pg_append_history(line, history_buf);
438 					pg_send_history(history_buf);
439 					line_saved_in_history = true;
440 				}
441 
442 				/* execute query unless we're in an inactive \if branch */
443 				if (conditional_active(cond_stack))
444 				{
445 					success = SendQuery(query_buf->data);
446 					slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
447 					pset.stmt_lineno = 1;
448 
449 					/* transfer query to previous_buf by pointer-swapping */
450 					{
451 						PQExpBuffer swap_buf = previous_buf;
452 
453 						previous_buf = query_buf;
454 						query_buf = swap_buf;
455 					}
456 					resetPQExpBuffer(query_buf);
457 
458 					added_nl_pos = -1;
459 					/* we need not do psql_scan_reset() here */
460 				}
461 				else
462 				{
463 					/* if interactive, warn about non-executed query */
464 					if (pset.cur_cmd_interactive)
465 						pg_log_error("query ignored; use \\endif or Ctrl-C to exit current \\if block");
466 					/* fake an OK result for purposes of loop checks */
467 					success = true;
468 					slashCmdStatus = PSQL_CMD_SEND;
469 					pset.stmt_lineno = 1;
470 					/* note that query_buf doesn't change state */
471 				}
472 			}
473 			else if (scan_result == PSCAN_BACKSLASH)
474 			{
475 				/* handle backslash command */
476 
477 				/*
478 				 * If we added a newline to query_buf, and nothing else has
479 				 * been inserted in query_buf by the lexer, then strip off the
480 				 * newline again.  This avoids any change to query_buf when a
481 				 * line contains only a backslash command.  Also, in this
482 				 * situation we force out any previous lines as a separate
483 				 * history entry; we don't want SQL and backslash commands
484 				 * intermixed in history if at all possible.
485 				 */
486 				if (query_buf->len == added_nl_pos)
487 				{
488 					query_buf->data[--query_buf->len] = '\0';
489 					pg_send_history(history_buf);
490 				}
491 				added_nl_pos = -1;
492 
493 				/* save backslash command in history */
494 				if (pset.cur_cmd_interactive && !line_saved_in_history)
495 				{
496 					pg_append_history(line, history_buf);
497 					pg_send_history(history_buf);
498 					line_saved_in_history = true;
499 				}
500 
501 				/* execute backslash command */
502 				slashCmdStatus = HandleSlashCmds(scan_state,
503 												 cond_stack,
504 												 query_buf,
505 												 previous_buf);
506 
507 				success = slashCmdStatus != PSQL_CMD_ERROR;
508 
509 				/*
510 				 * Resetting stmt_lineno after a backslash command isn't
511 				 * always appropriate, but it's what we've done historically
512 				 * and there have been few complaints.
513 				 */
514 				pset.stmt_lineno = 1;
515 
516 				if (slashCmdStatus == PSQL_CMD_SEND)
517 				{
518 					/* should not see this in inactive branch */
519 					Assert(conditional_active(cond_stack));
520 
521 					success = SendQuery(query_buf->data);
522 
523 					/* transfer query to previous_buf by pointer-swapping */
524 					{
525 						PQExpBuffer swap_buf = previous_buf;
526 
527 						previous_buf = query_buf;
528 						query_buf = swap_buf;
529 					}
530 					resetPQExpBuffer(query_buf);
531 
532 					/* flush any paren nesting info after forced send */
533 					psql_scan_reset(scan_state);
534 				}
535 				else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
536 				{
537 					/* should not see this in inactive branch */
538 					Assert(conditional_active(cond_stack));
539 					/* ensure what came back from editing ends in a newline */
540 					if (query_buf->len > 0 &&
541 						query_buf->data[query_buf->len - 1] != '\n')
542 						appendPQExpBufferChar(query_buf, '\n');
543 					/* rescan query_buf as new input */
544 					psql_scan_finish(scan_state);
545 					free(line);
546 					line = pg_strdup(query_buf->data);
547 					resetPQExpBuffer(query_buf);
548 					/* reset parsing state since we are rescanning whole line */
549 					psql_scan_reset(scan_state);
550 					psql_scan_setup(scan_state, line, strlen(line),
551 									pset.encoding, standard_strings());
552 					line_saved_in_history = false;
553 					prompt_status = PROMPT_READY;
554 					/* we'll want to redisplay after parsing what we have */
555 					need_redisplay = true;
556 				}
557 				else if (slashCmdStatus == PSQL_CMD_TERMINATE)
558 					break;
559 			}
560 
561 			/* fall out of loop if lexer reached EOL */
562 			if (scan_result == PSCAN_INCOMPLETE ||
563 				scan_result == PSCAN_EOL)
564 				break;
565 		}
566 
567 		/* Add line to pending history if we didn't execute anything yet */
568 		if (pset.cur_cmd_interactive && !line_saved_in_history)
569 			pg_append_history(line, history_buf);
570 
571 		psql_scan_finish(scan_state);
572 		free(line);
573 
574 		if (slashCmdStatus == PSQL_CMD_TERMINATE)
575 		{
576 			successResult = EXIT_SUCCESS;
577 			break;
578 		}
579 
580 		if (!pset.cur_cmd_interactive)
581 		{
582 			if (!success && die_on_error)
583 				successResult = EXIT_USER;
584 			/* Have we lost the db connection? */
585 			else if (!pset.db)
586 				successResult = EXIT_BADCONN;
587 		}
588 	}							/* while !endoffile/session */
589 
590 	/*
591 	 * If we have a non-semicolon-terminated query at the end of file, we
592 	 * process it unless the input source is interactive --- in that case it
593 	 * seems better to go ahead and quit.  Also skip if this is an error exit.
594 	 */
595 	if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
596 		successResult == EXIT_SUCCESS)
597 	{
598 		/* save query in history */
599 		/* currently unneeded since we don't use this block if interactive */
600 #ifdef NOT_USED
601 		if (pset.cur_cmd_interactive)
602 			pg_send_history(history_buf);
603 #endif
604 
605 		/* execute query unless we're in an inactive \if branch */
606 		if (conditional_active(cond_stack))
607 		{
608 			success = SendQuery(query_buf->data);
609 		}
610 		else
611 		{
612 			if (pset.cur_cmd_interactive)
613 				pg_log_error("query ignored; use \\endif or Ctrl-C to exit current \\if block");
614 			success = true;
615 		}
616 
617 		if (!success && die_on_error)
618 			successResult = EXIT_USER;
619 		else if (pset.db == NULL)
620 			successResult = EXIT_BADCONN;
621 	}
622 
623 	/*
624 	 * Check for unbalanced \if-\endifs unless user explicitly quit, or the
625 	 * script is erroring out
626 	 */
627 	if (slashCmdStatus != PSQL_CMD_TERMINATE &&
628 		successResult != EXIT_USER &&
629 		!conditional_stack_empty(cond_stack))
630 	{
631 		pg_log_error("reached EOF without finding closing \\endif(s)");
632 		if (die_on_error && !pset.cur_cmd_interactive)
633 			successResult = EXIT_USER;
634 	}
635 
636 	/*
637 	 * Let's just make real sure the SIGINT handler won't try to use
638 	 * sigint_interrupt_jmp after we exit this routine.  If there is an outer
639 	 * MainLoop instance, it will reset sigint_interrupt_jmp to point to
640 	 * itself at the top of its loop, before any further interactive input
641 	 * happens.
642 	 */
643 	sigint_interrupt_enabled = false;
644 
645 	destroyPQExpBuffer(query_buf);
646 	destroyPQExpBuffer(previous_buf);
647 	destroyPQExpBuffer(history_buf);
648 
649 	psql_scan_destroy(scan_state);
650 	conditional_stack_destroy(cond_stack);
651 
652 	pset.cur_cmd_source = prev_cmd_source;
653 	pset.cur_cmd_interactive = prev_cmd_interactive;
654 	pset.lineno = prev_lineno;
655 
656 	return successResult;
657 }								/* MainLoop() */
658