📄 fe-exec.c
字号:
} /* Parse it. */ parseInput(conn); } /* Return the appropriate thing. */ switch (conn->asyncStatus) { case PGASYNC_IDLE: res = NULL; /* query is complete */ break; case PGASYNC_READY: /* * conn->result is the PGresult to return. If it is NULL * (which probably shouldn't happen) we assume there is an * appropriate error message in conn->errorMessage. */ res = conn->result; conn->result = NULL;/* handing over ownership to caller */ conn->curTuple = NULL; /* just in case */ if (!res) res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); else { /* * Make sure PQerrorMessage agrees with result; it could * be that we have done other operations that changed * errorMessage since the result's error message was * saved. */ strcpy(conn->errorMessage, PQresultErrorMessage(res)); } /* Set the state back to BUSY, allowing parsing to proceed. */ conn->asyncStatus = PGASYNC_BUSY; break; case PGASYNC_COPY_IN: res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN); break; case PGASYNC_COPY_OUT: res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT); break; default: sprintf(conn->errorMessage, "PQgetResult: 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){ PGresult *result; PGresult *lastResult; /* * 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) { if (result->resultStatus == PGRES_COPY_IN || result->resultStatus == PGRES_COPY_OUT) { PQclear(result); sprintf(conn->errorMessage, "PQexec: you gotta get out of a COPY state yourself.\n"); return NULL; } PQclear(result); } /* OK to send the message */ if (!PQsendQuery(conn, query)) return NULL; /* * For backwards compatibility, return the last result if there are * more than one. We have to stop if we see copy in/out, however. We * will resume parsing when application calls PQendcopy. */ lastResult = NULL; while ((result = PQgetResult(conn)) != NULL) { if (lastResult) PQclear(lastResult); lastResult = result; if (result->resultStatus == PGRES_COPY_IN || result->resultStatus == PGRES_COPY_OUT) break; } return lastResult;}/* * Attempt to read a Notice response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'N' flag character has already been consumed. * Exit: returns 0 if successfully consumed Notice message. * returns EOF if not enough data. */static intgetNotice(PGconn *conn){ if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn)) return EOF; DONOTICE(conn, conn->errorMessage); return 0;}/* * Attempt to read a Notify response message. * This is possible in several places, so we break it out as a subroutine. * Entry: 'A' flag character has already been consumed. * Exit: returns 0 if successfully consumed Notify message. * returns EOF if not enough data. */static intgetNotify(PGconn *conn){ PGnotify tempNotify; PGnotify *newNotify; if (pqGetInt(&(tempNotify.be_pid), 4, conn)) return EOF; if (pqGets(tempNotify.relname, NAMEDATALEN, conn)) return EOF; newNotify = (PGnotify *) malloc(sizeof(PGnotify)); memcpy(newNotify, &tempNotify, sizeof(PGnotify)); DLAddTail(conn->notifyList, DLNewElem(newNotify)); return 0;}/* * 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){ Dlelem *e; PGnotify *event; if (!conn) return NULL; /* Parse any available data to see if we can extract NOTIFY messages. */ parseInput(conn); /* RemHead returns NULL if list is empty */ e = DLRemHead(conn->notifyList); if (!e) return NULL; event = (PGnotify *) DLE_VAL(e); DLFreeElem(e); return event;}/* * PQgetline - gets a newline-terminated string from the backend. * * Chiefly here so that applications can use "COPY <rel> to stdout" * and read the output string. Returns a null-terminated string in s. * * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips * the terminating \n (like gets(3)). * * CAUTION: the caller is responsible for detecting the end-of-copy signal * (a line containing just "\.") when using this routine. * * RETURNS: * EOF if it is detected or invalid arguments are given * 0 if EOL is reached (i.e., \n has been read) * (this is required for backward-compatibility -- this * routine used to always return EOF or 0, assuming that * the line ended within maxlen bytes.) * 1 in other cases (i.e., the buffer was filled before \n is reached) */intPQgetline(PGconn *conn, char *s, int maxlen){ int result = 1; /* return value if buffer overflows */ if (!s || maxlen <= 0) return EOF; if (!conn || conn->sock < 0) { *s = '\0'; return EOF; } /* * Since this is a purely synchronous routine, we don't bother to * maintain conn->inCursor; there is no need to back up. */ while (maxlen > 1) { if (conn->inStart < conn->inEnd) { char c = conn->inBuffer[conn->inStart++]; if (c == '\n') { result = 0; /* success exit */ break; } *s++ = c; maxlen--; } else { /* need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { result = EOF; break; } } } *s = '\0'; return result;}/* * PQgetlineAsync - gets a newline-terminated string without blocking. * * This routine is for applications that want to do "COPY <rel> to stdout" * asynchronously, that is without blocking. Having issued the COPY command * and gotten a PGRES_COPY_OUT response, the app should call PQconsumeInput * and this routine until the end-of-data signal is detected. Unlike * PQgetline, this routine takes responsibility for detecting end-of-data. * * On each call, PQgetlineAsync will return data if a complete newline- * terminated data line is available in libpq's input buffer, or if the * incoming data line is too long to fit in the buffer offered by the caller. * Otherwise, no data is returned until the rest of the line arrives. * * If -1 is returned, the end-of-data signal has been recognized (and removed * from libpq's input buffer). The caller *must* next call PQendcopy and * then return to normal processing. * * RETURNS: * -1 if the end-of-copy-data marker has been recognized * 0 if no data is available * >0 the number of bytes returned. * The data returned will not extend beyond a newline character. If possible * a whole line will be returned at one time. But if the buffer offered by * the caller is too small to hold a line sent by the backend, then a partial * data line will be returned. This can be detected by testing whether the * last returned byte is '\n' or not. * The returned string is *not* null-terminated. */intPQgetlineAsync(PGconn *conn, char *buffer, int bufsize){ int avail; if (!conn || conn->asyncStatus != PGASYNC_COPY_OUT) return -1; /* we are not doing a copy... */ /* * Move data from libpq's buffer to the caller's. We want to accept * data only in units of whole lines, not partial lines. This ensures * that we can recognize the terminator line "\\.\n". (Otherwise, if * it happened to cross a packet/buffer boundary, we might hand the * first one or two characters off to the caller, which we shouldn't.) */ conn->inCursor = conn->inStart; avail = bufsize; while (avail > 0 && conn->inCursor < conn->inEnd) { char c = conn->inBuffer[conn->inCursor++]; *buffer++ = c; --avail; if (c == '\n') { /* Got a complete line; mark the data removed from libpq */ conn->inStart = conn->inCursor; /* Is it the endmarker line? */ if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.') return -1; /* No, return the data line to the caller */ return bufsize - avail; } } /* * We don't have a complete line. We'd prefer to leave it in libpq's * buffer until the rest arrives, but there is a special case: what if * the line is longer than the buffer the caller is offering us? In * that case we'd better hand over a partial line, else we'd get into * an infinite loop. Do this in a way that ensures we can't * misrecognize a terminator line later: leave last 3 characters in * libpq buffer. */ if (avail == 0 && bufsize > 3) { conn->inStart = conn->inCursor - 3; return bufsize - 3; } return 0;}/* * PQputline -- sends a string to the backend. * Returns 0 if OK, EOF if not. * * Chiefly here so that applications can use "COPY <rel> from stdin". */intPQputline(PGconn *conn, const char *s){ if (!conn || conn->sock < 0) return EOF; return pqPutnchar(s, strlen(s), conn);}/* * PQputnbytes -- like PQputline, but buffer need not be null-terminated. * Returns 0 if OK, EOF if not. */intPQputnbytes(PGconn *conn, const char *buffer, int nbytes){ if (!conn || conn->sock < 0) return EOF; return pqPutnchar(buffer, nbytes, conn);}/* * PQendcopy * After completing the data transfer portion of a copy in/out, * the application must call this routine to finish the command protocol. * * RETURNS: * 0 on success * 1 on failure */intPQendcopy(PGconn *conn){ PGresult *result; if (!conn) return 0; if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { sprintf(conn->errorMessage, "PQendcopy() -- I don't think there's a copy in progress."); return 1; } (void) pqFlush(conn); /* make sure no data is waiting to be sent */ /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; conn->errorMessage[0] = '\0'; /* Wait for the completion response */ result = PQgetResult(conn); /* Expecting a successful result */ if (result && result->resultStatus == PGRES_COMMAND_OK) { PQclear(result); return 0; } /* * Trouble. The worst case is that we've lost sync with the backend * entirely due to application screwup of the copy in/out protocol. To * recover, reset the connection (talk about using a sledgehammer...) */ PQclear(result); if (conn->errorMessage[0]) DONOTICE(conn, conn->errorMessage); DONOTICE(conn, "PQendcopy: resetting connection\n"); PQreset(conn); return 1;}/* ---------------- * PQfn - Send a function call to the POSTGRES backend. * * conn : backend connection * fnid : function id * result_buf : pointer to result buffer (&int if integer) * result_len : length of return value. * actual_result_len: actual length returned. (differs from result_len * for varlena structures.) * result_type : If the result is an integer, this must be 1, * otherwise this should be 0 * args : pointer to an array of function arguments. * (each has length, if integer, and value/pointer) * nargs : # of arguments in args array. * * RETURNS * PGresult with status = PGRES_COMMAND_OK if successful. * *actual_result_len is > 0 if there is a return value, 0 if not. * PGresult with status = PGRES_FATAL_ERROR if backend returns an error. * NULL on communications failure. conn->errorMessage will be set. * ---------------- */PGresult *PQfn(PGconn *conn, int fnid, int *result_buf, int *actual_result_len, int result_is_int, PQArgBlock *args, int nargs){ bool needInput = false; ExecStatusType status = PGRES_FATAL_ERROR; char id; int i; *actual_result_len = 0; if (!conn) return NULL; if (conn->sock < 0 || conn->asyncStatus != PGASYNC_IDLE) { sprintf(conn->errorMessage, "PQfn() -- connection in wrong state\n"); return NULL; } /* clear the error string */ conn->errorMessage[0] = '\0'; if (pqPuts("F ", conn) || /* function */ pqPutInt(fnid, 4, conn) || /* function id */ pqPutInt(nargs, 4, conn)) /* # of args */ { handleSendFailure(conn); return NULL; } for (i = 0; i < nargs; ++i)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -