00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres_fe.h"
00016
00017 #include <ctype.h>
00018 #include <fcntl.h>
00019
00020 #include "libpq-fe.h"
00021 #include "libpq-int.h"
00022
00023
00024 #ifdef WIN32
00025 #include "win32.h"
00026 #else
00027 #include <unistd.h>
00028 #include <netinet/in.h>
00029 #ifdef HAVE_NETINET_TCP_H
00030 #include <netinet/tcp.h>
00031 #endif
00032 #include <arpa/inet.h>
00033 #endif
00034
00035
00036 static int getRowDescriptions(PGconn *conn);
00037 static int getAnotherTuple(PGconn *conn, bool binary);
00038 static int pqGetErrorNotice2(PGconn *conn, bool isError);
00039 static void checkXactStatus(PGconn *conn, const char *cmdTag);
00040 static int getNotify(PGconn *conn);
00041
00042
00043
00044
00045
00046
00047
00048
00049 PostgresPollingStatusType
00050 pqSetenvPoll(PGconn *conn)
00051 {
00052 PGresult *res;
00053
00054 if (conn == NULL || conn->status == CONNECTION_BAD)
00055 return PGRES_POLLING_FAILED;
00056
00057
00058 switch (conn->setenv_state)
00059 {
00060
00061 case SETENV_STATE_CLIENT_ENCODING_WAIT:
00062 case SETENV_STATE_OPTION_WAIT:
00063 case SETENV_STATE_QUERY1_WAIT:
00064 case SETENV_STATE_QUERY2_WAIT:
00065 {
00066
00067 int n = pqReadData(conn);
00068
00069 if (n < 0)
00070 goto error_return;
00071 if (n == 0)
00072 return PGRES_POLLING_READING;
00073
00074 break;
00075 }
00076
00077
00078 case SETENV_STATE_CLIENT_ENCODING_SEND:
00079 case SETENV_STATE_OPTION_SEND:
00080 case SETENV_STATE_QUERY1_SEND:
00081 case SETENV_STATE_QUERY2_SEND:
00082 break;
00083
00084
00085 case SETENV_STATE_IDLE:
00086 return PGRES_POLLING_OK;
00087
00088 default:
00089 printfPQExpBuffer(&conn->errorMessage,
00090 libpq_gettext(
00091 "invalid setenv state %c, "
00092 "probably indicative of memory corruption\n"
00093 ),
00094 conn->setenv_state);
00095 goto error_return;
00096 }
00097
00098
00099 for (;;)
00100 {
00101 switch (conn->setenv_state)
00102 {
00103
00104
00105
00106
00107
00108 case SETENV_STATE_CLIENT_ENCODING_SEND:
00109 {
00110 char setQuery[100];
00111
00112 const char *val = conn->client_encoding_initial;
00113
00114 if (val)
00115 {
00116 if (pg_strcasecmp(val, "default") == 0)
00117 sprintf(setQuery, "SET client_encoding = DEFAULT");
00118 else
00119 sprintf(setQuery, "SET client_encoding = '%.60s'",
00120 val);
00121 #ifdef CONNECTDEBUG
00122 fprintf(stderr,
00123 "Sending client_encoding with %s\n",
00124 setQuery);
00125 #endif
00126 if (!PQsendQuery(conn, setQuery))
00127 goto error_return;
00128
00129 conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT;
00130 }
00131 else
00132 conn->setenv_state = SETENV_STATE_OPTION_SEND;
00133 break;
00134 }
00135
00136 case SETENV_STATE_OPTION_SEND:
00137 {
00138
00139
00140
00141
00142
00143
00144 char setQuery[100];
00145
00146
00147 if (conn->next_eo->envName)
00148 {
00149 const char *val;
00150
00151 if ((val = getenv(conn->next_eo->envName)))
00152 {
00153 if (pg_strcasecmp(val, "default") == 0)
00154 sprintf(setQuery, "SET %s = DEFAULT",
00155 conn->next_eo->pgName);
00156 else
00157 sprintf(setQuery, "SET %s = '%.60s'",
00158 conn->next_eo->pgName, val);
00159 #ifdef CONNECTDEBUG
00160 fprintf(stderr,
00161 "Use environment variable %s to send %s\n",
00162 conn->next_eo->envName, setQuery);
00163 #endif
00164 if (!PQsendQuery(conn, setQuery))
00165 goto error_return;
00166
00167 conn->setenv_state = SETENV_STATE_OPTION_WAIT;
00168 }
00169 else
00170 conn->next_eo++;
00171 }
00172 else
00173 {
00174
00175 conn->setenv_state = SETENV_STATE_QUERY1_SEND;
00176 }
00177 break;
00178 }
00179
00180 case SETENV_STATE_CLIENT_ENCODING_WAIT:
00181 {
00182 if (PQisBusy(conn))
00183 return PGRES_POLLING_READING;
00184
00185 res = PQgetResult(conn);
00186
00187 if (res)
00188 {
00189 if (PQresultStatus(res) != PGRES_COMMAND_OK)
00190 {
00191 PQclear(res);
00192 goto error_return;
00193 }
00194 PQclear(res);
00195
00196 }
00197 else
00198 {
00199
00200 conn->setenv_state = SETENV_STATE_OPTION_SEND;
00201 }
00202 break;
00203 }
00204
00205 case SETENV_STATE_OPTION_WAIT:
00206 {
00207 if (PQisBusy(conn))
00208 return PGRES_POLLING_READING;
00209
00210 res = PQgetResult(conn);
00211
00212 if (res)
00213 {
00214 if (PQresultStatus(res) != PGRES_COMMAND_OK)
00215 {
00216 PQclear(res);
00217 goto error_return;
00218 }
00219 PQclear(res);
00220
00221 }
00222 else
00223 {
00224
00225 conn->next_eo++;
00226 conn->setenv_state = SETENV_STATE_OPTION_SEND;
00227 }
00228 break;
00229 }
00230
00231 case SETENV_STATE_QUERY1_SEND:
00232 {
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 if (!PQsendQuery(conn, "begin; select version(); end"))
00244 goto error_return;
00245
00246 conn->setenv_state = SETENV_STATE_QUERY1_WAIT;
00247 return PGRES_POLLING_READING;
00248 }
00249
00250 case SETENV_STATE_QUERY1_WAIT:
00251 {
00252 if (PQisBusy(conn))
00253 return PGRES_POLLING_READING;
00254
00255 res = PQgetResult(conn);
00256
00257 if (res)
00258 {
00259 char *val;
00260
00261 if (PQresultStatus(res) == PGRES_COMMAND_OK)
00262 {
00263
00264 PQclear(res);
00265 continue;
00266 }
00267
00268 if (PQresultStatus(res) != PGRES_TUPLES_OK ||
00269 PQntuples(res) != 1)
00270 {
00271 PQclear(res);
00272 goto error_return;
00273 }
00274
00275
00276
00277
00278
00279 val = PQgetvalue(res, 0, 0);
00280 if (val && strncmp(val, "PostgreSQL ", 11) == 0)
00281 {
00282 char *ptr;
00283
00284
00285 val += 11;
00286
00287
00288
00289
00290
00291 ptr = strchr(val, ' ');
00292 if (ptr)
00293 *ptr = '\0';
00294
00295 pqSaveParameterStatus(conn, "server_version",
00296 val);
00297 }
00298
00299 PQclear(res);
00300
00301 }
00302 else
00303 {
00304
00305 conn->setenv_state = SETENV_STATE_QUERY2_SEND;
00306 }
00307 break;
00308 }
00309
00310 case SETENV_STATE_QUERY2_SEND:
00311 {
00312 const char *query;
00313
00314
00315
00316
00317
00318
00319
00320
00321 if (conn->sversion >= 70300 &&
00322 conn->sversion < 70400)
00323 query = "begin; select pg_catalog.pg_client_encoding(); end";
00324 else
00325 query = "select pg_client_encoding()";
00326 if (!PQsendQuery(conn, query))
00327 goto error_return;
00328
00329 conn->setenv_state = SETENV_STATE_QUERY2_WAIT;
00330 return PGRES_POLLING_READING;
00331 }
00332
00333 case SETENV_STATE_QUERY2_WAIT:
00334 {
00335 if (PQisBusy(conn))
00336 return PGRES_POLLING_READING;
00337
00338 res = PQgetResult(conn);
00339
00340 if (res)
00341 {
00342 const char *val;
00343
00344 if (PQresultStatus(res) == PGRES_COMMAND_OK)
00345 {
00346
00347 PQclear(res);
00348 continue;
00349 }
00350
00351 if (PQresultStatus(res) == PGRES_TUPLES_OK &&
00352 PQntuples(res) == 1)
00353 {
00354
00355 val = PQgetvalue(res, 0, 0);
00356 if (val && *val)
00357 pqSaveParameterStatus(conn, "client_encoding",
00358 val);
00359 }
00360 else
00361 {
00362
00363
00364
00365
00366
00367 val = getenv("PGCLIENTENCODING");
00368 if (val && *val)
00369 pqSaveParameterStatus(conn, "client_encoding",
00370 val);
00371 else
00372 pqSaveParameterStatus(conn, "client_encoding",
00373 "SQL_ASCII");
00374 }
00375
00376 PQclear(res);
00377
00378 }
00379 else
00380 {
00381
00382 conn->setenv_state = SETENV_STATE_IDLE;
00383 return PGRES_POLLING_OK;
00384 }
00385 break;
00386 }
00387
00388 default:
00389 printfPQExpBuffer(&conn->errorMessage,
00390 libpq_gettext("invalid state %c, "
00391 "probably indicative of memory corruption\n"),
00392 conn->setenv_state);
00393 goto error_return;
00394 }
00395 }
00396
00397
00398
00399 error_return:
00400 conn->setenv_state = SETENV_STATE_IDLE;
00401 return PGRES_POLLING_FAILED;
00402 }
00403
00404
00405
00406
00407
00408
00409
00410 void
00411 pqParseInput2(PGconn *conn)
00412 {
00413 char id;
00414
00415
00416
00417
00418 for (;;)
00419 {
00420
00421
00422
00423
00424
00425
00426 if (conn->asyncStatus == PGASYNC_COPY_OUT)
00427 return;
00428
00429
00430
00431
00432 conn->inCursor = conn->inStart;
00433 if (pqGetc(&id, conn))
00434 return;
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 if (id == 'A')
00448 {
00449 if (getNotify(conn))
00450 return;
00451 }
00452 else if (id == 'N')
00453 {
00454 if (pqGetErrorNotice2(conn, false))
00455 return;
00456 }
00457 else if (conn->asyncStatus != PGASYNC_BUSY)
00458 {
00459
00460 if (conn->asyncStatus != PGASYNC_IDLE)
00461 return;
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 if (id == 'E')
00472 {
00473 if (pqGetErrorNotice2(conn, false ))
00474 return;
00475 }
00476 else
00477 {
00478 pqInternalNotice(&conn->noticeHooks,
00479 "message type 0x%02x arrived from server while idle",
00480 id);
00481
00482 conn->inStart = conn->inEnd;
00483 break;
00484 }
00485 }
00486 else
00487 {
00488
00489
00490
00491 switch (id)
00492 {
00493 case 'C':
00494 if (pqGets(&conn->workBuffer, conn))
00495 return;
00496 if (conn->result == NULL)
00497 {
00498 conn->result = PQmakeEmptyPGresult(conn,
00499 PGRES_COMMAND_OK);
00500 if (!conn->result)
00501 return;
00502 }
00503 strncpy(conn->result->cmdStatus, conn->workBuffer.data,
00504 CMDSTATUS_LEN);
00505 checkXactStatus(conn, conn->workBuffer.data);
00506 conn->asyncStatus = PGASYNC_READY;
00507 break;
00508 case 'E':
00509 if (pqGetErrorNotice2(conn, true))
00510 return;
00511 conn->asyncStatus = PGASYNC_READY;
00512 break;
00513 case 'Z':
00514 conn->asyncStatus = PGASYNC_IDLE;
00515 break;
00516 case 'I':
00517
00518 if (pqGetc(&id, conn))
00519 return;
00520 if (id != '\0')
00521 pqInternalNotice(&conn->noticeHooks,
00522 "unexpected character %c following empty query response (\"I\" message)",
00523 id);
00524 if (conn->result == NULL)
00525 conn->result = PQmakeEmptyPGresult(conn,
00526 PGRES_EMPTY_QUERY);
00527 conn->asyncStatus = PGASYNC_READY;
00528 break;
00529 case 'K':
00530
00531
00532
00533
00534
00535
00536 if (pqGetInt(&(conn->be_pid), 4, conn))
00537 return;
00538 if (pqGetInt(&(conn->be_key), 4, conn))
00539 return;
00540 break;
00541 case 'P':
00542 if (pqGets(&conn->workBuffer, conn))
00543 return;
00544
00545 break;
00546 case 'T':
00547 if (conn->result == NULL)
00548 {
00549
00550 if (getRowDescriptions(conn))
00551 return;
00552
00553 continue;
00554 }
00555 else
00556 {
00557
00558
00559
00560
00561
00562
00563
00564 conn->asyncStatus = PGASYNC_READY;
00565 return;
00566 }
00567 break;
00568 case 'D':
00569 if (conn->result != NULL)
00570 {
00571
00572 if (getAnotherTuple(conn, FALSE))
00573 return;
00574
00575 continue;
00576 }
00577 else
00578 {
00579 pqInternalNotice(&conn->noticeHooks,
00580 "server sent data (\"D\" message) without prior row description (\"T\" message)");
00581
00582 conn->inStart = conn->inEnd;
00583 return;
00584 }
00585 break;
00586 case 'B':
00587 if (conn->result != NULL)
00588 {
00589
00590 if (getAnotherTuple(conn, TRUE))
00591 return;
00592
00593 continue;
00594 }
00595 else
00596 {
00597 pqInternalNotice(&conn->noticeHooks,
00598 "server sent binary data (\"B\" message) without prior row description (\"T\" message)");
00599
00600 conn->inStart = conn->inEnd;
00601 return;
00602 }
00603 break;
00604 case 'G':
00605 conn->asyncStatus = PGASYNC_COPY_IN;
00606 break;
00607 case 'H':
00608 conn->asyncStatus = PGASYNC_COPY_OUT;
00609 break;
00610
00611
00612
00613
00614
00615 default:
00616 printfPQExpBuffer(&conn->errorMessage,
00617 libpq_gettext(
00618 "unexpected response from server; first received character was \"%c\"\n"),
00619 id);
00620
00621 pqSaveErrorResult(conn);
00622
00623 conn->inStart = conn->inEnd;
00624 conn->asyncStatus = PGASYNC_READY;
00625 return;
00626 }
00627 }
00628
00629 conn->inStart = conn->inCursor;
00630 }
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643 static int
00644 getRowDescriptions(PGconn *conn)
00645 {
00646 PGresult *result;
00647 int nfields;
00648 const char *errmsg;
00649 int i;
00650
00651 result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
00652 if (!result)
00653 {
00654 errmsg = NULL;
00655 goto advance_and_error;
00656 }
00657
00658
00659
00660 if (pqGetInt(&(result->numAttributes), 2, conn))
00661 goto EOFexit;
00662 nfields = result->numAttributes;
00663
00664
00665 if (nfields > 0)
00666 {
00667 result->attDescs = (PGresAttDesc *)
00668 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
00669 if (!result->attDescs)
00670 {
00671 errmsg = NULL;
00672 goto advance_and_error;
00673 }
00674 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
00675 }
00676
00677
00678 for (i = 0; i < nfields; i++)
00679 {
00680 int typid;
00681 int typlen;
00682 int atttypmod;
00683
00684 if (pqGets(&conn->workBuffer, conn) ||
00685 pqGetInt(&typid, 4, conn) ||
00686 pqGetInt(&typlen, 2, conn) ||
00687 pqGetInt(&atttypmod, 4, conn))
00688 goto EOFexit;
00689
00690
00691
00692
00693
00694 typlen = (int) ((int16) typlen);
00695
00696 result->attDescs[i].name = pqResultStrdup(result,
00697 conn->workBuffer.data);
00698 if (!result->attDescs[i].name)
00699 {
00700 errmsg = NULL;
00701 goto advance_and_error;
00702 }
00703 result->attDescs[i].tableid = 0;
00704 result->attDescs[i].columnid = 0;
00705 result->attDescs[i].format = 0;
00706 result->attDescs[i].typid = typid;
00707 result->attDescs[i].typlen = typlen;
00708 result->attDescs[i].atttypmod = atttypmod;
00709 }
00710
00711
00712 conn->result = result;
00713
00714
00715 conn->inStart = conn->inCursor;
00716
00717
00718
00719
00720
00721
00722
00723 return 0;
00724
00725 advance_and_error:
00726
00727
00728
00729
00730
00731
00732 conn->inStart = conn->inEnd;
00733
00734
00735
00736
00737
00738 pqClearAsyncResult(conn);
00739
00740
00741
00742
00743
00744
00745
00746 if (!errmsg)
00747 errmsg = libpq_gettext("out of memory for query result");
00748
00749 printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
00750
00751
00752
00753
00754
00755 conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
00756 conn->asyncStatus = PGASYNC_READY;
00757
00758 EOFexit:
00759 if (result && result != conn->result)
00760 PQclear(result);
00761 return EOF;
00762 }
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774 static int
00775 getAnotherTuple(PGconn *conn, bool binary)
00776 {
00777 PGresult *result = conn->result;
00778 int nfields = result->numAttributes;
00779 const char *errmsg;
00780 PGdataValue *rowbuf;
00781
00782
00783 char std_bitmap[64];
00784 char *bitmap = std_bitmap;
00785 int i;
00786 size_t nbytes;
00787 char bmap;
00788 int bitmap_index;
00789 int bitcnt;
00790 int vlen;
00791
00792
00793 rowbuf = conn->rowBuf;
00794 if (nfields > conn->rowBufLen)
00795 {
00796 rowbuf = (PGdataValue *) realloc(rowbuf,
00797 nfields * sizeof(PGdataValue));
00798 if (!rowbuf)
00799 {
00800 errmsg = NULL;
00801 goto advance_and_error;
00802 }
00803 conn->rowBuf = rowbuf;
00804 conn->rowBufLen = nfields;
00805 }
00806
00807
00808 result->binary = binary;
00809
00810
00811
00812
00813
00814 if (binary)
00815 {
00816 for (i = 0; i < nfields; i++)
00817 result->attDescs[i].format = 1;
00818 }
00819
00820
00821 nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
00822
00823 if (nbytes > sizeof(std_bitmap))
00824 {
00825 bitmap = (char *) malloc(nbytes);
00826 if (!bitmap)
00827 {
00828 errmsg = NULL;
00829 goto advance_and_error;
00830 }
00831 }
00832
00833 if (pqGetnchar(bitmap, nbytes, conn))
00834 goto EOFexit;
00835
00836
00837 bitmap_index = 0;
00838 bmap = bitmap[bitmap_index];
00839 bitcnt = 0;
00840
00841 for (i = 0; i < nfields; i++)
00842 {
00843
00844 if (!(bmap & 0200))
00845 vlen = NULL_LEN;
00846 else if (pqGetInt(&vlen, 4, conn))
00847 goto EOFexit;
00848 else
00849 {
00850 if (!binary)
00851 vlen = vlen - 4;
00852 if (vlen < 0)
00853 vlen = 0;
00854 }
00855 rowbuf[i].len = vlen;
00856
00857
00858
00859
00860
00861
00862 rowbuf[i].value = conn->inBuffer + conn->inCursor;
00863
00864
00865 if (vlen > 0)
00866 {
00867 if (pqSkipnchar(vlen, conn))
00868 goto EOFexit;
00869 }
00870
00871
00872 bitcnt++;
00873 if (bitcnt == BITS_PER_BYTE)
00874 {
00875 bitmap_index++;
00876 bmap = bitmap[bitmap_index];
00877 bitcnt = 0;
00878 }
00879 else
00880 bmap <<= 1;
00881 }
00882
00883
00884 if (bitmap != std_bitmap)
00885 free(bitmap);
00886 bitmap = NULL;
00887
00888
00889 conn->inStart = conn->inCursor;
00890
00891
00892 errmsg = NULL;
00893 if (pqRowProcessor(conn, &errmsg))
00894 return 0;
00895
00896 goto set_error_result;
00897
00898 advance_and_error:
00899
00900
00901
00902
00903
00904
00905 conn->inStart = conn->inEnd;
00906
00907 set_error_result:
00908
00909
00910
00911
00912
00913 pqClearAsyncResult(conn);
00914
00915
00916
00917
00918
00919
00920
00921 if (!errmsg)
00922 errmsg = libpq_gettext("out of memory for query result");
00923
00924 printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
00925
00926
00927
00928
00929
00930 conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
00931 conn->asyncStatus = PGASYNC_READY;
00932
00933 EOFexit:
00934 if (bitmap != NULL && bitmap != std_bitmap)
00935 free(bitmap);
00936 return EOF;
00937 }
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947 static int
00948 pqGetErrorNotice2(PGconn *conn, bool isError)
00949 {
00950 PGresult *res = NULL;
00951 PQExpBufferData workBuf;
00952 char *startp;
00953 char *splitp;
00954
00955
00956
00957
00958
00959
00960 initPQExpBuffer(&workBuf);
00961 if (pqGets(&workBuf, conn))
00962 goto failure;
00963
00964
00965
00966
00967
00968
00969 res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
00970 if (!res)
00971 goto failure;
00972 res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
00973 res->errMsg = pqResultStrdup(res, workBuf.data);
00974 if (!res->errMsg)
00975 goto failure;
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 while (workBuf.len > 0 && workBuf.data[workBuf.len - 1] == '\n')
00986 workBuf.data[--workBuf.len] = '\0';
00987 splitp = strstr(workBuf.data, ": ");
00988 if (splitp)
00989 {
00990
00991 *splitp = '\0';
00992 pqSaveMessageField(res, PG_DIAG_SEVERITY, workBuf.data);
00993 startp = splitp + 3;
00994 }
00995 else
00996 {
00997
00998 startp = workBuf.data;
00999 }
01000 splitp = strchr(startp, '\n');
01001 if (splitp)
01002 {
01003
01004 *splitp++ = '\0';
01005 pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);
01006
01007 while (*splitp && isspace((unsigned char) *splitp))
01008 splitp++;
01009 pqSaveMessageField(res, PG_DIAG_MESSAGE_DETAIL, splitp);
01010 }
01011 else
01012 {
01013
01014 pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);
01015 }
01016
01017
01018
01019
01020
01021
01022 if (isError)
01023 {
01024 pqClearAsyncResult(conn);
01025 conn->result = res;
01026 resetPQExpBuffer(&conn->errorMessage);
01027 appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
01028 if (conn->xactStatus == PQTRANS_INTRANS)
01029 conn->xactStatus = PQTRANS_INERROR;
01030 }
01031 else
01032 {
01033 if (res->noticeHooks.noticeRec != NULL)
01034 (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
01035 PQclear(res);
01036 }
01037
01038 termPQExpBuffer(&workBuf);
01039 return 0;
01040
01041 failure:
01042 if (res)
01043 PQclear(res);
01044 termPQExpBuffer(&workBuf);
01045 return EOF;
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060 static void
01061 checkXactStatus(PGconn *conn, const char *cmdTag)
01062 {
01063 if (strcmp(cmdTag, "BEGIN") == 0)
01064 conn->xactStatus = PQTRANS_INTRANS;
01065 else if (strcmp(cmdTag, "COMMIT") == 0)
01066 conn->xactStatus = PQTRANS_IDLE;
01067 else if (strcmp(cmdTag, "ROLLBACK") == 0)
01068 conn->xactStatus = PQTRANS_IDLE;
01069 else if (strcmp(cmdTag, "START TRANSACTION") == 0)
01070 conn->xactStatus = PQTRANS_INTRANS;
01071
01072
01073
01074
01075
01076
01077 else if (strcmp(cmdTag, "*ABORT STATE*") == 0)
01078 conn->xactStatus = PQTRANS_INERROR;
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088 static int
01089 getNotify(PGconn *conn)
01090 {
01091 int be_pid;
01092 int nmlen;
01093 PGnotify *newNotify;
01094
01095 if (pqGetInt(&be_pid, 4, conn))
01096 return EOF;
01097 if (pqGets(&conn->workBuffer, conn))
01098 return EOF;
01099
01100
01101
01102
01103
01104
01105 nmlen = strlen(conn->workBuffer.data);
01106 newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);
01107 if (newNotify)
01108 {
01109 newNotify->relname = (char *) newNotify + sizeof(PGnotify);
01110 strcpy(newNotify->relname, conn->workBuffer.data);
01111
01112 newNotify->extra = newNotify->relname + nmlen;
01113 newNotify->be_pid = be_pid;
01114 newNotify->next = NULL;
01115 if (conn->notifyTail)
01116 conn->notifyTail->next = newNotify;
01117 else
01118 conn->notifyHead = newNotify;
01119 conn->notifyTail = newNotify;
01120 }
01121
01122 return 0;
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135 int
01136 pqGetCopyData2(PGconn *conn, char **buffer, int async)
01137 {
01138 bool found;
01139 int msgLength;
01140
01141 for (;;)
01142 {
01143
01144
01145
01146 conn->inCursor = conn->inStart;
01147 found = false;
01148 while (conn->inCursor < conn->inEnd)
01149 {
01150 char c = conn->inBuffer[conn->inCursor++];
01151
01152 if (c == '\n')
01153 {
01154 found = true;
01155 break;
01156 }
01157 }
01158 if (!found)
01159 goto nodata;
01160 msgLength = conn->inCursor - conn->inStart;
01161
01162
01163
01164
01165
01166 if (msgLength == 3 &&
01167 strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0)
01168 {
01169 conn->inStart = conn->inCursor;
01170 conn->asyncStatus = PGASYNC_BUSY;
01171 return -1;
01172 }
01173
01174
01175
01176
01177 *buffer = (char *) malloc(msgLength + 1);
01178 if (*buffer == NULL)
01179 {
01180 printfPQExpBuffer(&conn->errorMessage,
01181 libpq_gettext("out of memory\n"));
01182 return -2;
01183 }
01184 memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength);
01185 (*buffer)[msgLength] = '\0';
01186
01187
01188 conn->inStart = conn->inCursor;
01189
01190 return msgLength;
01191
01192 nodata:
01193
01194 if (async)
01195 return 0;
01196
01197 if (pqWait(TRUE, FALSE, conn) ||
01198 pqReadData(conn) < 0)
01199 return -2;
01200 }
01201 }
01202
01203
01204
01205
01206
01207
01208
01209 int
01210 pqGetline2(PGconn *conn, char *s, int maxlen)
01211 {
01212 int result = 1;
01213
01214 if (conn->sock < 0 ||
01215 conn->asyncStatus != PGASYNC_COPY_OUT)
01216 {
01217 *s = '\0';
01218 return EOF;
01219 }
01220
01221
01222
01223
01224
01225 while (maxlen > 1)
01226 {
01227 if (conn->inStart < conn->inEnd)
01228 {
01229 char c = conn->inBuffer[conn->inStart++];
01230
01231 if (c == '\n')
01232 {
01233 result = 0;
01234 break;
01235 }
01236 *s++ = c;
01237 maxlen--;
01238 }
01239 else
01240 {
01241
01242 if (pqWait(TRUE, FALSE, conn) ||
01243 pqReadData(conn) < 0)
01244 {
01245 result = EOF;
01246 break;
01247 }
01248 }
01249 }
01250 *s = '\0';
01251
01252 return result;
01253 }
01254
01255
01256
01257
01258
01259
01260 int
01261 pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize)
01262 {
01263 int avail;
01264
01265 if (conn->asyncStatus != PGASYNC_COPY_OUT)
01266 return -1;
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 conn->inCursor = conn->inStart;
01277
01278 avail = bufsize;
01279 while (avail > 0 && conn->inCursor < conn->inEnd)
01280 {
01281 char c = conn->inBuffer[conn->inCursor++];
01282
01283 *buffer++ = c;
01284 --avail;
01285 if (c == '\n')
01286 {
01287
01288 conn->inStart = conn->inCursor;
01289
01290 if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.')
01291 return -1;
01292
01293 return bufsize - avail;
01294 }
01295 }
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305 if (avail == 0 && bufsize > 3)
01306 {
01307 conn->inStart = conn->inCursor - 3;
01308 return bufsize - 3;
01309 }
01310 return 0;
01311 }
01312
01313
01314
01315
01316
01317
01318 int
01319 pqEndcopy2(PGconn *conn)
01320 {
01321 PGresult *result;
01322
01323 if (conn->asyncStatus != PGASYNC_COPY_IN &&
01324 conn->asyncStatus != PGASYNC_COPY_OUT)
01325 {
01326 printfPQExpBuffer(&conn->errorMessage,
01327 libpq_gettext("no COPY in progress\n"));
01328 return 1;
01329 }
01330
01331
01332
01333
01334
01335 if (pqFlush(conn) && pqIsnonblocking(conn))
01336 return 1;
01337
01338
01339 if (pqIsnonblocking(conn) && PQisBusy(conn))
01340 return 1;
01341
01342
01343 conn->asyncStatus = PGASYNC_BUSY;
01344 resetPQExpBuffer(&conn->errorMessage);
01345
01346
01347 result = PQgetResult(conn);
01348
01349
01350 if (result && result->resultStatus == PGRES_COMMAND_OK)
01351 {
01352 PQclear(result);
01353 return 0;
01354 }
01355
01356
01357
01358
01359
01360
01361
01362
01363 if (conn->errorMessage.len > 0)
01364 {
01365
01366 char svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
01367
01368 if (svLast == '\n')
01369 conn->errorMessage.data[conn->errorMessage.len - 1] = '\0';
01370 pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data);
01371 conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
01372 }
01373
01374 PQclear(result);
01375
01376
01377
01378
01379
01380
01381 pqInternalNotice(&conn->noticeHooks,
01382 "lost synchronization with server, resetting connection");
01383
01384
01385
01386
01387
01388
01389 if (pqIsnonblocking(conn))
01390 PQresetStart(conn);
01391 else
01392 PQreset(conn);
01393
01394 return 1;
01395 }
01396
01397
01398
01399
01400
01401
01402
01403 PGresult *
01404 pqFunctionCall2(PGconn *conn, Oid fnid,
01405 int *result_buf, int *actual_result_len,
01406 int result_is_int,
01407 const PQArgBlock *args, int nargs)
01408 {
01409 bool needInput = false;
01410 ExecStatusType status = PGRES_FATAL_ERROR;
01411 char id;
01412 int i;
01413
01414
01415
01416 if (pqPutMsgStart('F', false, conn) < 0 ||
01417 pqPuts(" ", conn) < 0 ||
01418 pqPutInt(fnid, 4, conn) != 0 ||
01419 pqPutInt(nargs, 4, conn) != 0)
01420 {
01421 pqHandleSendFailure(conn);
01422 return NULL;
01423 }
01424
01425 for (i = 0; i < nargs; ++i)
01426 {
01427 if (pqPutInt(args[i].len, 4, conn))
01428 {
01429 pqHandleSendFailure(conn);
01430 return NULL;
01431 }
01432
01433 if (args[i].isint)
01434 {
01435 if (pqPutInt(args[i].u.integer, 4, conn))
01436 {
01437 pqHandleSendFailure(conn);
01438 return NULL;
01439 }
01440 }
01441 else
01442 {
01443 if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn))
01444 {
01445 pqHandleSendFailure(conn);
01446 return NULL;
01447 }
01448 }
01449 }
01450
01451 if (pqPutMsgEnd(conn) < 0 ||
01452 pqFlush(conn))
01453 {
01454 pqHandleSendFailure(conn);
01455 return NULL;
01456 }
01457
01458 for (;;)
01459 {
01460 if (needInput)
01461 {
01462
01463 if (pqWait(TRUE, FALSE, conn) ||
01464 pqReadData(conn) < 0)
01465 break;
01466 }
01467
01468
01469
01470
01471 conn->inCursor = conn->inStart;
01472 needInput = true;
01473
01474 if (pqGetc(&id, conn))
01475 continue;
01476
01477
01478
01479
01480
01481
01482 switch (id)
01483 {
01484 case 'V':
01485 if (pqGetc(&id, conn))
01486 continue;
01487 if (id == 'G')
01488 {
01489
01490 if (pqGetInt(actual_result_len, 4, conn))
01491 continue;
01492 if (result_is_int)
01493 {
01494 if (pqGetInt(result_buf, 4, conn))
01495 continue;
01496 }
01497 else
01498 {
01499 if (pqGetnchar((char *) result_buf,
01500 *actual_result_len,
01501 conn))
01502 continue;
01503 }
01504 if (pqGetc(&id, conn))
01505 continue;
01506 }
01507 if (id == '0')
01508 {
01509
01510 status = PGRES_COMMAND_OK;
01511 }
01512 else
01513 {
01514
01515 printfPQExpBuffer(&conn->errorMessage,
01516 libpq_gettext("protocol error: id=0x%x\n"),
01517 id);
01518 pqSaveErrorResult(conn);
01519 conn->inStart = conn->inCursor;
01520 return pqPrepareAsyncResult(conn);
01521 }
01522 break;
01523 case 'E':
01524 if (pqGetErrorNotice2(conn, true))
01525 continue;
01526 status = PGRES_FATAL_ERROR;
01527 break;
01528 case 'A':
01529
01530 if (getNotify(conn))
01531 continue;
01532 break;
01533 case 'N':
01534
01535 if (pqGetErrorNotice2(conn, false))
01536 continue;
01537 break;
01538 case 'Z':
01539
01540 conn->inStart = conn->inCursor;
01541
01542 if (conn->result)
01543 return pqPrepareAsyncResult(conn);
01544 return PQmakeEmptyPGresult(conn, status);
01545 default:
01546
01547 printfPQExpBuffer(&conn->errorMessage,
01548 libpq_gettext("protocol error: id=0x%x\n"),
01549 id);
01550 pqSaveErrorResult(conn);
01551 conn->inStart = conn->inCursor;
01552 return pqPrepareAsyncResult(conn);
01553 }
01554
01555 conn->inStart = conn->inCursor;
01556 needInput = false;
01557 }
01558
01559
01560
01561
01562
01563
01564 pqSaveErrorResult(conn);
01565 return pqPrepareAsyncResult(conn);
01566 }
01567
01568
01569
01570
01571
01572
01573
01574 char *
01575 pqBuildStartupPacket2(PGconn *conn, int *packetlen,
01576 const PQEnvironmentOption *options)
01577 {
01578 StartupPacket *startpacket;
01579
01580 *packetlen = sizeof(StartupPacket);
01581 startpacket = (StartupPacket *) malloc(sizeof(StartupPacket));
01582 if (!startpacket)
01583 return NULL;
01584
01585 MemSet(startpacket, 0, sizeof(StartupPacket));
01586
01587 startpacket->protoVersion = htonl(conn->pversion);
01588
01589 strncpy(startpacket->user, conn->pguser, SM_USER);
01590 strncpy(startpacket->database, conn->dbName, SM_DATABASE);
01591 strncpy(startpacket->tty, conn->pgtty, SM_TTY);
01592
01593 if (conn->pgoptions)
01594 strncpy(startpacket->options, conn->pgoptions, SM_OPTIONS);
01595
01596 return (char *) startpacket;
01597 }