📄 fe-exec.c
字号:
*/ while (pqReadData(conn) > 0) /* loop until no more data readable */ ; /* * Parse any available input messages. Since we are in PGASYNC_IDLE * state, only NOTICE and NOTIFY messages will be eaten. */ parseInput(conn);}/* * Consume any available input from the backend * 0 return: some kind of trouble * 1 return: no problem */intPQconsumeInput(PGconn *conn){ if (!conn) return 0; /* * for non-blocking connections try to flush the send-queue, otherwise we * may never get a response for something that may not have already been * sent because it's in our write buffer! */ if (pqIsnonblocking(conn)) { if (pqFlush(conn) < 0) return 0; } /* * Load more data, if available. We do this no matter what state we are * in, since we are probably getting called because the application wants * to get rid of a read-select condition. Note that we will NOT block * waiting for more input. */ if (pqReadData(conn) < 0) return 0; /* Parsing of the data waits till later. */ return 1;}/* * parseInput: if appropriate, parse input data from backend * until input is exhausted or a stopping state is reached. * Note that this function will NOT attempt to read more data from the backend. */static voidparseInput(PGconn *conn){ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) pqParseInput3(conn); else pqParseInput2(conn);}/* * PQisBusy * Return TRUE if PQgetResult would block waiting for input. */intPQisBusy(PGconn *conn){ if (!conn) return FALSE; /* Parse any available data, if our state permits. */ parseInput(conn); /* PQgetResult will return immediately in all states except BUSY. */ return conn->asyncStatus == PGASYNC_BUSY;}/* * PQgetResult * Get the next PGresult produced by a query. Returns NULL if no * query work remains or an error has occurred (e.g. out of * memory). */PGresult *PQgetResult(PGconn *conn){ PGresult *res; if (!conn) return NULL; /* Parse any available data, if our state permits. */ parseInput(conn); /* If not ready to return something, block until we are. */ while (conn->asyncStatus == PGASYNC_BUSY) { int flushResult; /* * If data remains unsent, send it. Else we might be waiting for the * result of a command the backend hasn't even got yet. */ while ((flushResult = pqFlush(conn)) > 0) { if (pqWait(FALSE, TRUE, conn)) { flushResult = -1; break; } } /* Wait for some more data, and load it. */ if (flushResult || pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { /* * conn->errorMessage has been set by pqWait or pqReadData. We * want to append it to any already-received error message. */ pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_IDLE; return pqPrepareAsyncResult(conn); } /* Parse it. */ parseInput(conn); } /* Return the appropriate thing. */ switch (conn->asyncStatus) { case PGASYNC_IDLE: res = NULL; /* query is complete */ break; case PGASYNC_READY: res = pqPrepareAsyncResult(conn); /* Set the state back to BUSY, allowing parsing to proceed. */ conn->asyncStatus = PGASYNC_BUSY; break; case PGASYNC_COPY_IN: if (conn->result && conn->result->resultStatus == PGRES_COPY_IN) res = pqPrepareAsyncResult(conn); else res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN); break; case PGASYNC_COPY_OUT: if (conn->result && conn->result->resultStatus == PGRES_COPY_OUT) res = pqPrepareAsyncResult(conn); else res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected asyncStatus: %d\n"), (int) conn->asyncStatus); res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); break; } return res;}/* * PQexec * send a query to the backend and package up the result in a PGresult * * If the query was not even sent, return NULL; conn->errorMessage is set to * a relevant message. * If the query was sent, a new PGresult is returned (which could indicate * either success or failure). * The user is responsible for freeing the PGresult via PQclear() * when done with it. */PGresult *PQexec(PGconn *conn, const char *query){ if (!PQexecStart(conn)) return NULL; if (!PQsendQuery(conn, query)) return NULL; return PQexecFinish(conn);}/* * PQexecParams * Like PQexec, but use protocol 3.0 so we can pass parameters */PGresult *PQexecParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat){ if (!PQexecStart(conn)) return NULL; if (!PQsendQueryParams(conn, command, nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat)) return NULL; return PQexecFinish(conn);}/* * PQprepare * Creates a prepared statement by issuing a v3.0 parse message. * * If the query was not even sent, return NULL; conn->errorMessage is set to * a relevant message. * If the query was sent, a new PGresult is returned (which could indicate * either success or failure). * The user is responsible for freeing the PGresult via PQclear() * when done with it. */PGresult *PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes){ if (!PQexecStart(conn)) return NULL; if (!PQsendPrepare(conn, stmtName, query, nParams, paramTypes)) return NULL; return PQexecFinish(conn);}/* * PQexecPrepared * Like PQexec, but execute a previously prepared statement, * using protocol 3.0 so we can pass parameters */PGresult *PQexecPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat){ if (!PQexecStart(conn)) return NULL; if (!PQsendQueryPrepared(conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat)) return NULL; return PQexecFinish(conn);}/* * Common code for PQexec and sibling routines: prepare to send command */static boolPQexecStart(PGconn *conn){ PGresult *result; if (!conn) return false; /* * Silently discard any prior query result that application didn't eat. * This is probably poor design, but it's here for backward compatibility. */ while ((result = PQgetResult(conn)) != NULL) { ExecStatusType resultStatus = result->resultStatus; PQclear(result); /* only need its status */ if (resultStatus == PGRES_COPY_IN) { if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { /* In protocol 3, we can get out of a COPY IN state */ if (PQputCopyEnd(conn, libpq_gettext("COPY terminated by new PQexec")) < 0) return false; /* keep waiting to swallow the copy's failure message */ } else { /* In older protocols we have to punt */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("COPY IN state must be terminated first\n")); return false; } } else if (resultStatus == PGRES_COPY_OUT) { if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { /* * In protocol 3, we can get out of a COPY OUT state: we just * switch back to BUSY and allow the remaining COPY data to be * dropped on the floor. */ conn->asyncStatus = PGASYNC_BUSY; /* keep waiting to swallow the copy's completion message */ } else { /* In older protocols we have to punt */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("COPY OUT state must be terminated first\n")); return false; } } /* check for loss of connection, too */ if (conn->status == CONNECTION_BAD) return false; } /* OK to send a command */ return true;}/* * Common code for PQexec and sibling routines: wait for command result */static PGresult *PQexecFinish(PGconn *conn){ PGresult *result; PGresult *lastResult; /* * For backwards compatibility, return the last result if there are more * than one --- but merge error messages if we get more than one error * result. * * We have to stop if we see copy in/out, however. We will resume parsing * after application performs the data transfer. * * Also stop if the connection is lost (else we'll loop infinitely). */ lastResult = NULL; while ((result = PQgetResult(conn)) != NULL) { if (lastResult) { if (lastResult->resultStatus == PGRES_FATAL_ERROR && result->resultStatus == PGRES_FATAL_ERROR) { pqCatenateResultError(lastResult, result->errMsg); PQclear(result); result = lastResult; /* * Make sure PQerrorMessage agrees with concatenated result */ resetPQExpBuffer(&conn->errorMessage); appendPQExpBufferStr(&conn->errorMessage, result->errMsg); } else PQclear(lastResult); } lastResult = result; if (result->resultStatus == PGRES_COPY_IN || result->resultStatus == PGRES_COPY_OUT || conn->status == CONNECTION_BAD) break; } return lastResult;}/* * PQnotifies * returns a PGnotify* structure of the latest async notification * that has not yet been handled * * returns NULL, if there is currently * no unhandled async notification from the backend * * the CALLER is responsible for FREE'ing the structure returned */PGnotify *PQnotifies(PGconn *conn){ PGnotify *event; if (!conn) return NULL; /* 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 - send some data to the backend during COPY IN * * Returns 1 if successful, 0 if data could not be sent (only possible * in nonblock mode), or -1 if an error occurs. */intPQputCopyData(PGconn *conn, const char *buffer, int nbytes){ if (!conn) return -1; if (conn->asyncStatus != PGASYNC_COPY_IN) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return -1; } /* * Process any NOTICE or NOTIFY messages that might be pending in the * input buffer. Since the server might generate many notices during * the COPY, we want to clean those out reasonably promptly to prevent * indefinite expansion of the input buffer. (Note: the actual read * of input data into the input buffer happens down inside pqSendSome, * but it's not authorized to get rid of the data again.) */ parseInput(conn); if (nbytes > 0) { /* * Try to flush any previously sent data in preference to growing the * output buffer. If we can't enlarge the buffer enough to hold the * data, return 0 in the nonblock case, else hard error. (For * simplicity, always assume 5 bytes of overhead even in protocol 2.0 * case.) */ if ((conn->outBufSize - conn->outCount - 5) < nbytes) { if (pqFlush(conn) < 0) return -1; if (pqCheckOutBufferSpace(conn->outCount + 5 + nbytes, conn)) return pqIsnonblocking(conn) ? 0 : -1; } /* Send the data (too simple to delegate to fe-protocol files) */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { if (pqPutMsgStart('d', false, conn) < 0 || pqPutnchar(buffer, nbytes, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } else { if (pqPutMsgStart(0, false, conn) < 0 || pqPutnchar(buffer, nbytes, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } } return 1;}/* * PQputCopyEnd - send EOF indication to the backend during COPY IN * * After calling this, use PQgetResult() to check command completion status. * * Returns 1 if successful, 0 if data could not be sent (only possible * in nonblock mode), or -1 if an error occurs. */intPQputCopyEnd(PGconn *conn, const char *errormsg){ if (!conn) return -1; if (conn->asyncStatus != PGASYNC_COPY_IN) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return -1; } /* * Send the COPY END indicator. This is simple enough that we don't * bother delegating it to the fe-protocol files. */ if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { if (errormsg) { /* Send COPY FAIL */ if (pqPutMsgStart('f', false, conn) < 0 || pqPuts(errormsg, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } else { /* Send COPY DONE */ if (pqPutMsgStart('c', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } /* * If we sent the COPY command in extended-query mode, we must issue a * Sync as well. */ if (conn->queryclass != PGQUERY_SIMPLE) { if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } } else { if (errormsg) { /* Ooops, no way to do this in 2.0 */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("function requires at least protocol version 3.0\n")); return -1; } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -