Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6428074

Browse files
committed
Update libpq to store an error message in PGresult, per pgsq-interfaces discussion of 21-Sep.
1 parent502769d commit6428074

File tree

6 files changed

+205
-79
lines changed

6 files changed

+205
-79
lines changed

‎src/interfaces/libpq/fe-connect.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.83 1998/09/20 04:51:10 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.84 1998/10/01 01:40:19 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -822,8 +822,8 @@ PQsetenv(PGconn *conn)
822822
sprintf(envbuf,"%s=%s",envname,encoding);
823823
putenv(envbuf);
824824
}
825-
PQclear(rtn);
826825
}
826+
PQclear(rtn);
827827
if (!encoding)
828828
{/* this should not happen */
829829
sprintf(envbuf,"%s=%s",envname,pg_encoding_to_char(MULTIBYTE));

‎src/interfaces/libpq/fe-exec.c

Lines changed: 132 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.68 1998/09/10 15:18:02 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.69 1998/10/01 01:40:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -50,7 +50,7 @@ const char *const pgresStatus[] = {
5050

5151

5252
staticvoidfreeTuple(PGresAttValue*tuple,intnumAttributes);
53-
staticvoidaddTuple(PGresult*res,PGresAttValue*tup);
53+
staticintaddTuple(PGresult*res,PGresAttValue*tup);
5454
staticvoidparseInput(PGconn*conn);
5555
staticintgetRowDescriptions(PGconn*conn);
5656
staticintgetAnotherTuple(PGconn*conn,intbinary);
@@ -60,7 +60,9 @@ static intgetNotice(PGconn *conn);
6060

6161
/*
6262
* PQmakeEmptyPGresult
63-
* returns a newly allocated, initialized PGresult with given status
63+
* returns a newly allocated, initialized PGresult with given status.
64+
* If conn is not NULL and status indicates an error, the conn's
65+
* errorMessage is copied.
6466
*
6567
* Note this is exported --- you wouldn't think an application would need
6668
* to build its own PGresults, but this has proven useful in both libpgtcl
@@ -74,7 +76,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
7476

7577
result= (PGresult*)malloc(sizeof(PGresult));
7678

77-
result->conn=conn;
79+
result->conn=conn;/* should go away eventually */
7880
result->ntups=0;
7981
result->numAttributes=0;
8082
result->attDescs=NULL;
@@ -83,13 +85,45 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
8385
result->resultStatus=status;
8486
result->cmdStatus[0]='\0';
8587
result->binary=0;
88+
result->errMsg=NULL;
89+
if (conn)/* consider copying conn's errorMessage */
90+
{
91+
switch (status)
92+
{
93+
casePGRES_EMPTY_QUERY:
94+
casePGRES_COMMAND_OK:
95+
casePGRES_TUPLES_OK:
96+
casePGRES_COPY_OUT:
97+
casePGRES_COPY_IN:
98+
/* non-error cases */
99+
break;
100+
default:
101+
pqSetResultError(result,conn->errorMessage);
102+
break;
103+
}
104+
}
86105
returnresult;
87106
}
88107

108+
/*
109+
* pqSetResultError -
110+
*assign a new error message to a PGresult
111+
*/
112+
void
113+
pqSetResultError(PGresult*res,constchar*msg)
114+
{
115+
if (!res)
116+
return;
117+
if (res->errMsg)
118+
free(res->errMsg);
119+
res->errMsg=NULL;
120+
if (msg&&*msg)
121+
res->errMsg=strdup(msg);
122+
}
123+
89124
/*
90125
* PQclear -
91126
* free's the memory associated with a PGresult
92-
*
93127
*/
94128
void
95129
PQclear(PGresult*res)
@@ -118,6 +152,10 @@ PQclear(PGresult *res)
118152
free(res->attDescs);
119153
}
120154

155+
/* free the error text */
156+
if (res->errMsg)
157+
free(res->errMsg);
158+
121159
/* free the structure itself */
122160
free(res);
123161
}
@@ -164,27 +202,35 @@ pqClearAsyncResult(PGconn *conn)
164202
/*
165203
* addTuple
166204
* add a row to the PGresult structure, growing it if necessary
205+
* Returns TRUE if OK, FALSE if not enough memory to add the row
167206
*/
168-
staticvoid
207+
staticint
169208
addTuple(PGresult*res,PGresAttValue*tup)
170209
{
171210
if (res->ntups >=res->tupArrSize)
172211
{
173-
/* grow the array */
174-
res->tupArrSize+=TUPARR_GROW_BY;
175-
176212
/*
177-
* we can use realloc because shallow copying of the structure is
213+
* Try to grow the array.
214+
*
215+
* We can use realloc because shallow copying of the structure is
178216
* okay. Note that the first time through, res->tuples is NULL.
179-
* realloc is supposed to do the right thing in that case. Also
180-
* note that the positions beyond res->ntups are garbage, not
217+
* realloc is supposed to do the right thing in that case. Also,
218+
* on failure realloc is supposed to return NULL without damaging
219+
* the existing allocation.
220+
* Note that the positions beyond res->ntups are garbage, not
181221
* necessarily NULL.
182222
*/
183-
res->tuples= (PGresAttValue**)
184-
realloc(res->tuples,res->tupArrSize*sizeof(PGresAttValue*));
223+
intnewSize=res->tupArrSize+TUPARR_GROW_BY;
224+
PGresAttValue**newTuples= (PGresAttValue**)
225+
realloc(res->tuples,newSize*sizeof(PGresAttValue*));
226+
if (!newTuples)
227+
return FALSE;/* realloc failed */
228+
res->tupArrSize=newSize;
229+
res->tuples=newTuples;
185230
}
186231
res->tuples[res->ntups]=tup;
187232
res->ntups++;
233+
return TRUE;
188234
}
189235

