PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
mainloop.h File Reference
Include dependency graph for mainloop.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int MainLoop (FILE *source)
 

Variables

const PsqlScanCallbacks psqlscan_callbacks
 

Function Documentation

int MainLoop ( FILE *  source)

Definition at line 35 of file mainloop.c.

References _, appendPQExpBufferChar(), Assert, cancel_pressed, conditional_active(), conditional_stack_create(), conditional_stack_destroy(), conditional_stack_empty(), conditional_stack_pop(), createPQExpBuffer(), _psqlSettings::cur_cmd_interactive, _psqlSettings::cur_cmd_source, PQExpBufferData::data, _psqlSettings::db, destroyPQExpBuffer(), _psqlSettings::echo, _psqlSettings::encoding, EXIT_BADCONN, EXIT_FAILURE, EXIT_SUCCESS, EXIT_USER, free, get_prompt(), gets_fromFile(), gets_interactive(), HandleSlashCmds(), _psqlSettings::ignoreeof, PQExpBufferData::len, _psqlSettings::lineno, memmove, _psqlSettings::notty, NULL, _psqlSettings::on_error_stop, pg_append_history(), pg_send_history(), pg_strdup(), pg_strncasecmp(), PG_UTF8, PQExpBufferBroken, _psqlSettings::progname, PROMPT_READY, PSCAN_BACKSLASH, PSCAN_EOL, PSCAN_INCOMPLETE, PSCAN_SEMICOLON, pset, PSQL_CMD_ERROR, PSQL_CMD_NEWEDIT, PSQL_CMD_SEND, PSQL_CMD_TERMINATE, PSQL_CMD_UNKNOWN, PSQL_ECHO_ALL, psql_error(), psql_scan(), psql_scan_create(), psql_scan_destroy(), psql_scan_finish(), psql_scan_in_quote(), psql_scan_reset(), psql_scan_set_passthrough(), psql_scan_setup(), _psqlSettings::quiet, resetPQExpBuffer(), SendQuery(), sigint_interrupt_enabled, sigint_interrupt_jmp, _psqlSettings::singleline, standard_strings(), _psqlSettings::stmt_lineno, and success.

