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 #include "mb/pg_wchar.h"
00024
00025 #ifdef WIN32
00026 #include "win32.h"
00027 #else
00028 #include <unistd.h>
00029 #include <netinet/in.h>
00030 #ifdef HAVE_NETINET_TCP_H
00031 #include <netinet/tcp.h>
00032 #endif
00033 #include <arpa/inet.h>
00034 #endif
00035
00036
00037
00038
00039
00040
00041 #define VALID_LONG_MESSAGE_TYPE(id) \
00042 ((id) == 'T' || (id) == 'D' || (id) == 'd' || (id) == 'V' || \
00043 (id) == 'E' || (id) == 'N' || (id) == 'A')
00044
00045
00046 static void handleSyncLoss(PGconn *conn, char id, int msgLength);
00047 static int getRowDescriptions(PGconn *conn, int msgLength);
00048 static int getParamDescriptions(PGconn *conn);
00049 static int getAnotherTuple(PGconn *conn, int msgLength);
00050 static int getParameterStatus(PGconn *conn);
00051 static int getNotify(PGconn *conn);
00052 static int getCopyStart(PGconn *conn, ExecStatusType copytype);
00053 static int getReadyForQuery(PGconn *conn);
00054 static void reportErrorPosition(PQExpBuffer msg, const char *query,
00055 int loc, int encoding);
00056 static int build_startup_packet(const PGconn *conn, char *packet,
00057 const PQEnvironmentOption *options);
00058
00059
00060
00061
00062
00063
00064
00065 void
00066 pqParseInput3(PGconn *conn)
00067 {
00068 char id;
00069 int msgLength;
00070 int avail;
00071
00072
00073
00074
00075 for (;;)
00076 {
00077
00078
00079
00080
00081 conn->inCursor = conn->inStart;
00082 if (pqGetc(&id, conn))
00083 return;
00084 if (pqGetInt(&msgLength, 4, conn))
00085 return;
00086
00087
00088
00089
00090
00091
00092 if (msgLength < 4)
00093 {
00094 handleSyncLoss(conn, id, msgLength);
00095 return;
00096 }
00097 if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
00098 {
00099 handleSyncLoss(conn, id, msgLength);
00100 return;
00101 }
00102
00103
00104
00105
00106 msgLength -= 4;
00107 avail = conn->inEnd - conn->inCursor;
00108 if (avail < msgLength)
00109 {
00110
00111
00112
00113
00114
00115
00116
00117
00118 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
00119 conn))
00120 {
00121
00122
00123
00124
00125
00126
00127 handleSyncLoss(conn, id, msgLength);
00128 }
00129 return;
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 if (id == 'A')
00149 {
00150 if (getNotify(conn))
00151 return;
00152 }
00153 else if (id == 'N')
00154 {
00155 if (pqGetErrorNotice3(conn, false))
00156 return;
00157 }
00158 else if (conn->asyncStatus != PGASYNC_BUSY)
00159 {
00160
00161 if (conn->asyncStatus != PGASYNC_IDLE)
00162 return;
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 if (id == 'E')
00174 {
00175 if (pqGetErrorNotice3(conn, false ))
00176 return;
00177 }
00178 else if (id == 'S')
00179 {
00180 if (getParameterStatus(conn))
00181 return;
00182 }
00183 else
00184 {
00185 pqInternalNotice(&conn->noticeHooks,
00186 "message type 0x%02x arrived from server while idle",
00187 id);
00188
00189 conn->inCursor += msgLength;
00190 }
00191 }
00192 else
00193 {
00194
00195
00196
00197 switch (id)
00198 {
00199 case 'C':
00200 if (pqGets(&conn->workBuffer, conn))
00201 return;
00202 if (conn->result == NULL)
00203 {
00204 conn->result = PQmakeEmptyPGresult(conn,
00205 PGRES_COMMAND_OK);
00206 if (!conn->result)
00207 return;
00208 }
00209 strncpy(conn->result->cmdStatus, conn->workBuffer.data,
00210 CMDSTATUS_LEN);
00211 conn->asyncStatus = PGASYNC_READY;
00212 break;
00213 case 'E':
00214 if (pqGetErrorNotice3(conn, true))
00215 return;
00216 conn->asyncStatus = PGASYNC_READY;
00217 break;
00218 case 'Z':
00219 if (getReadyForQuery(conn))
00220 return;
00221 conn->asyncStatus = PGASYNC_IDLE;
00222 break;
00223 case 'I':
00224 if (conn->result == NULL)
00225 {
00226 conn->result = PQmakeEmptyPGresult(conn,
00227 PGRES_EMPTY_QUERY);
00228 if (!conn->result)
00229 return;
00230 }
00231 conn->asyncStatus = PGASYNC_READY;
00232 break;
00233 case '1':
00234
00235 if (conn->queryclass == PGQUERY_PREPARE)
00236 {
00237 if (conn->result == NULL)
00238 {
00239 conn->result = PQmakeEmptyPGresult(conn,
00240 PGRES_COMMAND_OK);
00241 if (!conn->result)
00242 return;
00243 }
00244 conn->asyncStatus = PGASYNC_READY;
00245 }
00246 break;
00247 case '2':
00248 case '3':
00249
00250 break;
00251 case 'S':
00252 if (getParameterStatus(conn))
00253 return;
00254 break;
00255 case 'K':
00256
00257
00258
00259
00260
00261
00262 if (pqGetInt(&(conn->be_pid), 4, conn))
00263 return;
00264 if (pqGetInt(&(conn->be_key), 4, conn))
00265 return;
00266 break;
00267 case 'T':
00268 if (conn->result == NULL ||
00269 conn->queryclass == PGQUERY_DESCRIBE)
00270 {
00271
00272 if (getRowDescriptions(conn, msgLength))
00273 return;
00274
00275 continue;
00276 }
00277 else
00278 {
00279
00280
00281
00282
00283
00284
00285
00286 conn->asyncStatus = PGASYNC_READY;
00287 return;
00288 }
00289 break;
00290 case 'n':
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 if (conn->queryclass == PGQUERY_DESCRIBE)
00303 {
00304 if (conn->result == NULL)
00305 {
00306 conn->result = PQmakeEmptyPGresult(conn,
00307 PGRES_COMMAND_OK);
00308 if (!conn->result)
00309 return;
00310 }
00311 conn->asyncStatus = PGASYNC_READY;
00312 }
00313 break;
00314 case 't':
00315 if (getParamDescriptions(conn))
00316 return;
00317 break;
00318 case 'D':
00319 if (conn->result != NULL &&
00320 conn->result->resultStatus == PGRES_TUPLES_OK)
00321 {
00322
00323 if (getAnotherTuple(conn, msgLength))
00324 return;
00325
00326 continue;
00327 }
00328 else if (conn->result != NULL &&
00329 conn->result->resultStatus == PGRES_FATAL_ERROR)
00330 {
00331
00332
00333
00334
00335 conn->inCursor += msgLength;
00336 }
00337 else
00338 {
00339
00340 printfPQExpBuffer(&conn->errorMessage,
00341 libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n"));
00342 pqSaveErrorResult(conn);
00343
00344 conn->inCursor += msgLength;
00345 }
00346 break;
00347 case 'G':
00348 if (getCopyStart(conn, PGRES_COPY_IN))
00349 return;
00350 conn->asyncStatus = PGASYNC_COPY_IN;
00351 break;
00352 case 'H':
00353 if (getCopyStart(conn, PGRES_COPY_OUT))
00354 return;
00355 conn->asyncStatus = PGASYNC_COPY_OUT;
00356 conn->copy_already_done = 0;
00357 break;
00358 case 'W':
00359 if (getCopyStart(conn, PGRES_COPY_BOTH))
00360 return;
00361 conn->asyncStatus = PGASYNC_COPY_BOTH;
00362 conn->copy_already_done = 0;
00363 break;
00364 case 'd':
00365
00366
00367
00368
00369
00370
00371 conn->inCursor += msgLength;
00372 break;
00373 case 'c':
00374
00375
00376
00377
00378
00379
00380
00381 break;
00382 default:
00383 printfPQExpBuffer(&conn->errorMessage,
00384 libpq_gettext(
00385 "unexpected response from server; first received character was \"%c\"\n"),
00386 id);
00387
00388 pqSaveErrorResult(conn);
00389
00390 conn->asyncStatus = PGASYNC_READY;
00391
00392 conn->inCursor += msgLength;
00393 break;
00394 }
00395 }
00396
00397 if (conn->inCursor == conn->inStart + 5 + msgLength)
00398 {
00399
00400 conn->inStart = conn->inCursor;
00401 }
00402 else
00403 {
00404
00405 printfPQExpBuffer(&conn->errorMessage,
00406 libpq_gettext("message contents do not agree with length in message type \"%c\"\n"),
00407 id);
00408
00409 pqSaveErrorResult(conn);
00410 conn->asyncStatus = PGASYNC_READY;
00411
00412 conn->inStart += 5 + msgLength;
00413 }
00414 }
00415 }
00416
00417
00418
00419
00420
00421
00422 static void
00423 handleSyncLoss(PGconn *conn, char id, int msgLength)
00424 {
00425 printfPQExpBuffer(&conn->errorMessage,
00426 libpq_gettext(
00427 "lost synchronization with server: got message type \"%c\", length %d\n"),
00428 id, msgLength);
00429
00430 pqSaveErrorResult(conn);
00431 conn->asyncStatus = PGASYNC_READY;
00432
00433 pqDropConnection(conn);
00434 conn->status = CONNECTION_BAD;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 static int
00446 getRowDescriptions(PGconn *conn, int msgLength)
00447 {
00448 PGresult *result;
00449 int nfields;
00450 const char *errmsg;
00451 int i;
00452
00453
00454
00455
00456
00457
00458 if (conn->queryclass == PGQUERY_DESCRIBE)
00459 {
00460 if (conn->result)
00461 result = conn->result;
00462 else
00463 result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
00464 }
00465 else
00466 result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
00467 if (!result)
00468 {
00469 errmsg = NULL;
00470 goto advance_and_error;
00471 }
00472
00473
00474
00475 if (pqGetInt(&(result->numAttributes), 2, conn))
00476 {
00477
00478 errmsg = libpq_gettext("insufficient data in \"T\" message");
00479 goto advance_and_error;
00480 }
00481 nfields = result->numAttributes;
00482
00483
00484 if (nfields > 0)
00485 {
00486 result->attDescs = (PGresAttDesc *)
00487 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
00488 if (!result->attDescs)
00489 {
00490 errmsg = NULL;
00491 goto advance_and_error;
00492 }
00493 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
00494 }
00495
00496
00497 result->binary = (nfields > 0) ? 1 : 0;
00498
00499
00500 for (i = 0; i < nfields; i++)
00501 {
00502 int tableid;
00503 int columnid;
00504 int typid;
00505 int typlen;
00506 int atttypmod;
00507 int format;
00508
00509 if (pqGets(&conn->workBuffer, conn) ||
00510 pqGetInt(&tableid, 4, conn) ||
00511 pqGetInt(&columnid, 2, conn) ||
00512 pqGetInt(&typid, 4, conn) ||
00513 pqGetInt(&typlen, 2, conn) ||
00514 pqGetInt(&atttypmod, 4, conn) ||
00515 pqGetInt(&format, 2, conn))
00516 {
00517
00518 errmsg = libpq_gettext("insufficient data in \"T\" message");
00519 goto advance_and_error;
00520 }
00521
00522
00523
00524
00525
00526 columnid = (int) ((int16) columnid);
00527 typlen = (int) ((int16) typlen);
00528 format = (int) ((int16) format);
00529
00530 result->attDescs[i].name = pqResultStrdup(result,
00531 conn->workBuffer.data);
00532 if (!result->attDescs[i].name)
00533 {
00534 errmsg = NULL;
00535 goto advance_and_error;
00536 }
00537 result->attDescs[i].tableid = tableid;
00538 result->attDescs[i].columnid = columnid;
00539 result->attDescs[i].format = format;
00540 result->attDescs[i].typid = typid;
00541 result->attDescs[i].typlen = typlen;
00542 result->attDescs[i].atttypmod = atttypmod;
00543
00544 if (format != 1)
00545 result->binary = 0;
00546 }
00547
00548
00549 if (conn->inCursor != conn->inStart + 5 + msgLength)
00550 {
00551 errmsg = libpq_gettext("extraneous data in \"T\" message");
00552 goto advance_and_error;
00553 }
00554
00555
00556 conn->result = result;
00557
00558
00559 conn->inStart = conn->inCursor;
00560
00561
00562
00563
00564
00565 if (conn->queryclass == PGQUERY_DESCRIBE)
00566 {
00567 conn->asyncStatus = PGASYNC_READY;
00568 return 0;
00569 }
00570
00571
00572
00573
00574
00575
00576
00577 return 0;
00578
00579 advance_and_error:
00580
00581 if (result && result != conn->result)
00582 PQclear(result);
00583
00584
00585 conn->inStart += 5 + msgLength;
00586
00587
00588
00589
00590
00591 pqClearAsyncResult(conn);
00592
00593
00594
00595
00596
00597
00598
00599 if (!errmsg)
00600 errmsg = libpq_gettext("out of memory for query result");
00601
00602 printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
00603 pqSaveErrorResult(conn);
00604
00605
00606
00607
00608
00609
00610 return 0;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 static int
00623 getParamDescriptions(PGconn *conn)
00624 {
00625 PGresult *result;
00626 int nparams;
00627 int i;
00628
00629 result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
00630 if (!result)
00631 goto failure;
00632
00633
00634
00635 if (pqGetInt(&(result->numParameters), 2, conn))
00636 goto failure;
00637 nparams = result->numParameters;
00638
00639
00640 if (nparams > 0)
00641 {
00642 result->paramDescs = (PGresParamDesc *)
00643 pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE);
00644 if (!result->paramDescs)
00645 goto failure;
00646 MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
00647 }
00648
00649
00650 for (i = 0; i < nparams; i++)
00651 {
00652 int typid;
00653
00654 if (pqGetInt(&typid, 4, conn))
00655 goto failure;
00656 result->paramDescs[i].typid = typid;
00657 }
00658
00659
00660 conn->result = result;
00661 return 0;
00662
00663 failure:
00664 PQclear(result);
00665 return EOF;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674
00675 static int
00676 getAnotherTuple(PGconn *conn, int msgLength)
00677 {
00678 PGresult *result = conn->result;
00679 int nfields = result->numAttributes;
00680 const char *errmsg;
00681 PGdataValue *rowbuf;
00682 int tupnfields;
00683 int vlen;
00684 int i;
00685
00686
00687 if (pqGetInt(&tupnfields, 2, conn))
00688 {
00689
00690 errmsg = libpq_gettext("insufficient data in \"D\" message");
00691 goto advance_and_error;
00692 }
00693
00694 if (tupnfields != nfields)
00695 {
00696 errmsg = libpq_gettext("unexpected field count in \"D\" message");
00697 goto advance_and_error;
00698 }
00699
00700
00701 rowbuf = conn->rowBuf;
00702 if (nfields > conn->rowBufLen)
00703 {
00704 rowbuf = (PGdataValue *) realloc(rowbuf,
00705 nfields * sizeof(PGdataValue));
00706 if (!rowbuf)
00707 {
00708 errmsg = NULL;
00709 goto advance_and_error;
00710 }
00711 conn->rowBuf = rowbuf;
00712 conn->rowBufLen = nfields;
00713 }
00714
00715
00716 for (i = 0; i < nfields; i++)
00717 {
00718
00719 if (pqGetInt(&vlen, 4, conn))
00720 {
00721
00722 errmsg = libpq_gettext("insufficient data in \"D\" message");
00723 goto advance_and_error;
00724 }
00725 rowbuf[i].len = vlen;
00726
00727
00728
00729
00730
00731
00732 rowbuf[i].value = conn->inBuffer + conn->inCursor;
00733
00734
00735 if (vlen > 0)
00736 {
00737 if (pqSkipnchar(vlen, conn))
00738 {
00739
00740 errmsg = libpq_gettext("insufficient data in \"D\" message");
00741 goto advance_and_error;
00742 }
00743 }
00744 }
00745
00746
00747 if (conn->inCursor != conn->inStart + 5 + msgLength)
00748 {
00749 errmsg = libpq_gettext("extraneous data in \"D\" message");
00750 goto advance_and_error;
00751 }
00752
00753
00754 conn->inStart = conn->inCursor;
00755
00756
00757 errmsg = NULL;
00758 if (pqRowProcessor(conn, &errmsg))
00759 return 0;
00760
00761 goto set_error_result;
00762
00763 advance_and_error:
00764
00765 conn->inStart += 5 + msgLength;
00766
00767 set_error_result:
00768
00769
00770
00771
00772
00773 pqClearAsyncResult(conn);
00774
00775
00776
00777
00778
00779
00780
00781 if (!errmsg)
00782 errmsg = libpq_gettext("out of memory for query result");
00783
00784 printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
00785 pqSaveErrorResult(conn);
00786
00787
00788
00789
00790
00791
00792 return 0;
00793 }
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803 int
00804 pqGetErrorNotice3(PGconn *conn, bool isError)
00805 {
00806 PGresult *res = NULL;
00807 PQExpBufferData workBuf;
00808 char id;
00809 const char *val;
00810 const char *querytext = NULL;
00811 int querypos = 0;
00812
00813
00814
00815
00816
00817
00818
00819 initPQExpBuffer(&workBuf);
00820
00821
00822
00823
00824
00825
00826 res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
00827 if (!res)
00828 goto fail;
00829 res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
00830
00831
00832
00833
00834 for (;;)
00835 {
00836 if (pqGetc(&id, conn))
00837 goto fail;
00838 if (id == '\0')
00839 break;
00840 if (pqGets(&workBuf, conn))
00841 goto fail;
00842 pqSaveMessageField(res, id, workBuf.data);
00843 }
00844
00845
00846
00847
00848
00849
00850 resetPQExpBuffer(&workBuf);
00851 val = PQresultErrorField(res, PG_DIAG_SEVERITY);
00852 if (val)
00853 appendPQExpBuffer(&workBuf, "%s: ", val);
00854 val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
00855 if (val)
00856 {
00857 if (strlen(val) < sizeof(conn->last_sqlstate))
00858 strcpy(conn->last_sqlstate, val);
00859 if (conn->verbosity == PQERRORS_VERBOSE)
00860 appendPQExpBuffer(&workBuf, "%s: ", val);
00861 }
00862 val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
00863 if (val)
00864 appendPQExpBufferStr(&workBuf, val);
00865 val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION);
00866 if (val)
00867 {
00868 if (conn->verbosity != PQERRORS_TERSE && conn->last_query != NULL)
00869 {
00870
00871 querytext = conn->last_query;
00872 querypos = atoi(val);
00873 }
00874 else
00875 {
00876
00877
00878 appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
00879 val);
00880 }
00881 }
00882 else
00883 {
00884 val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION);
00885 if (val)
00886 {
00887 querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
00888 if (conn->verbosity != PQERRORS_TERSE && querytext != NULL)
00889 {
00890
00891 querypos = atoi(val);
00892 }
00893 else
00894 {
00895
00896
00897 appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
00898 val);
00899 }
00900 }
00901 }
00902 appendPQExpBufferChar(&workBuf, '\n');
00903 if (conn->verbosity != PQERRORS_TERSE)
00904 {
00905 if (querytext && querypos > 0)
00906 reportErrorPosition(&workBuf, querytext, querypos,
00907 conn->client_encoding);
00908 val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
00909 if (val)
00910 appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"), val);
00911 val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
00912 if (val)
00913 appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"), val);
00914 val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
00915 if (val)
00916 appendPQExpBuffer(&workBuf, libpq_gettext("QUERY: %s\n"), val);
00917 val = PQresultErrorField(res, PG_DIAG_CONTEXT);
00918 if (val)
00919 appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"), val);
00920 }
00921 if (conn->verbosity == PQERRORS_VERBOSE)
00922 {
00923 val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
00924 if (val)
00925 appendPQExpBuffer(&workBuf,
00926 libpq_gettext("SCHEMA NAME: %s\n"), val);
00927 val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
00928 if (val)
00929 appendPQExpBuffer(&workBuf,
00930 libpq_gettext("TABLE NAME: %s\n"), val);
00931 val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
00932 if (val)
00933 appendPQExpBuffer(&workBuf,
00934 libpq_gettext("COLUMN NAME: %s\n"), val);
00935 val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME);
00936 if (val)
00937 appendPQExpBuffer(&workBuf,
00938 libpq_gettext("DATATYPE NAME: %s\n"), val);
00939 val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME);
00940 if (val)
00941 appendPQExpBuffer(&workBuf,
00942 libpq_gettext("CONSTRAINT NAME: %s\n"), val);
00943 }
00944 if (conn->verbosity == PQERRORS_VERBOSE)
00945 {
00946 const char *valf;
00947 const char *vall;
00948
00949 valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE);
00950 vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE);
00951 val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION);
00952 if (val || valf || vall)
00953 {
00954 appendPQExpBufferStr(&workBuf, libpq_gettext("LOCATION: "));
00955 if (val)
00956 appendPQExpBuffer(&workBuf, libpq_gettext("%s, "), val);
00957 if (valf && vall)
00958 appendPQExpBuffer(&workBuf, libpq_gettext("%s:%s"),
00959 valf, vall);
00960 appendPQExpBufferChar(&workBuf, '\n');
00961 }
00962 }
00963
00964
00965
00966
00967 if (isError)
00968 {
00969 res->errMsg = pqResultStrdup(res, workBuf.data);
00970 if (!res->errMsg)
00971 goto fail;
00972 pqClearAsyncResult(conn);
00973 conn->result = res;
00974 appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
00975 }
00976 else
00977 {
00978
00979 res->errMsg = workBuf.data;
00980 if (res->noticeHooks.noticeRec != NULL)
00981 (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
00982 PQclear(res);
00983 }
00984
00985 termPQExpBuffer(&workBuf);
00986 return 0;
00987
00988 fail:
00989 PQclear(res);
00990 termPQExpBuffer(&workBuf);
00991 return EOF;
00992 }
00993
00994
00995
00996
00997
00998
00999
01000 static void
01001 reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
01002 {
01003 #define DISPLAY_SIZE 60
01004 #define MIN_RIGHT_CUT 10
01005
01006 char *wquery;
01007 int slen,
01008 cno,
01009 i,
01010 *qidx,
01011 *scridx,
01012 qoffset,
01013 scroffset,
01014 ibeg,
01015 iend,
01016 loc_line;
01017 bool mb_encoding,
01018 beg_trunc,
01019 end_trunc;
01020
01021
01022 loc--;
01023 if (loc < 0)
01024 return;
01025
01026
01027 wquery = strdup(query);
01028 if (wquery == NULL)
01029 return;
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 slen = strlen(wquery) + 1;
01041
01042 qidx = (int *) malloc(slen * sizeof(int));
01043 if (qidx == NULL)
01044 {
01045 free(wquery);
01046 return;
01047 }
01048 scridx = (int *) malloc(slen * sizeof(int));
01049 if (scridx == NULL)
01050 {
01051 free(qidx);
01052 free(wquery);
01053 return;
01054 }
01055
01056
01057 mb_encoding = (pg_encoding_max_length(encoding) != 1);
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068 qoffset = 0;
01069 scroffset = 0;
01070 loc_line = 1;
01071 ibeg = 0;
01072 iend = -1;
01073
01074 for (cno = 0; wquery[qoffset] != '\0'; cno++)
01075 {
01076 char ch = wquery[qoffset];
01077
01078 qidx[cno] = qoffset;
01079 scridx[cno] = scroffset;
01080
01081
01082
01083
01084
01085
01086 if (ch == '\t')
01087 wquery[qoffset] = ' ';
01088
01089
01090
01091
01092
01093 else if (ch == '\r' || ch == '\n')
01094 {
01095 if (cno < loc)
01096 {
01097 if (ch == '\r' ||
01098 cno == 0 ||
01099 wquery[qidx[cno - 1]] != '\r')
01100 loc_line++;
01101
01102 ibeg = cno + 1;
01103 }
01104 else
01105 {
01106
01107 iend = cno;
01108
01109 break;
01110 }
01111 }
01112
01113
01114 if (mb_encoding)
01115 {
01116 int w;
01117
01118 w = pg_encoding_dsplen(encoding, &wquery[qoffset]);
01119
01120 if (w <= 0)
01121 w = 1;
01122 scroffset += w;
01123 qoffset += pg_encoding_mblen(encoding, &wquery[qoffset]);
01124 }
01125 else
01126 {
01127
01128 scroffset++;
01129 qoffset++;
01130 }
01131 }
01132
01133 if (iend < 0)
01134 {
01135 iend = cno;
01136 qidx[iend] = qoffset;
01137 scridx[iend] = scroffset;
01138 }
01139
01140
01141 if (loc <= cno)
01142 {
01143
01144 beg_trunc = false;
01145 end_trunc = false;
01146 if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
01147 {
01148
01149
01150
01151
01152
01153 if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
01154 {
01155 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
01156 iend--;
01157 end_trunc = true;
01158 }
01159 else
01160 {
01161
01162 while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
01163 {
01164 iend--;
01165 end_trunc = true;
01166 }
01167
01168
01169 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
01170 {
01171 ibeg++;
01172 beg_trunc = true;
01173 }
01174 }
01175 }
01176
01177
01178 wquery[qidx[iend]] = '\0';
01179
01180
01181 i = msg->len;
01182 appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line);
01183 if (beg_trunc)
01184 appendPQExpBufferStr(msg, "...");
01185
01186
01187
01188
01189
01190 scroffset = 0;
01191 for (; i < msg->len; i += pg_encoding_mblen(encoding, &msg->data[i]))
01192 {
01193 int w = pg_encoding_dsplen(encoding, &msg->data[i]);
01194
01195 if (w <= 0)
01196 w = 1;
01197 scroffset += w;
01198 }
01199
01200
01201 appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]);
01202 if (end_trunc)
01203 appendPQExpBufferStr(msg, "...");
01204 appendPQExpBufferChar(msg, '\n');
01205
01206
01207 scroffset += scridx[loc] - scridx[ibeg];
01208 for (i = 0; i < scroffset; i++)
01209 appendPQExpBufferChar(msg, ' ');
01210 appendPQExpBufferChar(msg, '^');
01211 appendPQExpBufferChar(msg, '\n');
01212 }
01213
01214
01215 free(scridx);
01216 free(qidx);
01217 free(wquery);
01218 }
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228 static int
01229 getParameterStatus(PGconn *conn)
01230 {
01231 PQExpBufferData valueBuf;
01232
01233
01234 if (pqGets(&conn->workBuffer, conn))
01235 return EOF;
01236
01237 initPQExpBuffer(&valueBuf);
01238 if (pqGets(&valueBuf, conn))
01239 {
01240 termPQExpBuffer(&valueBuf);
01241 return EOF;
01242 }
01243
01244 pqSaveParameterStatus(conn, conn->workBuffer.data, valueBuf.data);
01245 termPQExpBuffer(&valueBuf);
01246 return 0;
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257 static int
01258 getNotify(PGconn *conn)
01259 {
01260 int be_pid;
01261 char *svname;
01262 int nmlen;
01263 int extralen;
01264 PGnotify *newNotify;
01265
01266 if (pqGetInt(&be_pid, 4, conn))
01267 return EOF;
01268 if (pqGets(&conn->workBuffer, conn))
01269 return EOF;
01270
01271 svname = strdup(conn->workBuffer.data);
01272 if (!svname)
01273 return EOF;
01274 if (pqGets(&conn->workBuffer, conn))
01275 {
01276 free(svname);
01277 return EOF;
01278 }
01279
01280
01281
01282
01283
01284
01285 nmlen = strlen(svname);
01286 extralen = strlen(conn->workBuffer.data);
01287 newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
01288 if (newNotify)
01289 {
01290 newNotify->relname = (char *) newNotify + sizeof(PGnotify);
01291 strcpy(newNotify->relname, svname);
01292 newNotify->extra = newNotify->relname + nmlen + 1;
01293 strcpy(newNotify->extra, conn->workBuffer.data);
01294 newNotify->be_pid = be_pid;
01295 newNotify->next = NULL;
01296 if (conn->notifyTail)
01297 conn->notifyTail->next = newNotify;
01298 else
01299 conn->notifyHead = newNotify;
01300 conn->notifyTail = newNotify;
01301 }
01302
01303 free(svname);
01304 return 0;
01305 }
01306
01307
01308
01309
01310
01311
01312
01313 static int
01314 getCopyStart(PGconn *conn, ExecStatusType copytype)
01315 {
01316 PGresult *result;
01317 int nfields;
01318 int i;
01319
01320 result = PQmakeEmptyPGresult(conn, copytype);
01321 if (!result)
01322 goto failure;
01323
01324 if (pqGetc(&conn->copy_is_binary, conn))
01325 goto failure;
01326 result->binary = conn->copy_is_binary;
01327
01328 if (pqGetInt(&(result->numAttributes), 2, conn))
01329 goto failure;
01330 nfields = result->numAttributes;
01331
01332
01333 if (nfields > 0)
01334 {
01335 result->attDescs = (PGresAttDesc *)
01336 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
01337 if (!result->attDescs)
01338 goto failure;
01339 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
01340 }
01341
01342 for (i = 0; i < nfields; i++)
01343 {
01344 int format;
01345
01346 if (pqGetInt(&format, 2, conn))
01347 goto failure;
01348
01349
01350
01351
01352
01353 format = (int) ((int16) format);
01354 result->attDescs[i].format = format;
01355 }
01356
01357
01358 conn->result = result;
01359 return 0;
01360
01361 failure:
01362 PQclear(result);
01363 return EOF;
01364 }
01365
01366
01367
01368
01369 static int
01370 getReadyForQuery(PGconn *conn)
01371 {
01372 char xact_status;
01373
01374 if (pqGetc(&xact_status, conn))
01375 return EOF;
01376 switch (xact_status)
01377 {
01378 case 'I':
01379 conn->xactStatus = PQTRANS_IDLE;
01380 break;
01381 case 'T':
01382 conn->xactStatus = PQTRANS_INTRANS;
01383 break;
01384 case 'E':
01385 conn->xactStatus = PQTRANS_INERROR;
01386 break;
01387 default:
01388 conn->xactStatus = PQTRANS_UNKNOWN;
01389 break;
01390 }
01391
01392 return 0;
01393 }
01394
01395
01396
01397
01398
01399
01400
01401 static int
01402 getCopyDataMessage(PGconn *conn)
01403 {
01404 char id;
01405 int msgLength;
01406 int avail;
01407
01408 for (;;)
01409 {
01410
01411
01412
01413
01414
01415 conn->inCursor = conn->inStart;
01416 if (pqGetc(&id, conn))
01417 return 0;
01418 if (pqGetInt(&msgLength, 4, conn))
01419 return 0;
01420 if (msgLength < 4)
01421 {
01422 handleSyncLoss(conn, id, msgLength);
01423 return -2;
01424 }
01425 avail = conn->inEnd - conn->inCursor;
01426 if (avail < msgLength - 4)
01427 {
01428
01429
01430
01431
01432 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4,
01433 conn))
01434 {
01435
01436
01437
01438
01439
01440
01441 handleSyncLoss(conn, id, msgLength);
01442 return -2;
01443 }
01444 return 0;
01445 }
01446
01447
01448
01449
01450
01451
01452
01453 switch (id)
01454 {
01455 case 'A':
01456 if (getNotify(conn))
01457 return 0;
01458 break;
01459 case 'N':
01460 if (pqGetErrorNotice3(conn, false))
01461 return 0;
01462 break;
01463 case 'S':
01464 if (getParameterStatus(conn))
01465 return 0;
01466 break;
01467 case 'd':
01468 return msgLength;
01469 case 'c':
01470
01471
01472
01473
01474
01475 if (conn->asyncStatus == PGASYNC_COPY_BOTH)
01476 conn->asyncStatus = PGASYNC_COPY_IN;
01477 else
01478 conn->asyncStatus = PGASYNC_BUSY;
01479 return -1;
01480 default:
01481
01482
01483
01484
01485 conn->asyncStatus = PGASYNC_BUSY;
01486 return -1;
01487 }
01488
01489
01490 conn->inStart = conn->inCursor;
01491 }
01492 }
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504 int
01505 pqGetCopyData3(PGconn *conn, char **buffer, int async)
01506 {
01507 int msgLength;
01508
01509 for (;;)
01510 {
01511
01512
01513
01514
01515
01516 msgLength = getCopyDataMessage(conn);
01517 if (msgLength < 0)
01518 return msgLength;
01519 if (msgLength == 0)
01520 {
01521
01522 if (async)
01523 return 0;
01524
01525 if (pqWait(TRUE, FALSE, conn) ||
01526 pqReadData(conn) < 0)
01527 return -2;
01528 continue;
01529 }
01530
01531
01532
01533
01534
01535 msgLength -= 4;
01536 if (msgLength > 0)
01537 {
01538 *buffer = (char *) malloc(msgLength + 1);
01539 if (*buffer == NULL)
01540 {
01541 printfPQExpBuffer(&conn->errorMessage,
01542 libpq_gettext("out of memory\n"));
01543 return -2;
01544 }
01545 memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength);
01546 (*buffer)[msgLength] = '\0';
01547
01548
01549 conn->inStart = conn->inCursor + msgLength;
01550
01551 return msgLength;
01552 }
01553
01554
01555 conn->inStart = conn->inCursor;
01556 }
01557 }
01558
01559
01560
01561
01562
01563
01564 int
01565 pqGetline3(PGconn *conn, char *s, int maxlen)
01566 {
01567 int status;
01568
01569 if (conn->sock < 0 ||
01570 (conn->asyncStatus != PGASYNC_COPY_OUT &&
01571 conn->asyncStatus != PGASYNC_COPY_BOTH) ||
01572 conn->copy_is_binary)
01573 {
01574 printfPQExpBuffer(&conn->errorMessage,
01575 libpq_gettext("PQgetline: not doing text COPY OUT\n"));
01576 *s = '\0';
01577 return EOF;
01578 }
01579
01580 while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0)
01581 {
01582
01583 if (pqWait(TRUE, FALSE, conn) ||
01584 pqReadData(conn) < 0)
01585 {
01586 *s = '\0';
01587 return EOF;
01588 }
01589 }
01590
01591 if (status < 0)
01592 {
01593
01594 strcpy(s, "\\.");
01595 return 0;
01596 }
01597
01598
01599 if (s[status - 1] == '\n')
01600 {
01601 s[status - 1] = '\0';
01602 return 0;
01603 }
01604 else
01605 {
01606 s[status] = '\0';
01607 return 1;
01608 }
01609 }
01610
01611
01612
01613
01614
01615
01616 int
01617 pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize)
01618 {
01619 int msgLength;
01620 int avail;
01621
01622 if (conn->asyncStatus != PGASYNC_COPY_OUT
01623 && conn->asyncStatus != PGASYNC_COPY_BOTH)
01624 return -1;
01625
01626
01627
01628
01629
01630
01631
01632 msgLength = getCopyDataMessage(conn);
01633 if (msgLength < 0)
01634 return -1;
01635 if (msgLength == 0)
01636 return 0;
01637
01638
01639
01640
01641
01642
01643
01644 conn->inCursor += conn->copy_already_done;
01645 avail = msgLength - 4 - conn->copy_already_done;
01646 if (avail <= bufsize)
01647 {
01648
01649 memcpy(buffer, &conn->inBuffer[conn->inCursor], avail);
01650
01651 conn->inStart = conn->inCursor + avail;
01652
01653 conn->copy_already_done = 0;
01654 return avail;
01655 }
01656 else
01657 {
01658
01659 memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize);
01660
01661 conn->copy_already_done += bufsize;
01662 return bufsize;
01663 }
01664 }
01665
01666
01667
01668
01669
01670
01671 int
01672 pqEndcopy3(PGconn *conn)
01673 {
01674 PGresult *result;
01675
01676 if (conn->asyncStatus != PGASYNC_COPY_IN &&
01677 conn->asyncStatus != PGASYNC_COPY_OUT &&
01678 conn->asyncStatus != PGASYNC_COPY_BOTH)
01679 {
01680 printfPQExpBuffer(&conn->errorMessage,
01681 libpq_gettext("no COPY in progress\n"));
01682 return 1;
01683 }
01684
01685
01686 if (conn->asyncStatus == PGASYNC_COPY_IN ||
01687 conn->asyncStatus == PGASYNC_COPY_BOTH)
01688 {
01689 if (pqPutMsgStart('c', false, conn) < 0 ||
01690 pqPutMsgEnd(conn) < 0)
01691 return 1;
01692
01693
01694
01695
01696
01697 if (conn->queryclass != PGQUERY_SIMPLE)
01698 {
01699 if (pqPutMsgStart('S', false, conn) < 0 ||
01700 pqPutMsgEnd(conn) < 0)
01701 return 1;
01702 }
01703 }
01704
01705
01706
01707
01708
01709 if (pqFlush(conn) && pqIsnonblocking(conn))
01710 return 1;
01711
01712
01713 conn->asyncStatus = PGASYNC_BUSY;
01714 resetPQExpBuffer(&conn->errorMessage);
01715
01716
01717
01718
01719
01720
01721
01722
01723 if (pqIsnonblocking(conn) && PQisBusy(conn))
01724 return 1;
01725
01726
01727 result = PQgetResult(conn);
01728
01729
01730 if (result && result->resultStatus == PGRES_COMMAND_OK)
01731 {
01732 PQclear(result);
01733 return 0;
01734 }
01735
01736
01737
01738
01739
01740
01741
01742
01743 if (conn->errorMessage.len > 0)
01744 {
01745
01746 char svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
01747
01748 if (svLast == '\n')
01749 conn->errorMessage.data[conn->errorMessage.len - 1] = '\0';
01750 pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data);
01751 conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
01752 }
01753
01754 PQclear(result);
01755
01756 return 1;
01757 }
01758
01759
01760
01761
01762
01763
01764
01765 PGresult *
01766 pqFunctionCall3(PGconn *conn, Oid fnid,
01767 int *result_buf, int *actual_result_len,
01768 int result_is_int,
01769 const PQArgBlock *args, int nargs)
01770 {
01771 bool needInput = false;
01772 ExecStatusType status = PGRES_FATAL_ERROR;
01773 char id;
01774 int msgLength;
01775 int avail;
01776 int i;
01777
01778
01779
01780 if (pqPutMsgStart('F', false, conn) < 0 ||
01781 pqPutInt(fnid, 4, conn) < 0 ||
01782 pqPutInt(1, 2, conn) < 0 ||
01783 pqPutInt(1, 2, conn) < 0 ||
01784 pqPutInt(nargs, 2, conn) < 0)
01785 {
01786 pqHandleSendFailure(conn);
01787 return NULL;
01788 }
01789
01790 for (i = 0; i < nargs; ++i)
01791 {
01792 if (pqPutInt(args[i].len, 4, conn))
01793 {
01794 pqHandleSendFailure(conn);
01795 return NULL;
01796 }
01797 if (args[i].len == -1)
01798 continue;
01799
01800 if (args[i].isint)
01801 {
01802 if (pqPutInt(args[i].u.integer, args[i].len, conn))
01803 {
01804 pqHandleSendFailure(conn);
01805 return NULL;
01806 }
01807 }
01808 else
01809 {
01810 if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn))
01811 {
01812 pqHandleSendFailure(conn);
01813 return NULL;
01814 }
01815 }
01816 }
01817
01818 if (pqPutInt(1, 2, conn) < 0)
01819 {
01820 pqHandleSendFailure(conn);
01821 return NULL;
01822 }
01823
01824 if (pqPutMsgEnd(conn) < 0 ||
01825 pqFlush(conn))
01826 {
01827 pqHandleSendFailure(conn);
01828 return NULL;
01829 }
01830
01831 for (;;)
01832 {
01833 if (needInput)
01834 {
01835
01836 if (pqWait(TRUE, FALSE, conn) ||
01837 pqReadData(conn) < 0)
01838 break;
01839 }
01840
01841
01842
01843
01844 needInput = true;
01845
01846 conn->inCursor = conn->inStart;
01847 if (pqGetc(&id, conn))
01848 continue;
01849 if (pqGetInt(&msgLength, 4, conn))
01850 continue;
01851
01852
01853
01854
01855
01856
01857 if (msgLength < 4)
01858 {
01859 handleSyncLoss(conn, id, msgLength);
01860 break;
01861 }
01862 if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
01863 {
01864 handleSyncLoss(conn, id, msgLength);
01865 break;
01866 }
01867
01868
01869
01870
01871 msgLength -= 4;
01872 avail = conn->inEnd - conn->inCursor;
01873 if (avail < msgLength)
01874 {
01875
01876
01877
01878
01879 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
01880 conn))
01881 {
01882
01883
01884
01885
01886
01887
01888 handleSyncLoss(conn, id, msgLength);
01889 break;
01890 }
01891 continue;
01892 }
01893
01894
01895
01896
01897
01898
01899 switch (id)
01900 {
01901 case 'V':
01902 if (pqGetInt(actual_result_len, 4, conn))
01903 continue;
01904 if (*actual_result_len != -1)
01905 {
01906 if (result_is_int)
01907 {
01908 if (pqGetInt(result_buf, *actual_result_len, conn))
01909 continue;
01910 }
01911 else
01912 {
01913 if (pqGetnchar((char *) result_buf,
01914 *actual_result_len,
01915 conn))
01916 continue;
01917 }
01918 }
01919
01920 status = PGRES_COMMAND_OK;
01921 break;
01922 case 'E':
01923 if (pqGetErrorNotice3(conn, true))
01924 continue;
01925 status = PGRES_FATAL_ERROR;
01926 break;
01927 case 'A':
01928
01929 if (getNotify(conn))
01930 continue;
01931 break;
01932 case 'N':
01933
01934 if (pqGetErrorNotice3(conn, false))
01935 continue;
01936 break;
01937 case 'Z':
01938 if (getReadyForQuery(conn))
01939 continue;
01940
01941 conn->inStart += 5 + msgLength;
01942
01943 if (conn->result)
01944 return pqPrepareAsyncResult(conn);
01945 return PQmakeEmptyPGresult(conn, status);
01946 case 'S':
01947 if (getParameterStatus(conn))
01948 continue;
01949 break;
01950 default:
01951
01952 printfPQExpBuffer(&conn->errorMessage,
01953 libpq_gettext("protocol error: id=0x%x\n"),
01954 id);
01955 pqSaveErrorResult(conn);
01956
01957 conn->inStart += 5 + msgLength;
01958 return pqPrepareAsyncResult(conn);
01959 }
01960
01961
01962 conn->inStart += 5 + msgLength;
01963 needInput = false;
01964 }
01965
01966
01967
01968
01969
01970
01971 pqSaveErrorResult(conn);
01972 return pqPrepareAsyncResult(conn);
01973 }
01974
01975
01976
01977
01978
01979
01980
01981 char *
01982 pqBuildStartupPacket3(PGconn *conn, int *packetlen,
01983 const PQEnvironmentOption *options)
01984 {
01985 char *startpacket;
01986
01987 *packetlen = build_startup_packet(conn, NULL, options);
01988 startpacket = (char *) malloc(*packetlen);
01989 if (!startpacket)
01990 return NULL;
01991 *packetlen = build_startup_packet(conn, startpacket, options);
01992 return startpacket;
01993 }
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004 static int
02005 build_startup_packet(const PGconn *conn, char *packet,
02006 const PQEnvironmentOption *options)
02007 {
02008 int packet_len = 0;
02009 const PQEnvironmentOption *next_eo;
02010 const char *val;
02011
02012
02013 if (packet)
02014 {
02015 ProtocolVersion pv = htonl(conn->pversion);
02016
02017 memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion));
02018 }
02019 packet_len += sizeof(ProtocolVersion);
02020
02021
02022
02023 #define ADD_STARTUP_OPTION(optname, optval) \
02024 do { \
02025 if (packet) \
02026 strcpy(packet + packet_len, optname); \
02027 packet_len += strlen(optname) + 1; \
02028 if (packet) \
02029 strcpy(packet + packet_len, optval); \
02030 packet_len += strlen(optval) + 1; \
02031 } while(0)
02032
02033 if (conn->pguser && conn->pguser[0])
02034 ADD_STARTUP_OPTION("user", conn->pguser);
02035 if (conn->dbName && conn->dbName[0])
02036 ADD_STARTUP_OPTION("database", conn->dbName);
02037 if (conn->replication && conn->replication[0])
02038 ADD_STARTUP_OPTION("replication", conn->replication);
02039 if (conn->pgoptions && conn->pgoptions[0])
02040 ADD_STARTUP_OPTION("options", conn->pgoptions);
02041 if (conn->send_appname)
02042 {
02043
02044 val = conn->appname ? conn->appname : conn->fbappname;
02045 if (val && val[0])
02046 ADD_STARTUP_OPTION("application_name", val);
02047 }
02048
02049 if (conn->client_encoding_initial && conn->client_encoding_initial[0])
02050 ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);
02051
02052
02053 for (next_eo = options; next_eo->envName; next_eo++)
02054 {
02055 if ((val = getenv(next_eo->envName)) != NULL)
02056 {
02057 if (pg_strcasecmp(val, "default") != 0)
02058 ADD_STARTUP_OPTION(next_eo->pgName, val);
02059 }
02060 }
02061
02062
02063 if (packet)
02064 packet[packet_len] = '\0';
02065 packet_len++;
02066
02067 return packet_len;
02068 }