fe-exec.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,443 行 · 第 1/4 页
C
2,443 行
* convert server version to a numeric form as well. */ if (strcmp(name, "client_encoding") == 0) conn->client_encoding = pg_char_to_encoding(value); else if (strcmp(name, "server_version") == 0) { int cnt; int vmaj, vmin, vrev; cnt = sscanf(value, "%d.%d.%d", &vmaj, &vmin, &vrev); if (cnt < 2) conn->sversion = 0; /* unknown */ else { if (cnt == 2) vrev = 0; conn->sversion = (100 * vmaj + vmin) * 100 + vrev; } }}/* * PQsendQuery * Submit a query, but don't wait for it to finish * * Returns: 1 if successfully submitted * 0 if error (conn->errorMessage is set) */intPQsendQuery(PGconn *conn, const char *query){ if (!PQsendQueryStart(conn)) return 0; if (!query) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("command string is a null pointer\n")); return 0; } /* construct the outgoing Query message */ if (pqPutMsgStart('Q', false, conn) < 0 || pqPuts(query, conn) < 0 || pqPutMsgEnd(conn) < 0) { pqHandleSendFailure(conn); return 0; } /* remember we are using simple query protocol */ conn->ext_query = false; /* * Give the data a push. In nonblock mode, don't complain if we're * unable to send it all; PQgetResult() will do any additional * flushing needed. */ if (pqFlush(conn) < 0) { pqHandleSendFailure(conn); return 0; } /* OK, it's launched! */ conn->asyncStatus = PGASYNC_BUSY; return 1;}/* * PQsendQueryParams * Like PQsendQuery, but use protocol 3.0 so we can pass parameters */intPQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat){ if (!PQsendQueryStart(conn)) return 0; if (!command) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("command string is a null pointer\n")); return 0; } return PQsendQueryGuts(conn, command, "", /* use unnamed statement */ nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat);}/* * PQsendQueryPrepared * Like PQsendQuery, but execute a previously prepared statement, * using protocol 3.0 so we can pass parameters */intPQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat){ if (!PQsendQueryStart(conn)) return 0; if (!stmtName) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("statement name is a null pointer\n")); return 0; } return PQsendQueryGuts(conn, NULL, /* no command to parse */ stmtName, nParams, NULL, /* no param types */ paramValues, paramLengths, paramFormats, resultFormat);}/* * Common startup code for PQsendQuery and sibling routines */static boolPQsendQueryStart(PGconn *conn){ if (!conn) return false; /* clear the error string */ resetPQExpBuffer(&conn->errorMessage); /* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no connection to the server\n")); return false; } /* Can't send while already busy, either. */ if (conn->asyncStatus != PGASYNC_IDLE) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("another command is already in progress\n")); return false; } /* initialize async result-accumulation state */ conn->result = NULL; conn->curTuple = NULL; /* ready to send command message */ return true;}/* * PQsendQueryGuts * Common code for protocol-3.0 query sending * PQsendQueryStart should be done already * * command may be NULL to indicate we use an already-prepared statement */static intPQsendQueryGuts(PGconn *conn, const char *command, const char *stmtName, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat){ int i; /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } /* * We will send Parse (if needed), Bind, Describe Portal, Execute, Sync, * using specified statement name and the unnamed portal. */ if (command) { /* construct the Parse message */ if (pqPutMsgStart('P', false, conn) < 0 || pqPuts(stmtName, conn) < 0 || pqPuts(command, conn) < 0) goto sendFailed; if (nParams > 0 && paramTypes) { if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; for (i = 0; i < nParams; i++) { if (pqPutInt(paramTypes[i], 4, conn) < 0) goto sendFailed; } } else { if (pqPutInt(0, 2, conn) < 0) goto sendFailed; } if (pqPutMsgEnd(conn) < 0) goto sendFailed; } /* construct the Bind message */ if (pqPutMsgStart('B', false, conn) < 0 || pqPuts("", conn) < 0 || pqPuts(stmtName, conn) < 0) goto sendFailed; if (nParams > 0 && paramFormats) { if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; for (i = 0; i < nParams; i++) { if (pqPutInt(paramFormats[i], 2, conn) < 0) goto sendFailed; } } else { if (pqPutInt(0, 2, conn) < 0) goto sendFailed; } if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed; for (i = 0; i < nParams; i++) { if (paramValues && paramValues[i]) { int nbytes; if (paramFormats && paramFormats[i] != 0) { /* binary parameter */ nbytes = paramLengths[i]; } else { /* text parameter, do not use paramLengths */ nbytes = strlen(paramValues[i]); } if (pqPutInt(nbytes, 4, conn) < 0 || pqPutnchar(paramValues[i], nbytes, conn) < 0) goto sendFailed; } else { /* take the param as NULL */ if (pqPutInt(-1, 4, conn) < 0) goto sendFailed; } } if (pqPutInt(1, 2, conn) < 0 || pqPutInt(resultFormat, 2, conn)) goto sendFailed; if (pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Describe Portal message */ if (pqPutMsgStart('D', false, conn) < 0 || pqPutc('P', conn) < 0 || pqPuts("", conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Execute message */ if (pqPutMsgStart('E', false, conn) < 0 || pqPuts("", conn) < 0 || pqPutInt(0, 4, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Sync message */ if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* remember we are using extended query protocol */ conn->ext_query = true; /* * Give the data a push. In nonblock mode, don't complain if we're * unable to send it all; PQgetResult() will do any additional * flushing needed. */ if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */ conn->asyncStatus = PGASYNC_BUSY; return 1;sendFailed: pqHandleSendFailure(conn); return 0;}/* * pqHandleSendFailure: try to clean up after failure to send command. * * Primarily, what we want to accomplish here is to process an async * NOTICE message that the backend might have sent just before it died. * * NOTE: this routine should only be called in PGASYNC_IDLE state. */voidpqHandleSendFailure(PGconn *conn){ /* * Accept any available input data, ignoring errors. Note that if * pqReadData decides the backend has closed the channel, it will * close our side of the socket --- that's just what we want here. */ 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 and only if no query work remains. */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);}/* * 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?