190236

@@ -235,7 +281,6 @@ PQsendQuery(PGconn *conn, const char *query)
235281
/* initialize async result-accumulation state */
236282
conn->result=NULL;
237283
conn->curTuple=NULL;
238-
conn->asyncErrorMessage[0]='\0';
239284

240285
/* send the query to the backend; */
241286
/* the frontend-backend protocol uses 'Q' to designate queries */
@@ -270,10 +315,8 @@ PQconsumeInput(PGconn *conn)
270315
* application wants to get rid of a read-select condition. Note that
271316
* we will NOT block waiting for more input.
272317
*/
273-
if (pqReadData(conn)<0) {
274-
strcpy(conn->asyncErrorMessage,conn->errorMessage);
318+
if (pqReadData(conn)<0)
275319
return0;
276-
}
277320
/* Parsing of the data waits till later. */
278321
return1;
279322
}
@@ -360,16 +403,13 @@ parseInput(PGconn *conn)
360403
conn->asyncStatus=PGASYNC_READY;
361404
break;
362405
case'E':/* error return */
363-
if (pqGets(conn->asyncErrorMessage,ERROR_MSG_LENGTH,conn))
406+
if (pqGets(conn->errorMessage,ERROR_MSG_LENGTH,conn))
364407
return;
365408
/* delete any partially constructed result */
366409
pqClearAsyncResult(conn);
367-
368-
/*
369-
* we leave result NULL while setting
370-
* asyncStatus=READY; this signals an error condition
371-
* to PQgetResult.
372-
*/
410+
/* and build an error result holding the error message */
411+
conn->result=PQmakeEmptyPGresult(conn,
412+
PGRES_FATAL_ERROR);
373413
conn->asyncStatus=PGASYNC_READY;
374414
break;
375415
case'Z':/* backend is ready for new query */
@@ -470,15 +510,18 @@ parseInput(PGconn *conn)
470510
conn->asyncStatus=PGASYNC_COPY_OUT;
471511
break;
472512
default:
473-
sprintf(conn->asyncErrorMessage,
513+
sprintf(conn->errorMessage,
474514
"unknown protocol character '%c' read from backend. "
475515
"(The protocol character is the first character the "
476-
"backend sends in response to a query it receives).\n",
516+
"backend sends in response to a query it receives).\n",
477517
id);
478518
/* Discard the unexpected message; good idea?? */
479519
conn->inStart=conn->inEnd;
480520
/* delete any partially constructed result */
481521
pqClearAsyncResult(conn);
522+
/* and build an error result holding the error message */
523+
conn->result=PQmakeEmptyPGresult(conn,
524+
PGRES_FATAL_ERROR);
482525
conn->asyncStatus=PGASYNC_READY;
483526
return;
484527
}/* switch on protocol character */
@@ -565,7 +608,7 @@ getRowDescriptions(PGconn *conn)
565608
/*
566609
* parseInput subroutine to read a 'B' or 'D' (row data) message.
567610
* We add another tuple to the existing PGresult structure.
568-
* Returns: 0 if completed message, EOF if not enough data yet.
611+
* Returns: 0 if completed message, EOF iferror ornot enough data yet.
569612
*
570613
* Note that if we run out of data, we have to suspend and reprocess
571614
* the message after more data is received. We keep a partially constructed
@@ -593,6 +636,8 @@ getAnotherTuple(PGconn *conn, int binary)
593636
{
594637
conn->curTuple= (PGresAttValue*)
595638
malloc(nfields*sizeof(PGresAttValue));
639+
if (conn->curTuple==NULL)
640+
gotooutOfMemory;
596641
MemSet((char*)conn->curTuple,0,nfields*sizeof(PGresAttValue));
597642
}
598643
tup=conn->curTuple;
@@ -601,9 +646,11 @@ getAnotherTuple(PGconn *conn, int binary)
601646
nbytes= (nfields+BYTELEN-1) /BYTELEN;
602647
if (nbytes >=MAX_FIELDS)
603648
{
604-
sprintf(conn->asyncErrorMessage,
605-
"getAnotherTuple() -- null-values bitmap is too large\n");
649+
/* Replace partially constructed result with an error result */
606650
pqClearAsyncResult(conn);
651+
sprintf(conn->errorMessage,
652+
"getAnotherTuple() -- null-values bitmap is too large\n");
653+
conn->result=PQmakeEmptyPGresult(conn,PGRES_FATAL_ERROR);
607654
conn->asyncStatus=PGASYNC_READY;
608655
/* Discard the broken message */
609656
conn->inStart=conn->inEnd;
@@ -624,7 +671,11 @@ getAnotherTuple(PGconn *conn, int binary)
624671
{
625672
/* if the field value is absent, make it a null string */
626673
if (tup[i].value==NULL)
674+
{
627675
tup[i].value=strdup("");
676+
if (tup[i].value==NULL)
677+
gotooutOfMemory;
678+
}
628679
tup[i].len=NULL_LEN;
629680
}
630681
else
@@ -637,7 +688,11 @@ getAnotherTuple(PGconn *conn, int binary)
637688
if (vlen<0)
638689
vlen=0;
639690
if (tup[i].value==NULL)
691+
{
640692
tup[i].value= (char*)malloc(vlen+1);
693+
if (tup[i].value==NULL)
694+
gotooutOfMemory;
695+
}
641696
tup[i].len=vlen;
642697
/* read in the value */
643698
if (vlen>0)
@@ -659,10 +714,28 @@ getAnotherTuple(PGconn *conn, int binary)
659714
}
660715

