📄 fe-exec.c
字号:
{ /* Send old-style end-of-data marker */ if (pqPutMsgStart(0, false, conn) < 0 || pqPutnchar("\\.\n", 3, conn) < 0 || pqPutMsgEnd(conn) < 0) return -1; } } /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; resetPQExpBuffer(&conn->errorMessage); /* Try to flush data */ if (pqFlush(conn) < 0) return -1; return 1;}/* * PQgetCopyData - read a row of data from the backend during COPY OUT * * If successful, sets *buffer to point to a malloc'd row of data, and * returns row length (always > 0) as result. * Returns 0 if no row available yet (only possible if async is true), * -1 if end of copy (consult PQgetResult), or -2 if error (consult * PQerrorMessage). */intPQgetCopyData(PGconn *conn, char **buffer, int async){ *buffer = NULL; /* for all failure cases */ if (!conn) return -2; if (conn->asyncStatus != PGASYNC_COPY_OUT) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return -2; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqGetCopyData3(conn, buffer, async); else return pqGetCopyData2(conn, buffer, async);}/* * 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. * * XXX this routine is now deprecated, because it can't handle binary data. * If called during a COPY BINARY we return EOF. * * 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 error (eg, 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){ if (!s || maxlen <= 0) return EOF; *s = '\0'; /* maxlen must be at least 3 to hold the \. terminator! */ if (maxlen < 3) return EOF; if (!conn) return EOF; if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqGetline3(conn, s, maxlen); else return pqGetline2(conn, s, maxlen);}/* * PQgetlineAsync - gets a COPY data row 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 data row * is available in libpq's input buffer. Otherwise, no data is returned * until the rest of the row 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 data-row boundary. If possible * a whole row will be returned at one time. But if the buffer offered by * the caller is too small to hold a row sent by the backend, then a partial * data row will be returned. In text mode this can be detected by testing * whether the last returned byte is '\n' or not. * * The returned data is *not* null-terminated. */intPQgetlineAsync(PGconn *conn, char *buffer, int bufsize){ if (!conn) return -1; if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqGetlineAsync3(conn, buffer, bufsize); else return pqGetlineAsync2(conn, buffer, bufsize);}/* * PQputline -- sends a string to the backend during COPY IN. * Returns 0 if OK, EOF if not. * * This is deprecated primarily because the return convention doesn't allow * caller to tell the difference between a hard error and a nonblock-mode * send failure. */intPQputline(PGconn *conn, const char *s){ return PQputnbytes(conn, s, strlen(s));}/* * 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 (PQputCopyData(conn, buffer, nbytes) > 0) return 0; else return EOF;}/* * PQendcopy * After completing the data transfer portion of a copy in/out, * the application must call this routine to finish the command protocol. * * When using protocol 3.0 this is deprecated; it's cleaner to use PQgetResult * to get the transfer status. Note however that when using 2.0 protocol, * recovering from a copy failure often requires a PQreset. PQendcopy will * take care of that, PQgetResult won't. * * RETURNS: * 0 on success * 1 on failure */intPQendcopy(PGconn *conn){ if (!conn) return 0; if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqEndcopy3(conn); else return pqEndcopy2(conn);}/* ---------------- * 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, const PQArgBlock *args, int nargs){ *actual_result_len = 0; if (!conn) return NULL; /* clear the error string */ resetPQExpBuffer(&conn->errorMessage); if (conn->sock < 0 || conn->asyncStatus != PGASYNC_IDLE || conn->result != NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection in wrong state\n")); return NULL; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) return pqFunctionCall3(conn, fnid, result_buf, actual_result_len, result_is_int, args, nargs); else return pqFunctionCall2(conn, fnid, result_buf, actual_result_len, result_is_int, args, nargs);}/* ====== accessor funcs for PGresult ======== */ExecStatusTypePQresultStatus(const PGresult *res){ if (!res) return PGRES_FATAL_ERROR; return res->resultStatus;}char *PQresStatus(ExecStatusType status){ if (status < 0 || status >= sizeof pgresStatus / sizeof pgresStatus[0]) return libpq_gettext("invalid ExecStatusType code"); return pgresStatus[status];}char *PQresultErrorMessage(const PGresult *res){ if (!res || !res->errMsg) return ""; return res->errMsg;}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;}intPQntuples(const PGresult *res){ if (!res) return 0; return res->ntups;}intPQnfields(const PGresult *res){ if (!res) return 0; return res->numAttributes;}intPQbinaryTuples(const PGresult *res){ if (!res) return 0; return res->binary;}/* * Helper routines to range-check field numbers and tuple numbers. * Return TRUE if OK, FALSE if not */static intcheck_field_number(const PGresult *res, int field_num){ if (!res) return FALSE; /* 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); return FALSE; } return TRUE;}static intcheck_tuple_field_number(const PGresult *res, int tup_num, int field_num){ if (!res) return FALSE; /* 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); return FALSE; } 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); return FALSE; } return TRUE;}/* * returns NULL if the field_num is invalid */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;}/* * PQfnumber: find column number given column name * * The column name is parsed as if it were in a SQL statement, including * case-folding and double-quote processing. But note a possible gotcha: * downcasing in the frontend might follow different locale rules than * downcasing in the backend... * * Returns -1 if no match. In the present backend it is also possible * to have multiple matches, in which case the first one is found. */intPQfnumber(const PGresult *res, const char *field_name){ char *field_case; bool in_quotes; char *iptr; char *optr; int i; if (!res) return -1; /* * Note: it is correct to reject a zero-length input string; the proper * input to match a zero-length field name would be "". */ if (field_name == NULL || field_name[0] == '\0' || res->attDescs == NULL) return -1; /* * Note: this code will not reject partially quoted strings, eg * foo"BAR"foo will become fooBARfoo when it probably ought to be an error * condition. */ field_case = strdup(field_name); if (field_case == NULL) return -1; /* grotty */ 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; } else if (c == '"') in_quotes = true; else { c = pg_tolower((unsigned char) 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;}OidPQftable(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;}intPQftablecol(const PGresult *res, int field_num){ if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].columnid; else return 0;}intPQfformat(const PGresult *res, int field_num){ if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].format; else return 0;}OidPQftype(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;}intPQfsize(const PGresult *res, int field_num){ if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].typlen; else return 0;}intPQfmod(const PGresult *res, int field_num){ if (!check_field_number(res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].atttypmod; else return 0;}char *PQcmdStatus(PGresult *res){ if (!res) return NULL; return res->cmdStatus;}/* * PQoidStatus - * if the last command was an INSERT, return the oid string * if not, return "" */char *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -