/* keep this in same order as ExecStatusType in libpq-fe.h */ char *const pgresStatus[] = { "PGRES_EMPTY_QUERY", "PGRES_COMMAND_OK", "PGRES_TUPLES_OK", "PGRES_COPY_OUT", "PGRES_COPY_IN", "PGRES_BAD_RESPONSE", "PGRES_NONFATAL_ERROR", "PGRES_FATAL_ERROR", "PGRES_COPY_BOTH", "PGRES_SINGLE_TUPLE", "PGRES_PIPELINE_SYNC", "PGRES_PIPELINE_ABORTED", "PGRES_TUPLES_CHUNK"
};
/* We return this if we're unable to make a PGresult at all */ staticconst PGresult OOM_result = {
.resultStatus = PGRES_FATAL_ERROR,
.client_encoding = PG_SQL_ASCII,
.errMsg = "out of memory\n",
};
if (conn)
{ /* copy connection data we might need for operations on PGresult */
result->noticeHooks = conn->noticeHooks;
result->client_encoding = conn->client_encoding;
/* consider copying conn's errorMessage */ switch (status)
{ case PGRES_EMPTY_QUERY: case PGRES_COMMAND_OK: case PGRES_TUPLES_OK: case PGRES_COPY_OUT: case PGRES_COPY_IN: case PGRES_COPY_BOTH: case PGRES_SINGLE_TUPLE: case PGRES_TUPLES_CHUNK: /* non-error cases */ break; default: /* we intentionally do not use or modify errorReported here */
pqSetResultError(result, &conn->errorMessage, 0); break;
}
/* copy events last; result must be valid if we need to PQclear */ if (conn->nEvents > 0)
{
result->events = dupEvents(conn->events, conn->nEvents,
&result->memorySize); if (!result->events)
{
PQclear(result); return NULL;
}
result->nEvents = conn->nEvents;
}
} else
{ /* defaults... */
result->noticeHooks.noticeRec = NULL;
result->noticeHooks.noticeRecArg = NULL;
result->noticeHooks.noticeProc = NULL;
result->noticeHooks.noticeProcArg = NULL;
result->client_encoding = PG_SQL_ASCII;
}
return result;
}
/* *PQsetResultAttrs * *Settheattributesforagivenresult.Thisfunctionfailsifthereare *alreadyattributescontainedintheprovidedresult.Thecallis *ignoredifnumAttributesiszeroorattDescsisNULL.Ifthe *functionfails,itreturnszero.Ifthefunctionsucceeds,it *returnsanon-zerovalue.
*/ int
PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs)
{ int i;
/* Fail if argument is NULL or OOM_result */ if (!res || (const PGresult *) res == &OOM_result) returnfalse;
/* If attrs already exist, they cannot be overwritten. */ if (res->numAttributes > 0) returnfalse;
/* deep-copy the attribute names, and determine format */
res->binary = 1; for (i = 0; i < res->numAttributes; i++)
{ if (res->attDescs[i].name)
res->attDescs[i].name = pqResultStrdup(res, res->attDescs[i].name); else
res->attDescs[i].name = res->null_field;
if (!res->attDescs[i].name) returnfalse;
if (res->attDescs[i].format == 0)
res->binary = 0;
}
/* Okay, trigger PGEVT_RESULTCOPY event */ for (i = 0; i < dest->nEvents; i++)
{ /* We don't fire events that had some previous failure */ if (src->events[i].resultInitialized)
{
PGEventResultCopy evt;
for (i = 0; i < count; i++)
{
newEvents[i].proc = events[i].proc;
newEvents[i].passThrough = events[i].passThrough;
newEvents[i].data = NULL;
newEvents[i].resultInitialized = false;
newEvents[i].name = strdup(events[i].name); if (!newEvents[i].name)
{ while (--i >= 0)
free(newEvents[i].name);
free(newEvents); return NULL;
}
msize += strlen(events[i].name) + 1;
}
*memSize += msize; return newEvents;
}
/* *Setsthevalueforatuplefield.Thetup_nummustbelessthanor *equaltoPQntuples(res).Ifitisequal,anewtupleiscreatedand *addedtotheresult. *Returnsanon-zerovalueforsuccessandzeroforfailure. *(Onfailure,wereportthespecificproblemviapqInternalNotice.)
*/ int
PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
{
PGresAttValue *attval; constchar *errmsg = NULL;
/* Fail if argument is NULL or OOM_result */ if (!res || (const PGresult *) res == &OOM_result) returnfalse;
/* Invalid field_num? */ if (!check_field_number(res, field_num)) returnfalse;
/* Invalid tup_num, must be <= ntups */ if (tup_num < 0 || tup_num > res->ntups)
{
pqInternalNotice(&res->noticeHooks, "row number %d is out of range 0..%d",
tup_num, res->ntups); returnfalse;
}
/* need to allocate a new tuple? */ if (tup_num == res->ntups)
{
PGresAttValue *tup; int i;
/* If there's enough space in the current block, no problem. */ if (nBytes <= (size_t) res->spaceLeft)
{
space = res->curBlock->space + res->curOffset;
res->curOffset += nBytes;
res->spaceLeft -= nBytes; return space;
}
/* As a convenience, do nothing for a NULL pointer */ if (!res) return; /* Also, do nothing if the argument is OOM_result */ if ((const PGresult *) res == &OOM_result) return;
/* Close down any events we may have */ for (i = 0; i < res->nEvents; i++)
{ /* only send DESTROY to successfully-initialized event procs */ if (res->events[i].resultInitialized)
{
PGEventResultDestroy evt;
/* *pqSaveErrorResult- *rememberthatwehaveanerrorcondition * *Inmuchoflibpq,reportinganerrorjustrequiresappendingtextto *conn->errorMessageandreturningafailurecodetoone'scaller. *Wherereturningafailurecodeisimpractical,insteadcallthis *functiontorememberthatanerrorneedstobereported. * *(Itmightseemthatappendingtexttoconn->errorMessageshouldbe *sufficient,butwecan'trelyonthatworkingunderout-of-memory *conditions.TheOOMhazardisalsowhywedon'ttrytomakeanew *PGresultrighthere.)
*/ void
pqSaveErrorResult(PGconn *conn)
{ /* Drop any pending result ... */
pqClearAsyncResult(conn); /* ... and set flag to remember to make an error result later */
conn->error_result = true;
}
/* *pqSaveWriteError- *reportawritefailure * *Asabove,afterappendingconn->write_err_msgtowhateverothererrorwe *have.Thisisusedwhenwe'vedetectedawritefailureandhaveexhausted *ourchancesofreportingsomethingelseinstead.
*/ staticvoid
pqSaveWriteError(PGconn *conn)
{ /* *Ifwrite_err_msgisnullbecauseofpreviousstrdupfailure,dowhatwe *can.(It'slikelyourmachinationsherewillgetOOMfailuresaswell, *butmightaswelltry.)
*/ if (conn->write_err_msg)
{
appendPQExpBufferStr(&conn->errorMessage, conn->write_err_msg); /* Avoid possibly appending the same message twice */
conn->write_err_msg[0] = '\0';
} else
libpq_append_conn_error(conn, "write to server failed");
if (hooks->noticeRec == NULL) return; /* nobody home to receive notice? */
/* Format the message */
va_start(args, fmt);
vsnprintf(msgBuf, sizeof(msgBuf), libpq_gettext(fmt), args);
va_end(args);
msgBuf[sizeof(msgBuf) - 1] = '\0'; /* make real sure it's terminated */
/* Make a PGresult to pass to the notice receiver */
res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR); if (!res) return;
res->noticeHooks = *hooks;
/* *Setupfieldsofnotice.
*/
pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, msgBuf);
pqSaveMessageField(res, PG_DIAG_SEVERITY, libpq_gettext("NOTICE"));
pqSaveMessageField(res, PG_DIAG_SEVERITY_NONLOCALIZED, "NOTICE"); /* XXX should provide a SQLSTATE too? */
/* *Inpartial-resultmode,ifwedon'talreadyhaveapartialPGresult *thenmakeonebycloningconn->result(whichshouldholdthecorrect *resultmetadatabynow).Thentheoriginalconn->resultismovedover *tosaved_resultsothatwecanre-useitasareferenceforfuture *partialresults.Thesavedresultwillbecomeactiveagainafter *pqPrepareAsyncResult()returnsthepartialresulttotheapplication.
*/ if (conn->partialResMode && conn->saved_result == NULL)
{ /* Copy everything that should be in the result at this point */
res = PQcopyResult(res,
PG_COPYRES_ATTRS | PG_COPYRES_EVENTS |
PG_COPYRES_NOTICEHOOKS); if (!res) return0; /* Change result status to appropriate special value */
res->resultStatus = (conn->singleRowMode ? PGRES_SINGLE_TUPLE : PGRES_TUPLES_CHUNK); /* And stash it as the active result */
conn->saved_result = conn->result;
conn->result = res;
}
/* check the argument */ if (!query)
{
libpq_append_conn_error(conn, "command string is a null pointer"); return0;
}
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
{
libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQsendQuery"); return0;
}
entry = pqAllocCmdQueueEntry(conn); if (entry == NULL) return0; /* error msg already set */
/* Send the query message(s) */ /* construct the outgoing Query message */ if (pqPutMsgStart(PqMsg_Query, conn) < 0 ||
pqPuts(query, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
{ /* error message should be set up already */
pqRecycleCmdQueueEntry(conn, entry); return0;
}
/* remember we are using simple query protocol */
entry->queryclass = PGQUERY_SIMPLE; /* and remember the query text too, if possible */
entry->query = strdup(query);
/* *Givethedataapush.Innonblockmode,don'tcomplainifwe'reunable *tosenditall;PQgetResult()willdoanyadditionalflushingneeded.
*/ if (pqFlush(conn) < 0) goto sendFailed;
sendFailed:
pqRecycleCmdQueueEntry(conn, entry); /* error message should be set up already */ return0;
}
/* *PQsendQueryParams *LikePQsendQuery,butuseextendedqueryprotocolsowecanpassparameters
*/ int
PQsendQueryParams(PGconn *conn, constchar *command, int nParams, const Oid *paramTypes, constchar *const *paramValues, constint *paramLengths, constint *paramFormats, int resultFormat)
{ if (!PQsendQueryStart(conn, true)) return0;
/* check the arguments */ if (!command)
{
libpq_append_conn_error(conn, "command string is a null pointer"); return0;
} if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT)
{
libpq_append_conn_error(conn, "number of parameters must be between 0 and %d",
PQ_QUERY_PARAM_MAX_LIMIT); return0;
}
/* *PQsendPrepare *SubmitaParsemessage,butdon'twaitforittofinish * *Returns:1ifsuccessfullysubmitted *0iferror(conn->errorMessageisset)
*/ int
PQsendPrepare(PGconn *conn, constchar *stmtName, constchar *query, int nParams, const Oid *paramTypes)
{
PGcmdQueueEntry *entry = NULL;
if (!PQsendQueryStart(conn, true)) return0;
/* check the arguments */ if (!stmtName)
{
libpq_append_conn_error(conn, "statement name is a null pointer"); return0;
} if (!query)
{
libpq_append_conn_error(conn, "command string is a null pointer"); return0;
} if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT)
{
libpq_append_conn_error(conn, "number of parameters must be between 0 and %d",
PQ_QUERY_PARAM_MAX_LIMIT); return0;
}
entry = pqAllocCmdQueueEntry(conn); if (entry == NULL) return0; /* error msg already set */
sendFailed:
pqRecycleCmdQueueEntry(conn, entry); /* error message should be set up already */ return0;
}
/* *PQsendQueryPrepared *LikePQsendQuery,butexecuteapreviouslypreparedstatement, *usingextendedqueryprotocolsowecanpassparameters
*/ int
PQsendQueryPrepared(PGconn *conn, constchar *stmtName, int nParams, constchar *const *paramValues, constint *paramLengths, constint *paramFormats, int resultFormat)
{ if (!PQsendQueryStart(conn, true)) return0;
/* check the arguments */ if (!stmtName)
{
libpq_append_conn_error(conn, "statement name is a null pointer"); return0;
} if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT)
{
libpq_append_conn_error(conn, "number of parameters must be between 0 and %d",
PQ_QUERY_PARAM_MAX_LIMIT); return0;
}
return PQsendQueryGuts(conn,
NULL, /* no command to parse */
stmtName,
nParams,
NULL, /* no param types */
paramValues,
paramLengths,
paramFormats,
resultFormat);
}
/* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK)
{
libpq_append_conn_error(conn, "no connection to the server"); returnfalse;
}
/* Can't send while already busy, either, unless enqueuing for later */ if (conn->asyncStatus != PGASYNC_IDLE &&
conn->pipelineStatus == PQ_PIPELINE_OFF)
{
libpq_append_conn_error(conn, "another command is already in progress"); returnfalse;
}
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
{ /* *Whenenqueuingcommandswedon'tchangemuchoftheconnection *statesinceit'salreadyinuseforthecurrentcommand.The *connectionstatewillgetupdatedwhenpqPipelineProcessQueue() *advancestostartprocessingthequeuedmessage. * *Justmakesurewecansafelyenqueuegiventhecurrentconnection *state.Wecanenqueuebehindanotherqueueitem,orbehinda *non-queuecommand(onethatsendsitsownsync),butwecan't *enqueueiftheconnectionisinacopystate.
*/ switch (conn->asyncStatus)
{ case PGASYNC_IDLE: case PGASYNC_PIPELINE_IDLE: case PGASYNC_READY: case PGASYNC_READY_MORE: case PGASYNC_BUSY: /* ok to queue */ break;
case PGASYNC_COPY_IN: case PGASYNC_COPY_OUT: case PGASYNC_COPY_BOTH:
libpq_append_conn_error(conn, "cannot queue commands during COPY"); returnfalse;
}
} else
{ /* *Thiscommand'sresultswillcomeinimmediately.Initializeasync *result-accumulationstate
*/
pqClearAsyncResult(conn);
/* construct the Sync message if not in pipeline mode */ if (conn->pipelineStatus == PQ_PIPELINE_OFF)
{ if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
pqPutMsgEnd(conn) < 0) goto sendFailed;
}
/* remember we are using extended query protocol */
entry->queryclass = PGQUERY_EXTENDED;
/* and remember the query text too, if possible */ /* if insufficient memory, query just winds up NULL */ if (command)
entry->query = strdup(command);
/* Return the appropriate thing. */ switch (conn->asyncStatus)
{ case PGASYNC_IDLE:
res = NULL; /* query is complete */ break; case PGASYNC_PIPELINE_IDLE:
Assert(conn->pipelineStatus != PQ_PIPELINE_OFF);
/* *We'reabouttoreturntheNULLthatterminatestheroundof *resultsfromthecurrentquery;preparetosendtheresultsof *thenextquery,ifany,whenwe'recallednext.Ifthere'sno *nextelementinthecommandqueue,thisgetsusinIDLEstate.
*/
pqPipelineProcessQueue(conn);
res = NULL; /* query is complete */ break;
case PGASYNC_READY:
res = pqPrepareAsyncResult(conn);
/* *...incaseswhenwe'resendingapipeline-syncresult, *movequeueprocessingforwardsimmediately,sothatnext *timewe'recalled,we'repreparedtoreturnthenextresult *receivedfromtheserver.Inallothercases,leavethe *queuestatechangefornexttime,sothataterminating *NULLresultissent. * *(Inotherwords:wedon'treturnaNULLafterapipeline *sync.)
*/ if (res->resultStatus == PGRES_PIPELINE_SYNC)
pqPipelineProcessQueue(conn);
} else
{ /* Set the state back to BUSY, allowing parsing to proceed. */
conn->asyncStatus = PGASYNC_BUSY;
} break; case PGASYNC_READY_MORE:
res = pqPrepareAsyncResult(conn); /* Set the state back to BUSY, allowing parsing to proceed. */
conn->asyncStatus = PGASYNC_BUSY; break; case PGASYNC_COPY_IN:
res = getCopyResult(conn, PGRES_COPY_IN); break; case PGASYNC_COPY_OUT:
res = getCopyResult(conn, PGRES_COPY_OUT); break; case PGASYNC_COPY_BOTH:
res = getCopyResult(conn, PGRES_COPY_BOTH); break; default:
libpq_append_conn_error(conn, "unexpected asyncStatus: %d", (int) conn->asyncStatus);
pqSaveErrorResult(conn);
conn->asyncStatus = PGASYNC_IDLE; /* try to restore valid state */
res = pqPrepareAsyncResult(conn); break;
}
/* Time to fire PGEVT_RESULTCREATE events, if there are any */ if (res && res->nEvents > 0)
(void) PQfireResultCreateEvents(conn, res);
/* If we have an async result for the COPY, return that */ if (conn->result && conn->result->resultStatus == copytype) return pqPrepareAsyncResult(conn);
/* *Sincethisisthebeginningofaquerycycle,resettheerrorstate. *However,inpipelinemodewithsomethingalreadyqueued,theerror *bufferbelongstothatcommandandweshouldn'tclearit.
*/ if (conn->cmd_queue_head == NULL)
pqClearConnErrorState(conn);
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
{
libpq_append_conn_error(conn, "synchronous command execution functions are not allowed in pipeline mode"); returnfalse;
}
PQclear(result); /* only need its status */ if (resultStatus == PGRES_COPY_IN)
{ /* get out of a COPY IN state */ if (PQputCopyEnd(conn,
libpq_gettext("COPY terminated by new PQexec")) < 0) returnfalse; /* keep waiting to swallow the copy's failure message */
} elseif (resultStatus == PGRES_COPY_OUT)
{ /* *GetoutofaCOPYOUTstate:wejustswitchbacktoBUSYand *allowtheremainingCOPYdatatobedroppedonthefloor.
*/
conn->asyncStatus = PGASYNC_BUSY; /* keep waiting to swallow the copy's completion message */
} elseif (resultStatus == PGRES_COPY_BOTH)
{ /* We don't allow PQexec during COPY BOTH */
libpq_append_conn_error(conn, "PQexec not allowed during COPY BOTH"); returnfalse;
} /* check for loss of connection, too */ if (conn->status == CONNECTION_BAD) returnfalse;
}
/* Treat null target as empty string */ if (!target)
target = "";
if (!PQsendQueryStart(conn, true)) return0;
entry = pqAllocCmdQueueEntry(conn); if (entry == NULL) return0; /* error msg already set */
/* construct the Close message */ if (pqPutMsgStart(command, conn) < 0 ||
pqPutc(type, conn) < 0 ||
pqPuts(target, conn) < 0 ||
pqPutMsgEnd(conn) < 0) goto sendFailed;
/* construct the Sync message */ if (conn->pipelineStatus == PQ_PIPELINE_OFF)
{ if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
pqPutMsgEnd(conn) < 0) goto sendFailed;
}
/* remember if we are doing a Close or a Describe */ if (command == PqMsg_Close)
{
entry->queryclass = PGQUERY_CLOSE;
} elseif (command == PqMsg_Describe)
{
entry->queryclass = PGQUERY_DESCRIBE;
} else
{
libpq_append_conn_error(conn, "unrecognized message type \"%c\"", command); goto sendFailed;
}
/* Parse any available data to see if we can extract NOTIFY messages. */
parseInput(conn);
event = conn->notifyHead; if (event)
{
conn->notifyHead = event->next; if (!conn->notifyHead)
conn->notifyTail = NULL;
event->next = NULL; /* don't let app see the internal state */
} return event;
}
/* *PQputCopyData-sendsomedatatothebackendduringCOPYINorCOPYBOTH * *Returns1ifsuccessful,0ifdatacouldnotbesent(onlypossible *innonblockmode),or-1ifanerroroccurs.
*/ int
PQputCopyData(PGconn *conn, constchar *buffer, int nbytes)
{ if (!conn) return -1; if (conn->asyncStatus != PGASYNC_COPY_IN &&
conn->asyncStatus != PGASYNC_COPY_BOTH)
{
libpq_append_conn_error(conn, "no COPY in progress"); return -1;
}
PGresult *
PQfn(PGconn *conn, int fnid, int *result_buf, int *result_len, int result_is_int, const PQArgBlock *args, int nargs)
{ return PQnfn(conn, fnid, result_buf, -1, result_len,
result_is_int, args, nargs);
}
/* *PQnfn *PrivateversionofPQfn()withverificationthatreturneddatafitsin *result_bufwhenresult_is_int==0.Settingbuf_sizeto-1disables *thisverification.
*/
PGresult *
PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, int *result_len, int result_is_int, const PQArgBlock *args, int nargs)
{
*result_len = 0;
if (!conn) return NULL;
/* *Sincethisisthebeginningofaquerycycle,resettheerrorstate. *However,inpipelinemodewithsomethingalreadyqueued,theerror *bufferbelongstothatcommandandweshouldn'tclearit.
*/ if (conn->cmd_queue_head == NULL)
pqClearConnErrorState(conn);
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
{
libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQfn"); return NULL;
}
if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE ||
pgHavePendingResult(conn))
{
libpq_append_conn_error(conn, "connection in wrong state"); return NULL;
}
switch (conn->asyncStatus)
{ case PGASYNC_READY: case PGASYNC_READY_MORE: /* there are some uncollected results */
libpq_append_conn_error(conn, "cannot exit pipeline mode with uncollected results"); return0;
case PGASYNC_BUSY:
libpq_append_conn_error(conn, "cannot exit pipeline mode while busy"); return0;
case PGASYNC_IDLE: case PGASYNC_PIPELINE_IDLE: /* OK */ break;
case PGASYNC_COPY_IN: case PGASYNC_COPY_OUT: case PGASYNC_COPY_BOTH:
libpq_append_conn_error(conn, "cannot exit pipeline mode while in COPY");
}
/* still work to process */ if (conn->cmd_queue_head != NULL)
{
libpq_append_conn_error(conn, "cannot exit pipeline mode with uncollected results"); return0;
}
/* *Ifwe'rewaitingforaSYNC,don'tadvancethequeueuntilwegetone.
*/ if (conn->cmd_queue_head->queryclass == PGQUERY_SYNC && !gotSync) return;
/* delink element from queue */
prevquery = conn->cmd_queue_head;
conn->cmd_queue_head = conn->cmd_queue_head->next;
/* If the queue is now empty, reset the tail too */ if (conn->cmd_queue_head == NULL)
conn->cmd_queue_tail = NULL;
/* and make the queue element recyclable */
prevquery->next = NULL;
pqRecycleCmdQueueEntry(conn, prevquery);
}
/* *pqPipelineProcessQueue:subroutineforPQgetResult *Inpipelinemode,startprocessingtheresultsofthenextqueryinthequeue.
*/ staticvoid
pqPipelineProcessQueue(PGconn *conn)
{ switch (conn->asyncStatus)
{ case PGASYNC_COPY_IN: case PGASYNC_COPY_OUT: case PGASYNC_COPY_BOTH: case PGASYNC_READY: case PGASYNC_READY_MORE: case PGASYNC_BUSY: /* client still has to process current query or results */ return;
if (conn->pipelineStatus == PQ_PIPELINE_OFF)
{
libpq_append_conn_error(conn, "cannot send pipeline when not in pipeline mode"); return0;
}
switch (conn->asyncStatus)
{ case PGASYNC_COPY_IN: case PGASYNC_COPY_OUT: case PGASYNC_COPY_BOTH: /* should be unreachable */
appendPQExpBufferStr(&conn->errorMessage, "internal error: cannot send pipeline while in COPY\n"); return0; case PGASYNC_READY: case PGASYNC_READY_MORE: case PGASYNC_BUSY: case PGASYNC_IDLE: case PGASYNC_PIPELINE_IDLE: /* OK to send sync */ break;
}
entry = pqAllocCmdQueueEntry(conn); if (entry == NULL) return0; /* error msg already set */
sendFailed:
pqRecycleCmdQueueEntry(conn, entry); /* error message should be set up already */ return0;
}
/* *PQsendFlushRequest *Sendrequestforservertoflushitsbuffer.Usefulinpipeline *modewhenasyncpointisnotdesired.
*/ int
PQsendFlushRequest(PGconn *conn)
{ if (!conn) return0;
/* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK)
{
libpq_append_conn_error(conn, "no connection to the server"); return0;
}
/* Can't send while already busy, either, unless enqueuing for later */ if (conn->asyncStatus != PGASYNC_IDLE &&
conn->pipelineStatus == PQ_PIPELINE_OFF)
{
libpq_append_conn_error(conn, "another command is already in progress"); return0;
}
/* If insufficient memory to format the message, fail cleanly */ if (PQExpBufferDataBroken(workBuf))
{
termPQExpBuffer(&workBuf); return strdup(libpq_gettext("out of memory\n"));
}
return workBuf.data;
}
char *
PQresultErrorField(const PGresult *res, int fieldcode)
{
PGMessageField *pfield;
if (!res) return NULL; for (pfield = res->errFields; pfield != NULL; pfield = pfield->next)
{ if (pfield->code == fieldcode) return pfield->contents;
} return NULL;
}
int
PQntuples(const PGresult *res)
{ if (!res) return0; return res->ntups;
}
int
PQnfields(const PGresult *res)
{ if (!res) return0; return res->numAttributes;
}
int
PQbinaryTuples(const PGresult *res)
{ if (!res) return0; return res->binary;
}
staticint
check_field_number(const PGresult *res, int field_num)
{ if (!res) returnfalse; /* no way to display error message... */ if (field_num < 0 || field_num >= res->numAttributes)
{
pqInternalNotice(&res->noticeHooks, "column number %d is out of range 0..%d",
field_num, res->numAttributes - 1); returnfalse;
} returntrue;
}
staticint
check_tuple_field_number(const PGresult *res, int tup_num, int field_num)
{ if (!res) returnfalse; /* no way to display error message... */ if (tup_num < 0 || tup_num >= res->ntups)
{
pqInternalNotice(&res->noticeHooks, "row number %d is out of range 0..%d",
tup_num, res->ntups - 1); returnfalse;
} if (field_num < 0 || field_num >= res->numAttributes)
{
pqInternalNotice(&res->noticeHooks, "column number %d is out of range 0..%d",
field_num, res->numAttributes - 1); returnfalse;
} returntrue;
}
staticint
check_param_number(const PGresult *res, int param_num)
{ if (!res) returnfalse; /* no way to display error message... */ if (param_num < 0 || param_num >= res->numParameters)
{
pqInternalNotice(&res->noticeHooks, "parameter number %d is out of range 0..%d",
param_num, res->numParameters - 1); returnfalse;
}
returntrue;
}
/* *returnsNULLifthefield_numisinvalid
*/ char *
PQfname(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return NULL; if (res->attDescs) return res->attDescs[field_num].name; else return NULL;
}
in_quotes = false;
optr = field_case; for (iptr = field_case; *iptr; iptr++)
{ char c = *iptr;
if (in_quotes)
{ if (c == '"')
{ if (iptr[1] == '"')
{ /* doubled quotes become a single quote */
*optr++ = '"';
iptr++;
} else
in_quotes = false;
} else
*optr++ = c;
} elseif (c == '"')
in_quotes = true; else
{
c = pg_tolower((unsignedchar) c);
*optr++ = c;
}
}
*optr = '\0';
for (i = 0; i < res->numAttributes; i++)
{ if (strcmp(field_case, res->attDescs[i].name) == 0)
{
free(field_case); return i;
}
}
free(field_case); return -1;
}
Oid
PQftable(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return InvalidOid; if (res->attDescs) return res->attDescs[field_num].tableid; else return InvalidOid;
}
int
PQftablecol(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return0; if (res->attDescs) return res->attDescs[field_num].columnid; else return0;
}
int
PQfformat(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return0; if (res->attDescs) return res->attDescs[field_num].format; else return0;
}
Oid
PQftype(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return InvalidOid; if (res->attDescs) return res->attDescs[field_num].typid; else return InvalidOid;
}
int
PQfsize(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return0; if (res->attDescs) return res->attDescs[field_num].typlen; else return0;
}
int
PQfmod(const PGresult *res, int field_num)
{ if (!check_field_number(res, field_num)) return0; if (res->attDescs) return res->attDescs[field_num].atttypmod; else return0;
}
if (strncmp(res->cmdStatus, "INSERT ", 7) == 0)
{
p = res->cmdStatus + 7; /* INSERT: skip oid and space */ while (*p && *p != ' ')
p++; if (*p == 0) goto interpret_error; /* no space? */
p++;
} elseif (strncmp(res->cmdStatus, "SELECT ", 7) == 0 ||
strncmp(res->cmdStatus, "DELETE ", 7) == 0 ||
strncmp(res->cmdStatus, "UPDATE ", 7) == 0)
p = res->cmdStatus + 7; elseif (strncmp(res->cmdStatus, "FETCH ", 6) == 0 ||
strncmp(res->cmdStatus, "MERGE ", 6) == 0)
p = res->cmdStatus + 6; elseif (strncmp(res->cmdStatus, "MOVE ", 5) == 0 ||
strncmp(res->cmdStatus, "COPY ", 5) == 0)
p = res->cmdStatus + 5; else return"";
/* check that we have an integer (at least one digit, nothing else) */ for (c = p; *c; c++)
{ if (!isdigit((unsignedchar) *c)) goto interpret_error;
} if (c == p) goto interpret_error;
return p;
interpret_error:
pqInternalNotice(&res->noticeHooks, "could not interpret result from server: %s",
res->cmdStatus); return"";
}
/* *PQgetvalue: *returnthevalueoffield'field_num'ofrow'tup_num'
*/ char *
PQgetvalue(const PGresult *res, int tup_num, int field_num)
{ if (!check_tuple_field_number(res, tup_num, field_num)) return NULL; return res->tuples[tup_num][field_num].value;
}
/* PQgetlength: *returnstheactuallengthofafieldvalueinbytes.
*/ int
PQgetlength(const PGresult *res, int tup_num, int field_num)
{ if (!check_tuple_field_number(res, tup_num, field_num)) return0; if (res->tuples[tup_num][field_num].len != NULL_LEN) return res->tuples[tup_num][field_num].len; else return0;
}
/* PQgetisnull: *returnsthenullstatusofafieldvalue.
*/ int
PQgetisnull(const PGresult *res, int tup_num, int field_num)
{ if (!check_tuple_field_number(res, tup_num, field_num)) return1; /* pretend it is null */ if (res->tuples[tup_num][field_num].len == NULL_LEN) return1; else return0;
}
/* PQnparams: *returnsthenumberofinputparametersofapreparedstatement.
*/ int
PQnparams(const PGresult *res)
{ if (!res) return0; return res->numParameters;
}
/* PQparamtype: *returnstypeOidofthespecifiedstatementparameter.
*/
Oid
PQparamtype(const PGresult *res, int param_num)
{ if (!check_param_number(res, param_num)) return InvalidOid; if (res->paramDescs) return res->paramDescs[param_num].typid; else return InvalidOid;
}
/* PQsetnonblocking: *setsthePGconn'sdatabaseconnectionnon-blockingiftheargistrue *ormakesitblockingiftheargisfalse,thiswillnotprotect *youfromPQexec(),you'llonlybesafewhenusingthenon-blockingAPI. *Needstobecalledonlyonaconnecteddatabaseconnection.
*/ int
PQsetnonblocking(PGconn *conn, int arg)
{ bool barg;
if (!conn || conn->status == CONNECTION_BAD) return -1;
barg = (arg ? true : false);
/* early out if the socket is already in the state requested */ if (barg == conn->nonblocking) return0;
/* if we are going from blocking to non-blocking flush here */ if (pqFlush(conn)) return -1;
conn->nonblocking = barg;
return0;
}
/* *returntheblockingstatusofthedatabaseconnection *true==nonblocking,false==blocking
*/ int
PQisnonblocking(const PGconn *conn)
{ if (!conn || conn->status == CONNECTION_BAD) returnfalse; return pqIsnonblocking(conn);
}
/* libpq is thread-safe? */ int
PQisthreadsafe(void)
{ returntrue;
}
/* try to force data out, really only useful for non-blocking users */ int
PQflush(PGconn *conn)
{ if (!conn || conn->status == CONNECTION_BAD) return -1; return pqFlush(conn);
}
while (remaining > 0)
{ char c = *source; int charlen; int i;
/* Fast path for plain ASCII */ if (!IS_HIGHBIT_SET(c))
{ /* Apply quoting if needed */ if (SQL_STR_DOUBLE(c, !std_strings))
*target++ = c; /* Copy the character */
*target++ = c;
source++;
remaining--; continue;
}
/* Slow path for possible multibyte characters */
charlen = pg_encoding_mblen_or_incomplete(encoding,
source, remaining);
if (remaining < charlen ||
pg_encoding_verifymbchar(encoding, source, charlen) == -1)
{ /* *Multibytecharacterisinvalid.It'simportanttoverifythat *asinvalidmultibytecharacterscoulde.g.beusedto"skip" *overquotecharacters,e.g.whenparsing *character-by-character. * *Reportanerrorifpossible,andreplacethecharacter'sfirst *bytewithaninvalidsequence.Theinvalidsequenceensures *thattheescapedstringwilltriggeranerroronthe *server-side,evenifwecan'tdirectlyreportanerrorhere. * *Thisisn't*that*crucialwhenwecanreportanerrortothe *caller;butifwecan'torthecallerignoresit,thecaller *willusethisstringunmodifiedanditneedstobesafefor *parsing. * *Weknowthere'senoughspacefortheinvalidsequencebecause *the"to"bufferneedstobeatleast2*length+1long,and *atworstwe'rereplacingasingleinputbytewithtwoinvalid *bytes. * *Itwouldbeabitfastertoverifythewholestringthefirst *timeweencounterasethighbit,butthiswaywecanreplace *justtheinvaliddata,whichprobablymakesiteasierforusers *tofindtheinvalidlyencodedportionofalargerstring.
*/ if (error)
*error = 1; if (conn && !already_complained)
{ if (remaining < charlen)
libpq_append_conn_error(conn, "incomplete multibyte character"); else
libpq_append_conn_error(conn, "invalid multibyte character"); /* Issue a complaint only once per string */
already_complained = true;
}
if (use_hex)
{ /* We prepend "\x" and double each input character. */ if (pg_add_size_overflow(len, bslash_len + 1, &len) ||
pg_add_size_overflow(len, from_length, &len) ||
pg_add_size_overflow(len, from_length, &len)) goto overflow;
} else
{
vp = from; for (i = from_length; i > 0; i--, vp++)
{ if (*vp < 0x20 || *vp > 0x7e)
{ if (pg_add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */ goto overflow;
} elseif (*vp == '\'')
{ if (pg_add_size_overflow(len, 2, &len)) /* double each quote */ goto overflow;
} elseif (*vp == '\\')
{ if (pg_add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */ goto overflow;
} else
{ if (pg_add_size_overflow(len, 1, &len)) goto overflow;
}
}
}
*to_length = len;
rp = result = (unsignedchar *) malloc(len); if (rp == NULL)
{ if (conn)
libpq_append_conn_error(conn, "out of memory"); return NULL;
}
if (use_hex)
{ if (!std_strings)
*rp++ = '\\';
*rp++ = '\\';
*rp++ = 'x';
}
vp = from; for (i = from_length; i > 0; i--, vp++)
{ unsignedchar c = *vp;
default:
buffer[j++] = strtext[i++]; break;
}
}
buflen = j; /* buflen is the length of the dequoted data */
}
/* Shrink the buffer to be no larger than necessary */ /* +1 avoids unportable behavior when buflen==0 */
tmpbuf = realloc(buffer, buflen + 1);
/* It would only be a very brain-dead realloc that could fail, but... */ if (!tmpbuf)
{
free(buffer); return NULL;
}
*retbuflen = buflen; return tmpbuf;
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.223Bemerkung:
(vorverarbeitet am 2026-08-06)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.