661716
/* Success! Store the completed tuple in the result */
662-
addTuple(conn->result,tup);
717+
if (!addTuple(conn->result,tup))
718+
{
719+
/* Oops, not enough memory to add the tuple to conn->result,
720+
* so must free it ourselves...
721+
*/
722+
freeTuple(tup,nfields);
723+
gotooutOfMemory;
724+
}
663725
/* and reset for a new message */
664726
conn->curTuple=NULL;
665727
return0;
728+
729+
outOfMemory:
730+
/* Replace partially constructed result with an error result */
731+
pqClearAsyncResult(conn);
732+
sprintf(conn->errorMessage,
733+
"getAnotherTuple() -- out of memory for result\n");
734+
conn->result=PQmakeEmptyPGresult(conn,PGRES_FATAL_ERROR);
735+
conn->asyncStatus=PGASYNC_READY;
736+
/* Discard the failed message --- good idea? */
737+
conn->inStart=conn->inEnd;
738+
returnEOF;
666739
}
667740

668741

@@ -725,19 +798,26 @@ PQgetResult(PGconn *conn)
725798
res=NULL;/* query is complete */
726799
break;
727800
casePGASYNC_READY:
728-
729801
/*
730-
* conn->result is the PGresult to return, or possibly NULL
731-
* indicating an error. conn->asyncErrorMessage holds the
732-
* errorMessage to return. (We keep it stashed there so that
733-
* other user calls can't overwrite it prematurely.)
802+
* conn->result is the PGresult to return. If it is NULL
803+
* (which probably shouldn't happen) we assume there is
804+
* an appropriate error message in conn->errorMessage.
734805
*/
735806
res=conn->result;
736-
conn->result=NULL;/* handing over ownership to caller */
807+
conn->result=NULL;/* handing over ownership to caller */
737808
conn->curTuple=NULL;/* just in case */
738809
if (!res)
810+
{
739811
res=PQmakeEmptyPGresult(conn,PGRES_FATAL_ERROR);
740-
strcpy(conn->errorMessage,conn->asyncErrorMessage);
812+
}
813+
else
814+
{
815+
/* Make sure PQerrorMessage agrees with result; it could be
816+
* that we have done other operations that changed
817+
* errorMessage since the result's error message was saved.
818+
*/
819+
strcpy(conn->errorMessage,PQresultErrorMessage(res));
820+
}
741821
/* Set the state back to BUSY, allowing parsing to proceed. */
742822
conn->asyncStatus=PGASYNC_BUSY;
743823
break;
@@ -763,11 +843,12 @@ PQgetResult(PGconn *conn)
763843
* PQexec
764844
* send a query to the backend and package up the result in a PGresult
765845
*
766-
* if the query failed, return NULL, conn->errorMessage is set to
767-
* a relevant message
768-
* if query is successful, a new PGresult is returned
769-
* the user is responsible for freeing that structure when done with it
770-
*
846+
* If the query was not even sent, return NULL; conn->errorMessage is set to
847+
* a relevant message.
848+
* If the query was sent, a new PGresult is returned (which could indicate
849+
* either success or failure).
850+
* The user is responsible for freeing the PGresult via PQclear()
851+
* when done with it.
771852
*/
772853

773854
PGresult*
@@ -1312,6 +1393,14 @@ PQresultStatus(PGresult *res)
13121393
returnres->resultStatus;
13131394
}
13141395

1396+
constchar*
1397+
PQresultErrorMessage(PGresult*res)
1398+
{
1399+
if (!res|| !res->errMsg)
1400+
return"";
1401+
returnres->errMsg;
1402+
}
1403+
13151404
int
13161405
PQntuples(PGresult*res)
13171406
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp