00001
00002
00003
00004
00005
00006
00007
00008 #include "postgres_fe.h"
00009 #include "common.h"
00010
00011 #include <ctype.h>
00012 #include <signal.h>
00013 #ifndef WIN32
00014 #include <unistd.h>
00015 #else
00016 #include <io.h>
00017 #include <win32.h>
00018 #endif
00019
00020 #include "portability/instr_time.h"
00021
00022 #include "settings.h"
00023 #include "command.h"
00024 #include "copy.h"
00025 #include "mbprint.h"
00026
00027
00028
00029 static bool ExecQueryUsingCursor(const char *query, double *elapsed_msec);
00030 static bool command_no_begin(const char *query);
00031 static bool is_select_command(const char *query);
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 bool
00042 setQFout(const char *fname)
00043 {
00044 bool status = true;
00045
00046
00047 if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
00048 {
00049 if (pset.queryFoutPipe)
00050 pclose(pset.queryFout);
00051 else
00052 fclose(pset.queryFout);
00053 }
00054
00055
00056 if (!fname || fname[0] == '\0')
00057 {
00058 pset.queryFout = stdout;
00059 pset.queryFoutPipe = false;
00060 }
00061 else if (*fname == '|')
00062 {
00063 pset.queryFout = popen(fname + 1, "w");
00064 pset.queryFoutPipe = true;
00065 }
00066 else
00067 {
00068 pset.queryFout = fopen(fname, "w");
00069 pset.queryFoutPipe = false;
00070 }
00071
00072 if (!(pset.queryFout))
00073 {
00074 psql_error("%s: %s\n", fname, strerror(errno));
00075 pset.queryFout = stdout;
00076 pset.queryFoutPipe = false;
00077 status = false;
00078 }
00079
00080
00081 #ifndef WIN32
00082 pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
00083 #endif
00084
00085 return status;
00086 }
00087
00088
00089
00090
00091
00092
00093
00094
00095 void
00096 psql_error(const char *fmt,...)
00097 {
00098 va_list ap;
00099
00100 fflush(stdout);
00101 if (pset.queryFout && pset.queryFout != stdout)
00102 fflush(pset.queryFout);
00103
00104 if (pset.inputfile)
00105 fprintf(stderr, "%s:%s:" UINT64_FORMAT ": ", pset.progname, pset.inputfile, pset.lineno);
00106 va_start(ap, fmt);
00107 vfprintf(stderr, _(fmt), ap);
00108 va_end(ap);
00109 }
00110
00111
00112
00113
00114
00115
00116 void
00117 NoticeProcessor(void *arg, const char *message)
00118 {
00119 (void) arg;
00120 psql_error("%s", message);
00121 }
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 volatile bool sigint_interrupt_enabled = false;
00150
00151 sigjmp_buf sigint_interrupt_jmp;
00152
00153 static PGcancel *volatile cancelConn = NULL;
00154
00155 #ifdef WIN32
00156 static CRITICAL_SECTION cancelConnLock;
00157 #endif
00158
00159
00160 #define write_stderr(str) write(fileno(stderr), str, strlen(str))
00161
00162
00163 #ifndef WIN32
00164
00165 static void
00166 handle_sigint(SIGNAL_ARGS)
00167 {
00168 int save_errno = errno;
00169 int rc;
00170 char errbuf[256];
00171
00172
00173 if (sigint_interrupt_enabled)
00174 {
00175 sigint_interrupt_enabled = false;
00176 siglongjmp(sigint_interrupt_jmp, 1);
00177 }
00178
00179
00180 cancel_pressed = true;
00181
00182
00183 if (cancelConn != NULL)
00184 {
00185 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
00186 {
00187 rc = write_stderr("Cancel request sent\n");
00188 (void) rc;
00189 }
00190 else
00191 {
00192 rc = write_stderr("Could not send cancel request: ");
00193 (void) rc;
00194 rc = write_stderr(errbuf);
00195 (void) rc;
00196 }
00197 }
00198
00199 errno = save_errno;
00200 }
00201
00202 void
00203 setup_cancel_handler(void)
00204 {
00205 pqsignal(SIGINT, handle_sigint);
00206 }
00207 #else
00208
00209 static BOOL WINAPI
00210 consoleHandler(DWORD dwCtrlType)
00211 {
00212 char errbuf[256];
00213
00214 if (dwCtrlType == CTRL_C_EVENT ||
00215 dwCtrlType == CTRL_BREAK_EVENT)
00216 {
00217
00218
00219
00220
00221
00222 cancel_pressed = true;
00223
00224
00225 EnterCriticalSection(&cancelConnLock);
00226 if (cancelConn != NULL)
00227 {
00228 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
00229 write_stderr("Cancel request sent\n");
00230 else
00231 {
00232 write_stderr("Could not send cancel request: ");
00233 write_stderr(errbuf);
00234 }
00235 }
00236 LeaveCriticalSection(&cancelConnLock);
00237
00238 return TRUE;
00239 }
00240 else
00241
00242 return FALSE;
00243 }
00244
00245 void
00246 setup_cancel_handler(void)
00247 {
00248 InitializeCriticalSection(&cancelConnLock);
00249
00250 SetConsoleCtrlHandler(consoleHandler, TRUE);
00251 }
00252 #endif
00253
00254
00255
00256
00257
00258
00259 static bool
00260 ConnectionUp(void)
00261 {
00262 return PQstatus(pset.db) != CONNECTION_BAD;
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 static bool
00278 CheckConnection(void)
00279 {
00280 bool OK;
00281
00282 OK = ConnectionUp();
00283 if (!OK)
00284 {
00285 if (!pset.cur_cmd_interactive)
00286 {
00287 psql_error("connection to server was lost\n");
00288 exit(EXIT_BADCONN);
00289 }
00290
00291 psql_error("The connection to the server was lost. Attempting reset: ");
00292 PQreset(pset.db);
00293 OK = ConnectionUp();
00294 if (!OK)
00295 {
00296 psql_error("Failed.\n");
00297 PQfinish(pset.db);
00298 pset.db = NULL;
00299 ResetCancelConn();
00300 UnsyncVariables();
00301 }
00302 else
00303 psql_error("Succeeded.\n");
00304 }
00305
00306 return OK;
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316 void
00317 SetCancelConn(void)
00318 {
00319 PGcancel *oldCancelConn;
00320
00321 #ifdef WIN32
00322 EnterCriticalSection(&cancelConnLock);
00323 #endif
00324
00325
00326 oldCancelConn = cancelConn;
00327
00328 cancelConn = NULL;
00329
00330 if (oldCancelConn != NULL)
00331 PQfreeCancel(oldCancelConn);
00332
00333 cancelConn = PQgetCancel(pset.db);
00334
00335 #ifdef WIN32
00336 LeaveCriticalSection(&cancelConnLock);
00337 #endif
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 void
00347 ResetCancelConn(void)
00348 {
00349 PGcancel *oldCancelConn;
00350
00351 #ifdef WIN32
00352 EnterCriticalSection(&cancelConnLock);
00353 #endif
00354
00355 oldCancelConn = cancelConn;
00356
00357 cancelConn = NULL;
00358
00359 if (oldCancelConn != NULL)
00360 PQfreeCancel(oldCancelConn);
00361
00362 #ifdef WIN32
00363 LeaveCriticalSection(&cancelConnLock);
00364 #endif
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 static bool
00377 AcceptResult(const PGresult *result)
00378 {
00379 bool OK;
00380
00381 if (!result)
00382 OK = false;
00383 else
00384 switch (PQresultStatus(result))
00385 {
00386 case PGRES_COMMAND_OK:
00387 case PGRES_TUPLES_OK:
00388 case PGRES_EMPTY_QUERY:
00389 case PGRES_COPY_IN:
00390 case PGRES_COPY_OUT:
00391
00392 OK = true;
00393 break;
00394
00395 case PGRES_BAD_RESPONSE:
00396 case PGRES_NONFATAL_ERROR:
00397 case PGRES_FATAL_ERROR:
00398 OK = false;
00399 break;
00400
00401 default:
00402 OK = false;
00403 psql_error("unexpected PQresultStatus: %d\n",
00404 PQresultStatus(result));
00405 break;
00406 }
00407
00408 if (!OK)
00409 {
00410 const char *error = PQerrorMessage(pset.db);
00411
00412 if (strlen(error))
00413 psql_error("%s", error);
00414
00415 CheckConnection();
00416 }
00417
00418 return OK;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 PGresult *
00440 PSQLexec(const char *query, bool start_xact)
00441 {
00442 PGresult *res;
00443
00444 if (!pset.db)
00445 {
00446 psql_error("You are currently not connected to a database.\n");
00447 return NULL;
00448 }
00449
00450 if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
00451 {
00452 printf(_("********* QUERY **********\n"
00453 "%s\n"
00454 "**************************\n\n"), query);
00455 fflush(stdout);
00456 if (pset.logfile)
00457 {
00458 fprintf(pset.logfile,
00459 _("********* QUERY **********\n"
00460 "%s\n"
00461 "**************************\n\n"), query);
00462 fflush(pset.logfile);
00463 }
00464
00465 if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
00466 return NULL;
00467 }
00468
00469 SetCancelConn();
00470
00471 if (start_xact &&
00472 !pset.autocommit &&
00473 PQtransactionStatus(pset.db) == PQTRANS_IDLE)
00474 {
00475 res = PQexec(pset.db, "BEGIN");
00476 if (PQresultStatus(res) != PGRES_COMMAND_OK)
00477 {
00478 psql_error("%s", PQerrorMessage(pset.db));
00479 PQclear(res);
00480 ResetCancelConn();
00481 return NULL;
00482 }
00483 PQclear(res);
00484 }
00485
00486 res = PQexec(pset.db, query);
00487
00488 ResetCancelConn();
00489
00490 if (!AcceptResult(res))
00491 {
00492 PQclear(res);
00493 res = NULL;
00494 }
00495
00496 return res;
00497 }
00498
00499
00500
00501
00502
00503
00504 static void
00505 PrintNotifications(void)
00506 {
00507 PGnotify *notify;
00508
00509 while ((notify = PQnotifies(pset.db)))
00510 {
00511
00512 if (notify->extra[0])
00513 fprintf(pset.queryFout, _("Asynchronous notification \"%s\" with payload \"%s\" received from server process with PID %d.\n"),
00514 notify->relname, notify->extra, notify->be_pid);
00515 else
00516 fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
00517 notify->relname, notify->be_pid);
00518 fflush(pset.queryFout);
00519 PQfreemem(notify);
00520 }
00521 }
00522
00523
00524
00525
00526
00527
00528
00529 static bool
00530 PrintQueryTuples(const PGresult *results)
00531 {
00532 printQueryOpt my_popt = pset.popt;
00533
00534
00535 if (pset.gfname)
00536 {
00537
00538 FILE *queryFout_copy = pset.queryFout;
00539 bool queryFoutPipe_copy = pset.queryFoutPipe;
00540
00541 pset.queryFout = stdout;
00542
00543
00544 if (!setQFout(pset.gfname))
00545 {
00546 pset.queryFout = queryFout_copy;
00547 pset.queryFoutPipe = queryFoutPipe_copy;
00548 return false;
00549 }
00550
00551 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
00552
00553
00554 setQFout(NULL);
00555
00556 pset.queryFout = queryFout_copy;
00557 pset.queryFoutPipe = queryFoutPipe_copy;
00558 }
00559 else
00560 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
00561
00562 return true;
00563 }
00564
00565
00566
00567
00568
00569
00570
00571 static bool
00572 StoreQueryTuple(const PGresult *result)
00573 {
00574 bool success = true;
00575
00576 if (PQntuples(result) < 1)
00577 {
00578 psql_error("no rows returned for \\gset\n");
00579 success = false;
00580 }
00581 else if (PQntuples(result) > 1)
00582 {
00583 psql_error("more than one row returned for \\gset\n");
00584 success = false;
00585 }
00586 else
00587 {
00588 int i;
00589
00590 for (i = 0; i < PQnfields(result); i++)
00591 {
00592 char *colname = PQfname(result, i);
00593 char *varname;
00594 char *value;
00595
00596
00597 varname = pg_malloc(strlen(pset.gset_prefix) + strlen(colname) + 1);
00598 strcpy(varname, pset.gset_prefix);
00599 strcat(varname, colname);
00600
00601 if (!PQgetisnull(result, 0, i))
00602 value = PQgetvalue(result, 0, i);
00603 else
00604 {
00605
00606 value = NULL;
00607 }
00608
00609 if (!SetVariable(pset.vars, varname, value))
00610 {
00611 psql_error("could not set variable \"%s\"\n", varname);
00612 free(varname);
00613 success = false;
00614 break;
00615 }
00616
00617 free(varname);
00618 }
00619 }
00620
00621 return success;
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643 static bool
00644 ProcessResult(PGresult **results)
00645 {
00646 PGresult *next_result;
00647 bool success = true;
00648 bool first_cycle = true;
00649
00650 do
00651 {
00652 ExecStatusType result_status;
00653 bool is_copy;
00654
00655 if (!AcceptResult(*results))
00656 {
00657
00658
00659
00660
00661
00662 success = false;
00663 break;
00664 }
00665
00666 result_status = PQresultStatus(*results);
00667 switch (result_status)
00668 {
00669 case PGRES_EMPTY_QUERY:
00670 case PGRES_COMMAND_OK:
00671 case PGRES_TUPLES_OK:
00672 is_copy = false;
00673 break;
00674
00675 case PGRES_COPY_OUT:
00676 case PGRES_COPY_IN:
00677 is_copy = true;
00678 break;
00679
00680 default:
00681
00682 is_copy = false;
00683 psql_error("unexpected PQresultStatus: %d\n", result_status);
00684 break;
00685 }
00686
00687 if (is_copy)
00688 {
00689
00690
00691
00692
00693
00694 SetCancelConn();
00695 if (result_status == PGRES_COPY_OUT)
00696 success = handleCopyOut(pset.db, pset.queryFout) && success;
00697 else
00698 success = handleCopyIn(pset.db, pset.cur_cmd_source,
00699 PQbinaryTuples(*results)) && success;
00700 ResetCancelConn();
00701
00702
00703
00704
00705
00706
00707 PQclear(*results);
00708 *results = next_result = PQgetResult(pset.db);
00709 }
00710 else if (first_cycle)
00711
00712 break;
00713 else if ((next_result = PQgetResult(pset.db)))
00714 {
00715
00716 PQclear(*results);
00717 *results = next_result;
00718 }
00719
00720 first_cycle = false;
00721 } while (next_result);
00722
00723
00724 if (!first_cycle && !CheckConnection())
00725 return false;
00726
00727 return success;
00728 }
00729
00730
00731
00732
00733
00734
00735
00736 static void
00737 PrintQueryStatus(PGresult *results)
00738 {
00739 char buf[16];
00740
00741 if (!pset.quiet)
00742 {
00743 if (pset.popt.topt.format == PRINT_HTML)
00744 {
00745 fputs("<p>", pset.queryFout);
00746 html_escaped_print(PQcmdStatus(results), pset.queryFout);
00747 fputs("</p>\n", pset.queryFout);
00748 }
00749 else
00750 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
00751 }
00752
00753 if (pset.logfile)
00754 fprintf(pset.logfile, "%s\n", PQcmdStatus(results));
00755
00756 snprintf(buf, sizeof(buf), "%u", (unsigned int) PQoidValue(results));
00757 SetVariable(pset.vars, "LASTOID", buf);
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768 static bool
00769 PrintQueryResults(PGresult *results)
00770 {
00771 bool success;
00772 const char *cmdstatus;
00773
00774 if (!results)
00775 return false;
00776
00777 switch (PQresultStatus(results))
00778 {
00779 case PGRES_TUPLES_OK:
00780
00781 if (pset.gset_prefix)
00782 success = StoreQueryTuple(results);
00783 else
00784 success = PrintQueryTuples(results);
00785
00786 cmdstatus = PQcmdStatus(results);
00787 if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
00788 strncmp(cmdstatus, "UPDATE", 6) == 0 ||
00789 strncmp(cmdstatus, "DELETE", 6) == 0)
00790 PrintQueryStatus(results);
00791 break;
00792
00793 case PGRES_COMMAND_OK:
00794 PrintQueryStatus(results);
00795 success = true;
00796 break;
00797
00798 case PGRES_EMPTY_QUERY:
00799 success = true;
00800 break;
00801
00802 case PGRES_COPY_OUT:
00803 case PGRES_COPY_IN:
00804
00805 success = true;
00806 break;
00807
00808 case PGRES_BAD_RESPONSE:
00809 case PGRES_NONFATAL_ERROR:
00810 case PGRES_FATAL_ERROR:
00811 success = false;
00812 break;
00813
00814 default:
00815 success = false;
00816 psql_error("unexpected PQresultStatus: %d\n",
00817 PQresultStatus(results));
00818 break;
00819 }
00820
00821 fflush(pset.queryFout);
00822
00823 return success;
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 bool
00840 SendQuery(const char *query)
00841 {
00842 PGresult *results;
00843 PGTransactionStatusType transaction_status;
00844 double elapsed_msec = 0;
00845 bool OK = false;
00846 bool on_error_rollback_savepoint = false;
00847 static bool on_error_rollback_warning = false;
00848
00849 if (!pset.db)
00850 {
00851 psql_error("You are currently not connected to a database.\n");
00852 goto sendquery_cleanup;
00853 }
00854
00855 if (pset.singlestep)
00856 {
00857 char buf[3];
00858
00859 printf(_("***(Single step mode: verify command)*******************************************\n"
00860 "%s\n"
00861 "***(press return to proceed or enter x and return to cancel)********************\n"),
00862 query);
00863 fflush(stdout);
00864 if (fgets(buf, sizeof(buf), stdin) != NULL)
00865 if (buf[0] == 'x')
00866 goto sendquery_cleanup;
00867 }
00868 else if (pset.echo == PSQL_ECHO_QUERIES)
00869 {
00870 puts(query);
00871 fflush(stdout);
00872 }
00873
00874 if (pset.logfile)
00875 {
00876 fprintf(pset.logfile,
00877 _("********* QUERY **********\n"
00878 "%s\n"
00879 "**************************\n\n"), query);
00880 fflush(pset.logfile);
00881 }
00882
00883 SetCancelConn();
00884
00885 transaction_status = PQtransactionStatus(pset.db);
00886
00887 if (transaction_status == PQTRANS_IDLE &&
00888 !pset.autocommit &&
00889 !command_no_begin(query))
00890 {
00891 results = PQexec(pset.db, "BEGIN");
00892 if (PQresultStatus(results) != PGRES_COMMAND_OK)
00893 {
00894 psql_error("%s", PQerrorMessage(pset.db));
00895 PQclear(results);
00896 ResetCancelConn();
00897 goto sendquery_cleanup;
00898 }
00899 PQclear(results);
00900 transaction_status = PQtransactionStatus(pset.db);
00901 }
00902
00903 if (transaction_status == PQTRANS_INTRANS &&
00904 pset.on_error_rollback != PSQL_ERROR_ROLLBACK_OFF &&
00905 (pset.cur_cmd_interactive ||
00906 pset.on_error_rollback == PSQL_ERROR_ROLLBACK_ON))
00907 {
00908 if (on_error_rollback_warning == false && pset.sversion < 80000)
00909 {
00910 psql_error("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n",
00911 pset.sversion / 10000, (pset.sversion / 100) % 100);
00912 on_error_rollback_warning = true;
00913 }
00914 else
00915 {
00916 results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint");
00917 if (PQresultStatus(results) != PGRES_COMMAND_OK)
00918 {
00919 psql_error("%s", PQerrorMessage(pset.db));
00920 PQclear(results);
00921 ResetCancelConn();
00922 goto sendquery_cleanup;
00923 }
00924 PQclear(results);
00925 on_error_rollback_savepoint = true;
00926 }
00927 }
00928
00929 if (pset.fetch_count <= 0 || !is_select_command(query))
00930 {
00931
00932 instr_time before,
00933 after;
00934
00935 if (pset.timing)
00936 INSTR_TIME_SET_CURRENT(before);
00937
00938 results = PQexec(pset.db, query);
00939
00940
00941 ResetCancelConn();
00942 OK = ProcessResult(&results);
00943
00944 if (pset.timing)
00945 {
00946 INSTR_TIME_SET_CURRENT(after);
00947 INSTR_TIME_SUBTRACT(after, before);
00948 elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
00949 }
00950
00951
00952 if (OK && results)
00953 OK = PrintQueryResults(results);
00954 }
00955 else
00956 {
00957
00958 OK = ExecQueryUsingCursor(query, &elapsed_msec);
00959 ResetCancelConn();
00960 results = NULL;
00961 }
00962
00963
00964 if (on_error_rollback_savepoint)
00965 {
00966 const char *svptcmd = NULL;
00967
00968 transaction_status = PQtransactionStatus(pset.db);
00969
00970 switch (transaction_status)
00971 {
00972 case PQTRANS_INERROR:
00973
00974 svptcmd = "ROLLBACK TO pg_psql_temporary_savepoint";
00975 break;
00976
00977 case PQTRANS_IDLE:
00978
00979 break;
00980
00981 case PQTRANS_INTRANS:
00982
00983
00984
00985
00986
00987
00988
00989 if (results &&
00990 (strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 ||
00991 strcmp(PQcmdStatus(results), "RELEASE") == 0 ||
00992 strcmp(PQcmdStatus(results), "ROLLBACK") == 0))
00993 svptcmd = NULL;
00994 else
00995 svptcmd = "RELEASE pg_psql_temporary_savepoint";
00996 break;
00997
00998 case PQTRANS_ACTIVE:
00999 case PQTRANS_UNKNOWN:
01000 default:
01001 OK = false;
01002
01003 if (transaction_status != PQTRANS_UNKNOWN || ConnectionUp())
01004 psql_error("unexpected transaction status (%d)\n",
01005 transaction_status);
01006 break;
01007 }
01008
01009 if (svptcmd)
01010 {
01011 PGresult *svptres;
01012
01013 svptres = PQexec(pset.db, svptcmd);
01014 if (PQresultStatus(svptres) != PGRES_COMMAND_OK)
01015 {
01016 psql_error("%s", PQerrorMessage(pset.db));
01017 PQclear(svptres);
01018 OK = false;
01019
01020 PQclear(results);
01021 ResetCancelConn();
01022 goto sendquery_cleanup;
01023 }
01024 PQclear(svptres);
01025 }
01026 }
01027
01028 PQclear(results);
01029
01030
01031 if (pset.timing)
01032 printf(_("Time: %.3f ms\n"), elapsed_msec);
01033
01034
01035
01036 if (pset.encoding != PQclientEncoding(pset.db) &&
01037 PQclientEncoding(pset.db) >= 0)
01038 {
01039
01040 pset.encoding = PQclientEncoding(pset.db);
01041 pset.popt.topt.encoding = pset.encoding;
01042 SetVariable(pset.vars, "ENCODING",
01043 pg_encoding_to_char(pset.encoding));
01044 }
01045
01046 PrintNotifications();
01047
01048
01049
01050 sendquery_cleanup:
01051
01052
01053 if (pset.gfname)
01054 {
01055 free(pset.gfname);
01056 pset.gfname = NULL;
01057 }
01058
01059
01060 if (pset.gset_prefix)
01061 {
01062 free(pset.gset_prefix);
01063 pset.gset_prefix = NULL;
01064 }
01065
01066 return OK;
01067 }
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080 static bool
01081 ExecQueryUsingCursor(const char *query, double *elapsed_msec)
01082 {
01083 bool OK = true;
01084 PGresult *results;
01085 PQExpBufferData buf;
01086 printQueryOpt my_popt = pset.popt;
01087 FILE *queryFout_copy = pset.queryFout;
01088 bool queryFoutPipe_copy = pset.queryFoutPipe;
01089 bool started_txn = false;
01090 bool did_pager = false;
01091 int ntuples;
01092 int fetch_count;
01093 char fetch_cmd[64];
01094 instr_time before,
01095 after;
01096 int flush_error;
01097
01098 *elapsed_msec = 0;
01099
01100
01101 my_popt.topt.start_table = true;
01102 my_popt.topt.stop_table = false;
01103 my_popt.topt.prior_records = 0;
01104
01105 if (pset.timing)
01106 INSTR_TIME_SET_CURRENT(before);
01107
01108
01109 if (PQtransactionStatus(pset.db) == PQTRANS_IDLE)
01110 {
01111 results = PQexec(pset.db, "BEGIN");
01112 OK = AcceptResult(results) &&
01113 (PQresultStatus(results) == PGRES_COMMAND_OK);
01114 PQclear(results);
01115 if (!OK)
01116 return false;
01117 started_txn = true;
01118 }
01119
01120
01121 initPQExpBuffer(&buf);
01122 appendPQExpBuffer(&buf, "DECLARE _psql_cursor NO SCROLL CURSOR FOR\n%s",
01123 query);
01124
01125 results = PQexec(pset.db, buf.data);
01126 OK = AcceptResult(results) &&
01127 (PQresultStatus(results) == PGRES_COMMAND_OK);
01128 PQclear(results);
01129 termPQExpBuffer(&buf);
01130 if (!OK)
01131 goto cleanup;
01132
01133 if (pset.timing)
01134 {
01135 INSTR_TIME_SET_CURRENT(after);
01136 INSTR_TIME_SUBTRACT(after, before);
01137 *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
01138 }
01139
01140
01141
01142
01143
01144 if (pset.gset_prefix)
01145 fetch_count = 2;
01146 else
01147 fetch_count = pset.fetch_count;
01148
01149 snprintf(fetch_cmd, sizeof(fetch_cmd),
01150 "FETCH FORWARD %d FROM _psql_cursor",
01151 fetch_count);
01152
01153
01154 if (pset.gfname)
01155 {
01156
01157 pset.queryFout = stdout;
01158
01159
01160 if (!setQFout(pset.gfname))
01161 {
01162 pset.queryFout = queryFout_copy;
01163 pset.queryFoutPipe = queryFoutPipe_copy;
01164 OK = false;
01165 goto cleanup;
01166 }
01167 }
01168
01169
01170 clearerr(pset.queryFout);
01171
01172 for (;;)
01173 {
01174 if (pset.timing)
01175 INSTR_TIME_SET_CURRENT(before);
01176
01177
01178 results = PQexec(pset.db, fetch_cmd);
01179
01180 if (pset.timing)
01181 {
01182 INSTR_TIME_SET_CURRENT(after);
01183 INSTR_TIME_SUBTRACT(after, before);
01184 *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
01185 }
01186
01187 if (PQresultStatus(results) != PGRES_TUPLES_OK)
01188 {
01189
01190 if (did_pager)
01191 {
01192 ClosePager(pset.queryFout);
01193 pset.queryFout = queryFout_copy;
01194 pset.queryFoutPipe = queryFoutPipe_copy;
01195 did_pager = false;
01196 }
01197
01198 OK = AcceptResult(results);
01199 Assert(!OK);
01200 PQclear(results);
01201 break;
01202 }
01203
01204 if (pset.gset_prefix)
01205 {
01206
01207 OK = StoreQueryTuple(results);
01208 PQclear(results);
01209 break;
01210 }
01211
01212 ntuples = PQntuples(results);
01213
01214 if (ntuples < fetch_count)
01215 {
01216
01217 my_popt.topt.stop_table = true;
01218 }
01219 else if (pset.queryFout == stdout && !did_pager)
01220 {
01221
01222
01223
01224
01225 pset.queryFout = PageOutput(100000, my_popt.topt.pager);
01226 did_pager = true;
01227 }
01228
01229 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
01230
01231 PQclear(results);
01232
01233
01234 my_popt.topt.start_table = false;
01235 my_popt.topt.prior_records += ntuples;
01236
01237
01238
01239
01240
01241
01242
01243 flush_error = fflush(pset.queryFout);
01244
01245
01246
01247
01248
01249
01250
01251
01252 if (ntuples < fetch_count || cancel_pressed || flush_error ||
01253 ferror(pset.queryFout))
01254 break;
01255 }
01256
01257
01258 if (pset.gfname)
01259 {
01260
01261 setQFout(NULL);
01262
01263 pset.queryFout = queryFout_copy;
01264 pset.queryFoutPipe = queryFoutPipe_copy;
01265 }
01266 else if (did_pager)
01267 {
01268 ClosePager(pset.queryFout);
01269 pset.queryFout = queryFout_copy;
01270 pset.queryFoutPipe = queryFoutPipe_copy;
01271 }
01272
01273 cleanup:
01274 if (pset.timing)
01275 INSTR_TIME_SET_CURRENT(before);
01276
01277
01278
01279
01280
01281
01282 results = PQexec(pset.db, "CLOSE _psql_cursor");
01283 if (OK)
01284 {
01285 OK = AcceptResult(results) &&
01286 (PQresultStatus(results) == PGRES_COMMAND_OK);
01287 }
01288 PQclear(results);
01289
01290 if (started_txn)
01291 {
01292 results = PQexec(pset.db, OK ? "COMMIT" : "ROLLBACK");
01293 OK &= AcceptResult(results) &&
01294 (PQresultStatus(results) == PGRES_COMMAND_OK);
01295 PQclear(results);
01296 }
01297
01298 if (pset.timing)
01299 {
01300 INSTR_TIME_SET_CURRENT(after);
01301 INSTR_TIME_SUBTRACT(after, before);
01302 *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
01303 }
01304
01305 return OK;
01306 }
01307
01308
01309
01310
01311
01312 static const char *
01313 skip_white_space(const char *query)
01314 {
01315 int cnestlevel = 0;
01316
01317 while (*query)
01318 {
01319 int mblen = PQmblen(query, pset.encoding);
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329 if (isspace((unsigned char) *query))
01330 query += mblen;
01331 else if (query[0] == '/' && query[1] == '*')
01332 {
01333 cnestlevel++;
01334 query += 2;
01335 }
01336 else if (cnestlevel > 0 && query[0] == '*' && query[1] == '/')
01337 {
01338 cnestlevel--;
01339 query += 2;
01340 }
01341 else if (cnestlevel == 0 && query[0] == '-' && query[1] == '-')
01342 {
01343 query += 2;
01344
01345
01346
01347
01348
01349 while (*query)
01350 {
01351 if (*query == '\n')
01352 {
01353 query++;
01354 break;
01355 }
01356 query += PQmblen(query, pset.encoding);
01357 }
01358 }
01359 else if (cnestlevel > 0)
01360 query += mblen;
01361 else
01362 break;
01363 }
01364
01365 return query;
01366 }
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376 static bool
01377 command_no_begin(const char *query)
01378 {
01379 int wordlen;
01380
01381
01382
01383
01384 query = skip_white_space(query);
01385
01386
01387
01388
01389 wordlen = 0;
01390 while (isalpha((unsigned char) query[wordlen]))
01391 wordlen += PQmblen(&query[wordlen], pset.encoding);
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401 if (wordlen == 5 && pg_strncasecmp(query, "abort", 5) == 0)
01402 return true;
01403 if (wordlen == 5 && pg_strncasecmp(query, "begin", 5) == 0)
01404 return true;
01405 if (wordlen == 5 && pg_strncasecmp(query, "start", 5) == 0)
01406 return true;
01407 if (wordlen == 6 && pg_strncasecmp(query, "commit", 6) == 0)
01408 return true;
01409 if (wordlen == 3 && pg_strncasecmp(query, "end", 3) == 0)
01410 return true;
01411 if (wordlen == 8 && pg_strncasecmp(query, "rollback", 8) == 0)
01412 return true;
01413 if (wordlen == 7 && pg_strncasecmp(query, "prepare", 7) == 0)
01414 {
01415
01416 query += wordlen;
01417
01418 query = skip_white_space(query);
01419
01420 wordlen = 0;
01421 while (isalpha((unsigned char) query[wordlen]))
01422 wordlen += PQmblen(&query[wordlen], pset.encoding);
01423
01424 if (wordlen == 11 && pg_strncasecmp(query, "transaction", 11) == 0)
01425 return true;
01426 return false;
01427 }
01428
01429
01430
01431
01432
01433
01434 if (wordlen == 6 && pg_strncasecmp(query, "vacuum", 6) == 0)
01435 return true;
01436 if (wordlen == 7 && pg_strncasecmp(query, "cluster", 7) == 0)
01437 {
01438
01439 query += wordlen;
01440
01441 query = skip_white_space(query);
01442
01443 if (isalpha((unsigned char) query[0]))
01444 return false;
01445 return true;
01446 }
01447
01448 if (wordlen == 6 && pg_strncasecmp(query, "create", 6) == 0)
01449 {
01450 query += wordlen;
01451
01452 query = skip_white_space(query);
01453
01454 wordlen = 0;
01455 while (isalpha((unsigned char) query[wordlen]))
01456 wordlen += PQmblen(&query[wordlen], pset.encoding);
01457
01458 if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
01459 return true;
01460 if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
01461 return true;
01462
01463
01464 if (wordlen == 6 && pg_strncasecmp(query, "unique", 6) == 0)
01465 {
01466 query += wordlen;
01467
01468 query = skip_white_space(query);
01469
01470 wordlen = 0;
01471 while (isalpha((unsigned char) query[wordlen]))
01472 wordlen += PQmblen(&query[wordlen], pset.encoding);
01473 }
01474
01475 if (wordlen == 5 && pg_strncasecmp(query, "index", 5) == 0)
01476 {
01477 query += wordlen;
01478
01479 query = skip_white_space(query);
01480
01481 wordlen = 0;
01482 while (isalpha((unsigned char) query[wordlen]))
01483 wordlen += PQmblen(&query[wordlen], pset.encoding);
01484
01485 if (wordlen == 12 && pg_strncasecmp(query, "concurrently", 12) == 0)
01486 return true;
01487 }
01488
01489 return false;
01490 }
01491
01492
01493
01494
01495
01496
01497 if ((wordlen == 4 && pg_strncasecmp(query, "drop", 4) == 0) ||
01498 (wordlen == 7 && pg_strncasecmp(query, "reindex", 7) == 0))
01499 {
01500 query += wordlen;
01501
01502 query = skip_white_space(query);
01503
01504 wordlen = 0;
01505 while (isalpha((unsigned char) query[wordlen]))
01506 wordlen += PQmblen(&query[wordlen], pset.encoding);
01507
01508 if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
01509 return true;
01510 if (wordlen == 6 && pg_strncasecmp(query, "system", 6) == 0)
01511 return true;
01512 if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
01513 return true;
01514 return false;
01515 }
01516
01517
01518 if (wordlen == 7 && pg_strncasecmp(query, "discard", 7) == 0)
01519 {
01520 query += wordlen;
01521
01522 query = skip_white_space(query);
01523
01524 wordlen = 0;
01525 while (isalpha((unsigned char) query[wordlen]))
01526 wordlen += PQmblen(&query[wordlen], pset.encoding);
01527
01528 if (wordlen == 3 && pg_strncasecmp(query, "all", 3) == 0)
01529 return true;
01530 return false;
01531 }
01532
01533 return false;
01534 }
01535
01536
01537
01538
01539
01540 static bool
01541 is_select_command(const char *query)
01542 {
01543 int wordlen;
01544
01545
01546
01547
01548 for (;;)
01549 {
01550 query = skip_white_space(query);
01551 if (query[0] == '(')
01552 query++;
01553 else
01554 break;
01555 }
01556
01557
01558
01559
01560 wordlen = 0;
01561 while (isalpha((unsigned char) query[wordlen]))
01562 wordlen += PQmblen(&query[wordlen], pset.encoding);
01563
01564 if (wordlen == 6 && pg_strncasecmp(query, "select", 6) == 0)
01565 return true;
01566
01567 if (wordlen == 6 && pg_strncasecmp(query, "values", 6) == 0)
01568 return true;
01569
01570 return false;
01571 }
01572
01573
01574
01575
01576
01577
01578
01579
01580 bool
01581 is_superuser(void)
01582 {
01583 const char *val;
01584
01585 if (!pset.db)
01586 return false;
01587
01588 val = PQparameterStatus(pset.db, "is_superuser");
01589
01590 if (val && strcmp(val, "on") == 0)
01591 return true;
01592
01593 return false;
01594 }
01595
01596
01597
01598
01599
01600
01601
01602
01603 bool
01604 standard_strings(void)
01605 {
01606 const char *val;
01607
01608 if (!pset.db)
01609 return false;
01610
01611 val = PQparameterStatus(pset.db, "standard_conforming_strings");
01612
01613 if (val && strcmp(val, "on") == 0)
01614 return true;
01615
01616 return false;
01617 }
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627 const char *
01628 session_username(void)
01629 {
01630 const char *val;
01631
01632 if (!pset.db)
01633 return NULL;
01634
01635 val = PQparameterStatus(pset.db, "session_authorization");
01636 if (val)
01637 return val;
01638 else
01639 return PQuser(pset.db);
01640 }
01641
01642
01643
01644
01645
01646
01647
01648 void
01649 expand_tilde(char **filename)
01650 {
01651 if (!filename || !(*filename))
01652 return;
01653
01654
01655
01656
01657
01658
01659 #ifndef WIN32
01660
01661
01662 if (**filename == '~')
01663 {
01664 char *fn;
01665 char oldp,
01666 *p;
01667 struct passwd *pw;
01668 char home[MAXPGPATH];
01669
01670 fn = *filename;
01671 *home = '\0';
01672
01673 p = fn + 1;
01674 while (*p != '/' && *p != '\0')
01675 p++;
01676
01677 oldp = *p;
01678 *p = '\0';
01679
01680 if (*(fn + 1) == '\0')
01681 get_home_path(home);
01682 else if ((pw = getpwnam(fn + 1)) != NULL)
01683 strlcpy(home, pw->pw_dir, sizeof(home));
01684
01685 *p = oldp;
01686 if (strlen(home) != 0)
01687 {
01688 char *newfn;
01689
01690 newfn = pg_malloc(strlen(home) + strlen(p) + 1);
01691 strcpy(newfn, home);
01692 strcat(newfn, p);
01693
01694 free(fn);
01695 *filename = newfn;
01696 }
01697 }
01698 #endif
01699
01700 return;
01701 }