Referenced by main(), and process_file().

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  volatile int successResult = EXIT_SUCCESS;
50  volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
51  volatile promptStatus_t prompt_status = PROMPT_READY;
52  volatile int count_eof = 0;
53  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  prev_cmd_source = pset.cur_cmd_source;
60  prev_cmd_interactive = pset.cur_cmd_interactive;
61  prev_lineno = pset.lineno;
62  /* pset.stmt_lineno does not need to be saved and restored */
63 
64  /* Establish new source */
65  pset.cur_cmd_source = source;
66  pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
67  pset.lineno = 0;
68  pset.stmt_lineno = 1;
69 
70  /* Create working state */
71  scan_state = psql_scan_create(&psqlscan_callbacks);
72  cond_stack = conditional_stack_create();
73  psql_scan_set_passthrough(scan_state, (void *) cond_stack);
74 
75  query_buf = createPQExpBuffer();
76  previous_buf = createPQExpBuffer();
77  history_buf = createPQExpBuffer();
78  if (PQExpBufferBroken(query_buf) ||
79  PQExpBufferBroken(previous_buf) ||
80  PQExpBufferBroken(history_buf))
81  {
82  psql_error("out of memory\n");
83  exit(EXIT_FAILURE);
84  }
85 
86  /* main loop to get queries and execute them */
87  while (successResult == EXIT_SUCCESS)
88  {
89  /*
90  * Clean up after a previous Control-C
91  */
92  if (cancel_pressed)
93  {
95  {
96  /*
97  * You get here if you stopped a script with Ctrl-C.
98  */
99  successResult = EXIT_USER;
100  break;
101  }
102 
103  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  if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
112  {
113  /* got here with longjmp */
114 
115  /* reset parsing state */
116  psql_scan_finish(scan_state);
117  psql_scan_reset(scan_state);
118  resetPQExpBuffer(query_buf);
119  resetPQExpBuffer(history_buf);
120  count_eof = 0;
121  slashCmdStatus = PSQL_CMD_UNKNOWN;
122  prompt_status = PROMPT_READY;
123  pset.stmt_lineno = 1;
124  cancel_pressed = false;
125 
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  psql_error("\\if: escaped\n");
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  */
153  {
154  /* May need to reset prompt, eg after \r command */
155  if (query_buf->len == 0)
156  prompt_status = PROMPT_READY;
157  line = gets_interactive(get_prompt(prompt_status, cond_stack),
158  query_buf);
159  }
160  else
161  {
162  line = gets_fromFile(source);
163  if (!line && ferror(source))
164  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  if (line == NULL)
174  {
176  {
177  /* This tries to mimic bash's IGNOREEOF feature. */
178  count_eof++;
179 
180  if (count_eof < pset.ignoreeof)
181  {
182  if (!pset.quiet)
183  printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
184  continue;
185  }
186 
187  puts(pset.quiet ? "" : "\\q");
188  }
189  break;
190  }
191 
192  count_eof = 0;
193 
194  pset.lineno++;
195 
196  /* ignore UTF-8 Unicode byte-order mark */
197  if (pset.lineno == 1 && pset.encoding == PG_UTF8 && strncmp(line, "\xef\xbb\xbf", 3) == 0)
198  memmove(line, line + 3, strlen(line + 3) + 1);
199 
200  /* Detect attempts to run custom-format dumps as SQL scripts */
201  if (pset.lineno == 1 && !pset.cur_cmd_interactive &&
202  strncmp(line, "PGDMP", 5) == 0)
203  {
204  free(line);
205  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  fflush(stdout);
208  successResult = EXIT_FAILURE;
209  break;
210  }
211 
212  /* no further processing of empty lines, unless within a literal */
213  if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
214  {
215  free(line);
216  continue;
217  }
218 
219  /* A request for help? Be friendly and give them some guidance */
220  if (pset.cur_cmd_interactive && query_buf->len == 0 &&
221  pg_strncasecmp(line, "help", 4) == 0 &&
222  (line[4] == '\0' || line[4] == ';' || isspace((unsigned char) line[4])))
223  {
224  free(line);
225  puts(_("You are using psql, the command-line interface to PostgreSQL."));
226  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  fflush(stdout);
233  continue;
234  }
235 
236  /* echo back if flag is set, unless interactive */
238  {
239  puts(line);
240  fflush(stdout);
241  }
242 
243  /* insert newlines into query buffer between source lines */
244  if (query_buf->len > 0)
245  {
246  appendPQExpBufferChar(query_buf, '\n');
247  added_nl_pos = query_buf->len;
248  }
249  else
250  added_nl_pos = -1; /* flag we didn't add one */
251 
252  /* Setting this will not have effect until next line. */
253  die_on_error = pset.on_error_stop;
254 
255  /*
256  * Parse line, looking for command separators.
257  */
258  psql_scan_setup(scan_state, line, strlen(line),
260  success = true;
261  line_saved_in_history = false;
262 
263  while (success || !die_on_error)
264  {
265  PsqlScanResult scan_result;
266  promptStatus_t prompt_tmp = prompt_status;
267  size_t pos_in_query;
268  char *tmp_line;
269 
270  pos_in_query = query_buf->len;
271  scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
272  prompt_status = prompt_tmp;
273 
274  if (PQExpBufferBroken(query_buf))
275  {
276  psql_error("out of memory\n");
277  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  tmp_line = query_buf->data + pos_in_query;
287  while (*tmp_line != '\0')
288  {
289  if (*(tmp_line++) == '\n')
290  pset.stmt_lineno++;
291  }
292 
293  if (scan_result == PSCAN_EOL)
294  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  if (scan_result == PSCAN_SEMICOLON ||
301  (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  if (pset.cur_cmd_interactive && !line_saved_in_history)
310  {
311  pg_append_history(line, history_buf);
312  pg_send_history(history_buf);
313  line_saved_in_history = true;
314  }
315 
316  /* execute query unless we're in an inactive \if branch */
317  if (conditional_active(cond_stack))
318  {
319  success = SendQuery(query_buf->data);
320  slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
321  pset.stmt_lineno = 1;
322 
323  /* transfer query to previous_buf by pointer-swapping */
324  {
325  PQExpBuffer swap_buf = previous_buf;
326 
327  previous_buf = query_buf;
328  query_buf = swap_buf;
329  }
330  resetPQExpBuffer(query_buf);
331 
332  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 */
339  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  success = true;
342  slashCmdStatus = PSQL_CMD_SEND;
343  pset.stmt_lineno = 1;
344  /* note that query_buf doesn't change state */
345  }
346  }
347  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  if (query_buf->len == added_nl_pos)
361  {
362  query_buf->data[--query_buf->len] = '\0';
363  pg_send_history(history_buf);
364  }
365  added_nl_pos = -1;
366 
367  /* save backslash command in history */
368  if (pset.cur_cmd_interactive && !line_saved_in_history)
369  {
370  pg_append_history(line, history_buf);
371  pg_send_history(history_buf);
372  line_saved_in_history = true;
373  }
374 
375  /* execute backslash command */
376  slashCmdStatus = HandleSlashCmds(scan_state,
377  cond_stack,
378  query_buf,
379  previous_buf);
380 
381  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  pset.stmt_lineno = 1;
389 
390  if (slashCmdStatus == PSQL_CMD_SEND)
391  {
392  /* should not see this in inactive branch */
393  Assert(conditional_active(cond_stack));
394 
395  success = SendQuery(query_buf->data);
396 
397  /* transfer query to previous_buf by pointer-swapping */
398  {
399  PQExpBuffer swap_buf = previous_buf;
400 
401  previous_buf = query_buf;
402  query_buf = swap_buf;
403  }
404  resetPQExpBuffer(query_buf);
405 
406  /* flush any paren nesting info after forced send */
407  psql_scan_reset(scan_state);
408  }
409  else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
410  {
411  /* should not see this in inactive branch */
412  Assert(conditional_active(cond_stack));
413  /* rescan query_buf as new input */
414  psql_scan_finish(scan_state);
415  free(line);
416  line = pg_strdup(query_buf->data);
417  resetPQExpBuffer(query_buf);
418  /* reset parsing state since we are rescanning whole line */
419  psql_scan_reset(scan_state);
420  psql_scan_setup(scan_state, line, strlen(line),
422  line_saved_in_history = false;
423  prompt_status = PROMPT_READY;
424  }
425  else if (slashCmdStatus == PSQL_CMD_TERMINATE)
426  break;
427  }
428 
429  /* fall out of loop if lexer reached EOL */
430  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  if (pset.cur_cmd_interactive && !line_saved_in_history)
437  pg_append_history(line, history_buf);
438 
439  psql_scan_finish(scan_state);
440  free(line);
441 
442  if (slashCmdStatus == PSQL_CMD_TERMINATE)
443  {
444  successResult = EXIT_SUCCESS;
445  break;
446  }
447 
449  {
450  if (!success && die_on_error)
451  successResult = EXIT_USER;
452  /* Have we lost the db connection? */
453  else if (!pset.db)
454  successResult = EXIT_BADCONN;
455  }
456  } /* while !endoffile/session */
457 
458  /*
459  * Process query at the end of file without a semicolon
460  */
461  if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
462  successResult == EXIT_SUCCESS)
463  {
464  /* save query in history */
466  pg_send_history(history_buf);
467 
468  /* execute query unless we're in an inactive \if branch */
469  if (conditional_active(cond_stack))
470  {
471  success = SendQuery(query_buf->data);
472  }
473  else
474  {
476  psql_error("query ignored; use \\endif or Ctrl-C to exit current \\if block\n");
477  success = true;
478  }
479 
480  if (!success && die_on_error)
481  successResult = EXIT_USER;
482  else if (pset.db == NULL)
483  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  if (slashCmdStatus != PSQL_CMD_TERMINATE &&
491  successResult != EXIT_USER &&
492  !conditional_stack_empty(cond_stack))
493  {
494  psql_error("reached EOF without finding closing \\endif(s)\n");
495  if (die_on_error && !pset.cur_cmd_interactive)
496  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  sigint_interrupt_enabled = false;
507 
508  destroyPQExpBuffer(query_buf);
509  destroyPQExpBuffer(previous_buf);
510  destroyPQExpBuffer(history_buf);
511 
512  psql_scan_destroy(scan_state);
513  conditional_stack_destroy(cond_stack);
514 
515  pset.cur_cmd_source = prev_cmd_source;
516  pset.cur_cmd_interactive = prev_cmd_interactive;
517  pset.lineno = prev_lineno;
518 
519  return successResult;
520 } /* MainLoop() */
PSQL_ECHO echo
Definition: settings.h:131
PGconn * db
Definition: settings.h:82
PsqlScanResult
Definition: psqlscan.h:30
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:104
void pg_send_history(PQExpBuffer history_buf)
Definition: input.c:135
volatile bool sigint_interrupt_enabled
Definition: common.c:273
#define EXIT_SUCCESS
Definition: settings.h:147
PsqlSettings pset
Definition: startup.c:33
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:55
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
char * get_prompt(promptStatus_t status, ConditionalStack cstack)
Definition: prompt.c:69
bool on_error_stop
Definition: settings.h:124
FILE * cur_cmd_source
Definition: settings.h:103
sigjmp_buf sigint_interrupt_jmp
Definition: common.c:275
#define EXIT_BADCONN
Definition: settings.h:154
volatile bool cancel_pressed
Definition: print.c:46
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
void destroyPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:113
bool cur_cmd_interactive
Definition: settings.h:105
static bool success
Definition: pg_basebackup.c:96
#define memmove(d, s, c)
Definition: c.h:1058
const PsqlScanCallbacks psqlscan_callbacks
Definition: mainloop.c:21
void psql_scan_reset(PsqlScanState state)
#define EXIT_USER
Definition: settings.h:156
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
bool singleline
Definition: settings.h:126
char * gets_interactive(const char *prompt, PQExpBuffer query_buf)
Definition: input.c:66
ConditionalStack conditional_stack_create(void)
Definition: conditional.c:16
void psql_error(const char *fmt,...)
Definition: common.c:220
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:71
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:396
void psql_scan_destroy(PsqlScanState state)
bool standard_strings(void)
Definition: common.c:2058
#define free(a)
Definition: header.h:65
enum _backslashResult backslashResult
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void pg_append_history(const char *s, PQExpBuffer history_buf)
Definition: input.c:113
const char * progname
Definition: settings.h:107
char * gets_fromFile(FILE *source)
Definition: input.c:187
enum _promptStatus promptStatus_t
#define PQExpBufferBroken(str)
Definition: pqexpbuffer.h:59
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
void conditional_stack_destroy(ConditionalStack cstack)
Definition: conditional.c:28
void psql_scan_set_passthrough(PsqlScanState state, void *passthrough)
uint64 lineno
Definition: settings.h:109
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:94
#define EXIT_FAILURE
Definition: settings.h:151
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
bool SendQuery(const char *query)
Definition: common.c:1230
bool psql_scan_in_quote(PsqlScanState state)
void psql_scan_finish(PsqlScanState state)
backslashResult HandleSlashCmds(PsqlScanState scan_state, ConditionalStack cstack, PQExpBuffer query_buf, PQExpBuffer previous_buf)
Definition: command.c:202
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
int encoding
Definition: settings.h:83
#define _(x)
Definition: elog.c:84
uint64 stmt_lineno
Definition: settings.h:110

Variable Documentation

const PsqlScanCallbacks psqlscan_callbacks

Definition at line 21 of file mainloop.c.

Referenced by main().