OSDN Git Service

109f23192f84ab044c5aea2d9952d5048e490fbd
[pg-rex/syncrep.git] / src / bin / psql / mainloop.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.66 2005/01/01 05:43:08 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "mainloop.h"
10
11 #include "pqexpbuffer.h"
12
13 #include "command.h"
14 #include "common.h"
15 #include "input.h"
16 #include "prompt.h"
17 #include "psqlscan.h"
18 #include "settings.h"
19
20 #ifndef WIN32
21 #include <setjmp.h>
22 sigjmp_buf      main_loop_jmp;
23 #endif
24
25
26 /*
27  * Main processing loop for reading lines of input
28  *      and sending them to the backend.
29  *
30  * This loop is re-entrant. May be called by \i command
31  *      which reads input from a file.
32  */
33 int
34 MainLoop(FILE *source)
35 {
36         PsqlScanState scan_state;       /* lexer working state */
37         PQExpBuffer query_buf;          /* buffer for query being accumulated */
38         PQExpBuffer previous_buf;       /* if there isn't anything in the new
39                                                                  * buffer yet, use this one for \e, etc. */
40         char       *line;                       /* current line of input */
41         int                     added_nl_pos;
42         bool            success;
43         volatile int successResult = EXIT_SUCCESS;
44         volatile backslashResult slashCmdStatus = CMD_UNKNOWN;
45         volatile promptStatus_t prompt_status = PROMPT_READY;
46         volatile int count_eof = 0;
47         volatile bool die_on_error = false;
48
49         /* Save the prior command source */
50         FILE       *prev_cmd_source;
51         bool            prev_cmd_interactive;
52         unsigned int prev_lineno;
53
54         /* Save old settings */
55         prev_cmd_source = pset.cur_cmd_source;
56         prev_cmd_interactive = pset.cur_cmd_interactive;
57         prev_lineno = pset.lineno;
58
59         /* Establish new source */
60         pset.cur_cmd_source = source;
61         pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
62         pset.lineno = 0;
63
64         /* Create working state */
65         scan_state = psql_scan_create();
66
67         query_buf = createPQExpBuffer();
68         previous_buf = createPQExpBuffer();
69         if (!query_buf || !previous_buf)
70         {
71                 psql_error("out of memory\n");
72                 exit(EXIT_FAILURE);
73         }
74
75         /* main loop to get queries and execute them */
76         while (successResult == EXIT_SUCCESS)
77         {
78                 /*
79                  * Welcome code for Control-C
80                  */
81                 if (cancel_pressed)
82                 {
83                         if (!pset.cur_cmd_interactive)
84                         {
85                                 /*
86                                  * You get here if you stopped a script with Ctrl-C and a
87                                  * query cancel was issued. In that case we don't do the
88                                  * longjmp, so the query routine can finish nicely.
89                                  */
90                                 successResult = EXIT_USER;
91                                 break;
92                         }
93
94                         cancel_pressed = false;
95                 }
96
97 #ifndef WIN32
98                 if (sigsetjmp(main_loop_jmp, 1) != 0)
99                 {
100                         /* got here with longjmp */
101
102                         /* reset parsing state */
103                         resetPQExpBuffer(query_buf);
104                         psql_scan_finish(scan_state);
105                         psql_scan_reset(scan_state);
106                         count_eof = 0;
107                         slashCmdStatus = CMD_UNKNOWN;
108                         prompt_status = PROMPT_READY;
109
110                         if (pset.cur_cmd_interactive)
111                                 putc('\n', stdout);
112                         else
113                         {
114                                 successResult = EXIT_USER;
115                                 break;
116                         }
117                 }
118
119                 /*
120                  * establish the control-C handler only after main_loop_jmp is
121                  * ready
122                  */
123                 pqsignal(SIGINT, handle_sigint);                /* control-C => cancel */
124
125 #else /* WIN32 */
126                 setup_cancel_handler();
127 #endif
128
129                 fflush(stdout);
130
131                 if (slashCmdStatus == CMD_NEWEDIT)
132                 {
133                         /*
134                          * just returned from editing the line? then just copy to the
135                          * input buffer
136                          */
137                         line = pg_strdup(query_buf->data);
138                         /* reset parsing state since we are rescanning whole line */
139                         resetPQExpBuffer(query_buf);
140                         psql_scan_reset(scan_state);
141                         slashCmdStatus = CMD_UNKNOWN;
142                         prompt_status = PROMPT_READY;
143                 }
144
145                 /*
146                  * otherwise, get another line
147                  */
148                 else if (pset.cur_cmd_interactive)
149                 {
150                         /* May need to reset prompt, eg after \r command */
151                         if (query_buf->len == 0)
152                                 prompt_status = PROMPT_READY;
153                         line = gets_interactive(get_prompt(prompt_status));
154                 }
155                 else
156                         line = gets_fromFile(source);
157
158                 /*
159                  * query_buf holds query already accumulated.  line is the
160                  * malloc'd new line of input (note it must be freed before
161                  * looping around!)
162                  */
163
164                 /* No more input.  Time to quit, or \i done */
165                 if (line == NULL)
166                 {
167                         if (pset.cur_cmd_interactive)
168                         {
169                                 /* This tries to mimic bash's IGNOREEOF feature. */
170                                 count_eof++;
171
172                                 if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10, false))
173                                 {
174                                         if (!QUIET())
175                                                 printf(gettext("Use \"\\q\" to leave %s.\n"), pset.progname);
176                                         continue;
177                                 }
178
179                                 puts(QUIET() ? "" : "\\q");
180                         }
181                         break;
182                 }
183
184                 count_eof = 0;
185
186                 pset.lineno++;
187
188                 /* nothing left on line? then ignore */
189                 if (line[0] == '\0' && !psql_scan_in_quote(scan_state))
190                 {
191                         free(line);
192                         continue;
193                 }
194
195                 /* echo back if flag is set */
196                 if (!pset.cur_cmd_interactive &&
197                         VariableEquals(pset.vars, "ECHO", "all"))
198                         puts(line);
199                 fflush(stdout);
200
201                 /* insert newlines into query buffer between source lines */
202                 if (query_buf->len > 0)
203                 {
204                         appendPQExpBufferChar(query_buf, '\n');
205                         added_nl_pos = query_buf->len;
206                 }
207                 else
208                         added_nl_pos = -1;      /* flag we didn't add one */
209
210                 /* Setting this will not have effect until next line. */
211                 die_on_error = GetVariableBool(pset.vars, "ON_ERROR_STOP");
212
213                 /*
214                  * Parse line, looking for command separators.
215                  */
216                 psql_scan_setup(scan_state, line, strlen(line));
217                 success = true;
218
219                 while (success || !die_on_error)
220                 {
221                         PsqlScanResult scan_result;
222                         promptStatus_t prompt_tmp = prompt_status;
223
224                         scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
225                         prompt_status = prompt_tmp;
226
227                         /*
228                          * Send command if semicolon found, or if end of line and
229                          * we're in single-line mode.
230                          */
231                         if (scan_result == PSCAN_SEMICOLON ||
232                                 (scan_result == PSCAN_EOL &&
233                                  GetVariableBool(pset.vars, "SINGLELINE")))
234                         {
235                                 /* execute query */
236                                 success = SendQuery(query_buf->data);
237                                 slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
238
239                                 resetPQExpBuffer(previous_buf);
240                                 appendPQExpBufferStr(previous_buf, query_buf->data);
241                                 resetPQExpBuffer(query_buf);
242                                 added_nl_pos = -1;
243                                 /* we need not do psql_scan_reset() here */
244                         }
245                         else if (scan_result == PSCAN_BACKSLASH)
246                         {
247                                 /* handle backslash command */
248
249                                 /*
250                                  * If we added a newline to query_buf, and nothing else
251                                  * has been inserted in query_buf by the lexer, then strip
252                                  * off the newline again.  This avoids any change to
253                                  * query_buf when a line contains only a backslash
254                                  * command.
255                                  */
256                                 if (query_buf->len == added_nl_pos)
257                                         query_buf->data[--query_buf->len] = '\0';
258                                 added_nl_pos = -1;
259
260                                 slashCmdStatus = HandleSlashCmds(scan_state,
261                                                                                                  query_buf->len > 0 ?
262                                                                                            query_buf : previous_buf);
263
264                                 success = slashCmdStatus != CMD_ERROR;
265
266                                 if ((slashCmdStatus == CMD_SEND || slashCmdStatus == CMD_NEWEDIT) &&
267                                         query_buf->len == 0)
268                                 {
269                                         /* copy previous buffer to current for handling */
270                                         appendPQExpBufferStr(query_buf, previous_buf->data);
271                                 }
272
273                                 if (slashCmdStatus == CMD_SEND)
274                                 {
275                                         success = SendQuery(query_buf->data);
276
277                                         resetPQExpBuffer(previous_buf);
278                                         appendPQExpBufferStr(previous_buf, query_buf->data);
279                                         resetPQExpBuffer(query_buf);
280
281                                         /* flush any paren nesting info after forced send */
282                                         psql_scan_reset(scan_state);
283                                 }
284
285                                 if (slashCmdStatus == CMD_TERMINATE)
286                                         break;
287                         }
288
289                         /* fall out of loop if lexer reached EOL */
290                         if (scan_result == PSCAN_INCOMPLETE ||
291                                 scan_result == PSCAN_EOL)
292                                 break;
293                 }
294
295                 psql_scan_finish(scan_state);
296                 free(line);
297
298                 if (slashCmdStatus == CMD_TERMINATE)
299                 {
300                         successResult = EXIT_SUCCESS;
301                         break;
302                 }
303
304                 if (!pset.cur_cmd_interactive)
305                 {
306                         if (!success && die_on_error)
307                                 successResult = EXIT_USER;
308                         /* Have we lost the db connection? */
309                         else if (!pset.db)
310                                 successResult = EXIT_BADCONN;
311                 }
312         }                                                       /* while !endoffile/session */
313
314         /*
315          * Process query at the end of file without a semicolon
316          */
317         if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
318                 successResult == EXIT_SUCCESS)
319         {
320                 success = SendQuery(query_buf->data);
321
322                 if (!success && die_on_error)
323                         successResult = EXIT_USER;
324                 else if (pset.db == NULL)
325                         successResult = EXIT_BADCONN;
326         }
327
328         /*
329          * Reset SIGINT handler because main_loop_jmp will be invalid as soon
330          * as we exit this routine.  If there is an outer MainLoop instance,
331          * it will re-enable ^C catching as soon as it gets back to the top of
332          * its loop and resets main_loop_jmp to point to itself.
333          */
334 #ifndef WIN32
335         pqsignal(SIGINT, SIG_DFL);
336 #endif
337
338         destroyPQExpBuffer(query_buf);
339         destroyPQExpBuffer(previous_buf);
340
341         psql_scan_destroy(scan_state);
342
343         pset.cur_cmd_source = prev_cmd_source;
344         pset.cur_cmd_interactive = prev_cmd_interactive;
345         pset.lineno = prev_lineno;
346
347         return successResult;
348 }       /* MainLoop() */