LCOV - code coverage report
Current view: top level - src/bin/psql - mainloop.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 128 207 61.8 %
Date: 2017-09-29 13:40:31 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          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() */

Generated by: LCOV version 1.11