Header And Logo

PostgreSQL
| The world's most advanced open source database.

mainloop.c

Go to the documentation of this file.
00001 /*
00002  * psql - the PostgreSQL interactive terminal
00003  *
00004  * Copyright (c) 2000-2013, PostgreSQL Global Development Group
00005  *
00006  * src/bin/psql/mainloop.c
00007  */
00008 #include "postgres_fe.h"
00009 #include "mainloop.h"
00010 
00011 
00012 #include "command.h"
00013 #include "common.h"
00014 #include "input.h"
00015 #include "settings.h"
00016 
00017 #include "mb/pg_wchar.h"
00018 
00019 
00020 /*
00021  * Main processing loop for reading lines of input
00022  *  and sending them to the backend.
00023  *
00024  * This loop is re-entrant. May be called by \i command
00025  *  which reads input from a file.
00026  */
00027 int
00028 MainLoop(FILE *source)
00029 {
00030     PsqlScanState scan_state;   /* lexer working state */
00031     volatile PQExpBuffer query_buf;     /* buffer for query being accumulated */
00032     volatile PQExpBuffer previous_buf;  /* if there isn't anything in the new
00033                                          * buffer yet, use this one for \e,
00034                                          * etc. */
00035     PQExpBuffer history_buf;    /* earlier lines of a multi-line command, not
00036                                  * yet saved to readline history */
00037     char       *line;           /* current line of input */
00038     int         added_nl_pos;
00039     bool        success;
00040     bool        line_saved_in_history;
00041     volatile int successResult = EXIT_SUCCESS;
00042     volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
00043     volatile promptStatus_t prompt_status = PROMPT_READY;
00044     volatile int count_eof = 0;
00045     volatile bool die_on_error = false;
00046 
00047     /* Save the prior command source */
00048     FILE       *prev_cmd_source;
00049     bool        prev_cmd_interactive;
00050     uint64      prev_lineno;
00051 
00052     /* Save old settings */
00053     prev_cmd_source = pset.cur_cmd_source;
00054     prev_cmd_interactive = pset.cur_cmd_interactive;
00055     prev_lineno = pset.lineno;
00056 
00057     /* Establish new source */
00058     pset.cur_cmd_source = source;
00059     pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
00060     pset.lineno = 0;
00061 
00062     /* Create working state */
00063     scan_state = psql_scan_create();
00064 
00065     query_buf = createPQExpBuffer();
00066     previous_buf = createPQExpBuffer();
00067     history_buf = createPQExpBuffer();
00068     if (PQExpBufferBroken(query_buf) ||
00069         PQExpBufferBroken(previous_buf) ||
00070         PQExpBufferBroken(history_buf))
00071     {
00072         psql_error("out of memory\n");
00073         exit(EXIT_FAILURE);
00074     }
00075 
00076     /* main loop to get queries and execute them */
00077     while (successResult == EXIT_SUCCESS)
00078     {
00079         /*
00080          * Clean up after a previous Control-C
00081          */
00082         if (cancel_pressed)
00083         {
00084             if (!pset.cur_cmd_interactive)
00085             {
00086                 /*
00087                  * You get here if you stopped a script with Ctrl-C.
00088                  */
00089                 successResult = EXIT_USER;
00090                 break;
00091             }
00092 
00093             cancel_pressed = false;
00094         }
00095 
00096         /*
00097          * Establish longjmp destination for exiting from wait-for-input. We
00098          * must re-do this each time through the loop for safety, since the
00099          * jmpbuf might get changed during command execution.
00100          */
00101         if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
00102         {
00103             /* got here with longjmp */
00104 
00105             /* reset parsing state */
00106             psql_scan_finish(scan_state);
00107             psql_scan_reset(scan_state);
00108             resetPQExpBuffer(query_buf);
00109             resetPQExpBuffer(history_buf);
00110             count_eof = 0;
00111             slashCmdStatus = PSQL_CMD_UNKNOWN;
00112             prompt_status = PROMPT_READY;
00113             cancel_pressed = false;
00114 
00115             if (pset.cur_cmd_interactive)
00116                 putc('\n', stdout);
00117             else
00118             {
00119                 successResult = EXIT_USER;
00120                 break;
00121             }
00122         }
00123 
00124         fflush(stdout);
00125 
00126         /*
00127          * get another line
00128          */
00129         if (pset.cur_cmd_interactive)
00130         {
00131             /* May need to reset prompt, eg after \r command */
00132             if (query_buf->len == 0)
00133                 prompt_status = PROMPT_READY;
00134             line = gets_interactive(get_prompt(prompt_status));
00135         }
00136         else
00137         {
00138             line = gets_fromFile(source);
00139             if (!line && ferror(source))
00140                 successResult = EXIT_FAILURE;
00141         }
00142 
00143         /*
00144          * query_buf holds query already accumulated.  line is the malloc'd
00145          * new line of input (note it must be freed before looping around!)
00146          */
00147 
00148         /* No more input.  Time to quit, or \i done */
00149         if (line == NULL)
00150         {
00151             if (pset.cur_cmd_interactive)
00152             {
00153                 /* This tries to mimic bash's IGNOREEOF feature. */
00154                 count_eof++;
00155 
00156                 if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10, false))
00157                 {
00158                     if (!pset.quiet)
00159                         printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
00160                     continue;
00161                 }
00162 
00163                 puts(pset.quiet ? "" : "\\q");
00164             }
00165             break;
00166         }
00167 
00168         count_eof = 0;
00169 
00170         pset.lineno++;
00171 
00172         /* ignore UTF-8 Unicode byte-order mark */
00173         if (pset.lineno == 1 && pset.encoding == PG_UTF8 && strncmp(line, "\xef\xbb\xbf", 3) == 0)
00174             memmove(line, line + 3, strlen(line + 3) + 1);
00175 
00176         /* nothing left on line? then ignore */
00177         if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
00178         {
00179             free(line);
00180             continue;
00181         }
00182 
00183         /* A request for help? Be friendly and give them some guidance */
00184         if (pset.cur_cmd_interactive && query_buf->len == 0 &&
00185             pg_strncasecmp(line, "help", 4) == 0 &&
00186             (line[4] == '\0' || line[4] == ';' || isspace((unsigned char) line[4])))
00187         {
00188             free(line);
00189             puts(_("You are using psql, the command-line interface to PostgreSQL."));
00190             printf(_("Type:  \\copyright for distribution terms\n"
00191                      "       \\h for help with SQL commands\n"
00192                      "       \\? for help with psql commands\n"
00193                   "       \\g or terminate with semicolon to execute query\n"
00194                      "       \\q to quit\n"));
00195 
00196             fflush(stdout);
00197             continue;
00198         }
00199 
00200         /* echo back if flag is set */
00201         if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
00202             puts(line);
00203         fflush(stdout);
00204 
00205         /* insert newlines into query buffer between source lines */
00206         if (query_buf->len > 0)
00207         {
00208             appendPQExpBufferChar(query_buf, '\n');
00209             added_nl_pos = query_buf->len;
00210         }
00211         else
00212             added_nl_pos = -1;  /* flag we didn't add one */
00213 
00214         /* Setting this will not have effect until next line. */
00215         die_on_error = pset.on_error_stop;
00216 
00217         /*
00218          * Parse line, looking for command separators.
00219          */
00220         psql_scan_setup(scan_state, line, strlen(line));
00221         success = true;
00222         line_saved_in_history = false;
00223 
00224         while (success || !die_on_error)
00225         {
00226             PsqlScanResult scan_result;
00227             promptStatus_t prompt_tmp = prompt_status;
00228 
00229             scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
00230             prompt_status = prompt_tmp;
00231 
00232             if (PQExpBufferBroken(query_buf))
00233             {
00234                 psql_error("out of memory\n");
00235                 exit(EXIT_FAILURE);
00236             }
00237 
00238             /*
00239              * Send command if semicolon found, or if end of line and we're in
00240              * single-line mode.
00241              */
00242             if (scan_result == PSCAN_SEMICOLON ||
00243                 (scan_result == PSCAN_EOL && pset.singleline))
00244             {
00245                 /*
00246                  * Save query in history.  We use history_buf to accumulate
00247                  * multi-line queries into a single history entry.
00248                  */
00249                 if (pset.cur_cmd_interactive && !line_saved_in_history)
00250                 {
00251                     pg_append_history(line, history_buf);
00252                     pg_send_history(history_buf);
00253                     line_saved_in_history = true;
00254                 }
00255 
00256                 /* execute query */
00257                 success = SendQuery(query_buf->data);
00258                 slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
00259 
00260                 /* transfer query to previous_buf by pointer-swapping */
00261                 {
00262                     PQExpBuffer swap_buf = previous_buf;
00263 
00264                     previous_buf = query_buf;
00265                     query_buf = swap_buf;
00266                 }
00267                 resetPQExpBuffer(query_buf);
00268 
00269                 added_nl_pos = -1;
00270                 /* we need not do psql_scan_reset() here */
00271             }
00272             else if (scan_result == PSCAN_BACKSLASH)
00273             {
00274                 /* handle backslash command */
00275 
00276                 /*
00277                  * If we added a newline to query_buf, and nothing else has
00278                  * been inserted in query_buf by the lexer, then strip off the
00279                  * newline again.  This avoids any change to query_buf when a
00280                  * line contains only a backslash command.  Also, in this
00281                  * situation we force out any previous lines as a separate
00282                  * history entry; we don't want SQL and backslash commands
00283                  * intermixed in history if at all possible.
00284                  */
00285                 if (query_buf->len == added_nl_pos)
00286                 {
00287                     query_buf->data[--query_buf->len] = '\0';
00288                     pg_send_history(history_buf);
00289                 }
00290                 added_nl_pos = -1;
00291 
00292                 /* save backslash command in history */
00293                 if (pset.cur_cmd_interactive && !line_saved_in_history)
00294                 {
00295                     pg_append_history(line, history_buf);
00296                     pg_send_history(history_buf);
00297                     line_saved_in_history = true;
00298                 }
00299 
00300                 /* execute backslash command */
00301                 slashCmdStatus = HandleSlashCmds(scan_state,
00302                                                  query_buf->len > 0 ?
00303                                                  query_buf : previous_buf);
00304 
00305                 success = slashCmdStatus != PSQL_CMD_ERROR;
00306 
00307                 if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) &&
00308                     query_buf->len == 0)
00309                 {
00310                     /* copy previous buffer to current for handling */
00311                     appendPQExpBufferStr(query_buf, previous_buf->data);
00312                 }
00313 
00314                 if (slashCmdStatus == PSQL_CMD_SEND)
00315                 {
00316                     success = SendQuery(query_buf->data);
00317 
00318                     /* transfer query to previous_buf by pointer-swapping */
00319                     {
00320                         PQExpBuffer swap_buf = previous_buf;
00321 
00322                         previous_buf = query_buf;
00323                         query_buf = swap_buf;
00324                     }
00325                     resetPQExpBuffer(query_buf);
00326 
00327                     /* flush any paren nesting info after forced send */
00328                     psql_scan_reset(scan_state);
00329                 }
00330                 else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
00331                 {
00332                     /* rescan query_buf as new input */
00333                     psql_scan_finish(scan_state);
00334                     free(line);
00335                     line = pg_strdup(query_buf->data);
00336                     resetPQExpBuffer(query_buf);
00337                     /* reset parsing state since we are rescanning whole line */
00338                     psql_scan_reset(scan_state);
00339                     psql_scan_setup(scan_state, line, strlen(line));
00340                     line_saved_in_history = false;
00341                     prompt_status = PROMPT_READY;
00342                 }
00343                 else if (slashCmdStatus == PSQL_CMD_TERMINATE)
00344                     break;
00345             }
00346 
00347             /* fall out of loop if lexer reached EOL */
00348             if (scan_result == PSCAN_INCOMPLETE ||
00349                 scan_result == PSCAN_EOL)
00350                 break;
00351         }
00352 
00353         /* Add line to pending history if we didn't execute anything yet */
00354         if (pset.cur_cmd_interactive && !line_saved_in_history)
00355             pg_append_history(line, history_buf);
00356 
00357         psql_scan_finish(scan_state);
00358         free(line);
00359 
00360         if (slashCmdStatus == PSQL_CMD_TERMINATE)
00361         {
00362             successResult = EXIT_SUCCESS;
00363             break;
00364         }
00365 
00366         if (!pset.cur_cmd_interactive)
00367         {
00368             if (!success && die_on_error)
00369                 successResult = EXIT_USER;
00370             /* Have we lost the db connection? */
00371             else if (!pset.db)
00372                 successResult = EXIT_BADCONN;
00373         }
00374     }                           /* while !endoffile/session */
00375 
00376     /*
00377      * Process query at the end of file without a semicolon
00378      */
00379     if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
00380         successResult == EXIT_SUCCESS)
00381     {
00382         /* save query in history */
00383         if (pset.cur_cmd_interactive)
00384             pg_send_history(history_buf);
00385 
00386         /* execute query */
00387         success = SendQuery(query_buf->data);
00388 
00389         if (!success && die_on_error)
00390             successResult = EXIT_USER;
00391         else if (pset.db == NULL)
00392             successResult = EXIT_BADCONN;
00393     }
00394 
00395     /*
00396      * Let's just make real sure the SIGINT handler won't try to use
00397      * sigint_interrupt_jmp after we exit this routine.  If there is an outer
00398      * MainLoop instance, it will reset sigint_interrupt_jmp to point to
00399      * itself at the top of its loop, before any further interactive input
00400      * happens.
00401      */
00402     sigint_interrupt_enabled = false;
00403 
00404     destroyPQExpBuffer(query_buf);
00405     destroyPQExpBuffer(previous_buf);
00406     destroyPQExpBuffer(history_buf);
00407 
00408     psql_scan_destroy(scan_state);
00409 
00410     pset.cur_cmd_source = prev_cmd_source;
00411     pset.cur_cmd_interactive = prev_cmd_interactive;
00412     pset.lineno = prev_lineno;
00413 
00414     return successResult;
00415 }   /* MainLoop() */
00416 
00417 
00418 /*
00419  * psqlscan.c is #include'd here instead of being compiled on its own.
00420  * This is because we need postgres_fe.h to be read before any system
00421  * include files, else things tend to break on platforms that have
00422  * multiple infrastructures for stdio.h and so on.  flex is absolutely
00423  * uncooperative about that, so we can't compile psqlscan.c on its own.
00424  */
00425 #include "psqlscan.c"