📄 fe-exec.c
字号:
{ /* len.int4 + contents */ if (pqPutInt(args[i].len, 4, conn)) { handleSendFailure(conn); return NULL; } if (args[i].isint) { if (pqPutInt(args[i].u.integer, 4, conn)) { handleSendFailure(conn); return NULL; } } else { if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) { handleSendFailure(conn); return NULL; } } } if (pqFlush(conn)) { handleSendFailure(conn); return NULL; } for (;;) { if (needInput) { /* Wait for some data to arrive (or for the channel to close) */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) break; } /* * Scan the message. If we run out of data, loop around to try * again. */ conn->inCursor = conn->inStart; needInput = true; if (pqGetc(&id, conn)) continue; /* * We should see V or E response to the command, but might get N * and/or A notices first. We also need to swallow the final Z * before returning. */ switch (id) { case 'V': /* function result */ if (pqGetc(&id, conn)) continue; if (id == 'G') { /* function returned nonempty value */ if (pqGetInt(actual_result_len, 4, conn)) continue; if (result_is_int) { if (pqGetInt(result_buf, 4, conn)) continue; } else { if (pqGetnchar((char *) result_buf, *actual_result_len, conn)) continue; } if (pqGetc(&id, conn)) /* get the last '0' */ continue; } if (id == '0') { /* correctly finished function result message */ status = PGRES_COMMAND_OK; } else { /* The backend violates the protocol. */ sprintf(conn->errorMessage, "FATAL: PQfn: protocol error: id=%x\n", id); conn->inStart = conn->inCursor; return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); } break; case 'E': /* error return */ if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn)) continue; status = PGRES_FATAL_ERROR; break; case 'A': /* notify message */ /* handle notify and go back to processing return values */ if (getNotify(conn)) continue; break; case 'N': /* notice */ /* handle notice and go back to processing return values */ if (getNotice(conn)) continue; break; case 'Z': /* backend is ready for new query */ /* consume the message and exit */ conn->inStart = conn->inCursor; return PQmakeEmptyPGresult(conn, status); default: /* The backend violates the protocol. */ sprintf(conn->errorMessage, "FATAL: PQfn: protocol error: id=%x\n", id); conn->inStart = conn->inCursor; return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); } /* Completed this message, keep going */ conn->inStart = conn->inCursor; needInput = false; } /* we fall out of the loop only upon failing to read data */ return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);}/* ====== accessor funcs for PGresult ======== */ExecStatusTypePQresultStatus(PGresult *res){ if (!res) return PGRES_NONFATAL_ERROR; return res->resultStatus;}const char *PQresStatus(ExecStatusType status){ if (((int) status) < 0 || ((int) status) >= (sizeof(pgresStatus) / sizeof(pgresStatus[0]))) return "Invalid ExecStatusType code"; return pgresStatus[status];}const char *PQresultErrorMessage(PGresult *res){ if (!res || !res->errMsg) return ""; return res->errMsg;}intPQntuples(PGresult *res){ if (!res) return 0; return res->ntups;}intPQnfields(PGresult *res){ if (!res) return 0; return res->numAttributes;}intPQbinaryTuples(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 char *routineName, PGresult *res, int field_num){ if (!res) return FALSE; /* no way to display error message... */ if (field_num < 0 || field_num >= res->numAttributes) { if (res->conn) { sprintf(res->conn->errorMessage, "%s: ERROR! field number %d is out of range 0..%d\n", routineName, field_num, res->numAttributes - 1); DONOTICE(res->conn, res->conn->errorMessage); } return FALSE; } return TRUE;}static intcheck_tuple_field_number(const char *routineName, 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) { if (res->conn) { sprintf(res->conn->errorMessage, "%s: ERROR! tuple number %d is out of range 0..%d\n", routineName, tup_num, res->ntups - 1); DONOTICE(res->conn, res->conn->errorMessage); } return FALSE; } if (field_num < 0 || field_num >= res->numAttributes) { if (res->conn) { sprintf(res->conn->errorMessage, "%s: ERROR! field number %d is out of range 0..%d\n", routineName, field_num, res->numAttributes - 1); DONOTICE(res->conn, res->conn->errorMessage); } return FALSE; } return TRUE;}/* returns NULL if the field_num is invalid*/char *PQfname(PGresult *res, int field_num){ if (!check_field_number("PQfname", res, field_num)) return NULL; if (res->attDescs) return res->attDescs[field_num].name; else return NULL;}/* returns -1 on a bad field name*/intPQfnumber(PGresult *res, const char *field_name){ int i; char *field_case; if (!res) return -1; if (field_name == NULL || field_name[0] == '\0' || res->attDescs == NULL) return -1; field_case = strdup(field_name); if (*field_case == '"') { strcpy(field_case, field_case + 1); *(field_case + strlen(field_case) - 1) = '\0'; } else for (i = 0; field_case[i]; i++) if (isascii((unsigned char) field_case[i]) && isupper(field_case[i])) field_case[i] = tolower(field_case[i]); 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;}OidPQftype(PGresult *res, int field_num){ if (!check_field_number("PQftype", res, field_num)) return InvalidOid; if (res->attDescs) return res->attDescs[field_num].typid; else return InvalidOid;}intPQfsize(PGresult *res, int field_num){ if (!check_field_number("PQfsize", res, field_num)) return 0; if (res->attDescs) return res->attDescs[field_num].typlen; else return 0;}intPQfmod(PGresult *res, int field_num){ if (!check_field_number("PQfmod", 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 ""*/const char *PQoidStatus(PGresult *res){ char *p, *e, *scan; int slen, olen; if (!res) return ""; if (strncmp(res->cmdStatus, "INSERT ", 7) != 0) return ""; /*---------- * The cmdStatus string looks like * INSERT oid count\0 * In order to be able to return an ordinary C string without * damaging the result for PQcmdStatus or PQcmdTuples, we copy * the oid part of the string to just after the null, so that * cmdStatus looks like * INSERT oid count\0oid\0 * ^ our return value points here * Pretty klugy eh? This routine should've just returned an Oid value. *---------- */ slen = strlen(res->cmdStatus); p = res->cmdStatus + 7; /* where oid is now */ e = res->cmdStatus + slen + 1; /* where to put the oid string */ for (scan = p; *scan && *scan != ' ';) scan++; olen = scan - p; if (slen + olen + 2 > sizeof(res->cmdStatus)) return ""; /* something very wrong if it doesn't fit */ strncpy(e, p, olen); e[olen] = '\0'; return e;}/* PQcmdTuples - if the last command was an INSERT/UPDATE/DELETE, return number of inserted/affected tuples, if not, return ""*/const char *PQcmdTuples(PGresult *res){ if (!res) return ""; if (strncmp(res->cmdStatus, "INSERT", 6) == 0 || strncmp(res->cmdStatus, "DELETE", 6) == 0 || strncmp(res->cmdStatus, "UPDATE", 6) == 0) { char *p = res->cmdStatus + 6; if (*p == 0) { if (res->conn) { sprintf(res->conn->errorMessage, "PQcmdTuples (%s) -- bad input from server\n", res->cmdStatus); DONOTICE(res->conn, res->conn->errorMessage); } return ""; } p++; if (*(res->cmdStatus) != 'I') /* UPDATE/DELETE */ return p; while (*p != ' ' && *p) p++; /* INSERT: skip oid */ if (*p == 0) { if (res->conn) { sprintf(res->conn->errorMessage, "PQcmdTuples (INSERT) -- there's no # of tuples\n"); DONOTICE(res->conn, res->conn->errorMessage); } return ""; } p++; return p; } return "";}/* PQgetvalue: return the value of field 'field_num' of row 'tup_num' If res is binary, then the value returned is NOT a null-terminated ASCII string, but the binary representation in the server's native format. if res is not binary, a null-terminated ASCII string is returned.*/char *PQgetvalue(PGresult *res, int tup_num, int field_num){ if (!check_tuple_field_number("PQgetvalue", res, tup_num, field_num)) return NULL; return res->tuples[tup_num][field_num].value;}/* PQgetlength: returns the length of a field value in bytes. If res is binary, i.e. a result of a binary portal, then the length returned does NOT include the size field of the varlena. (The data returned by PQgetvalue doesn't either.)*/intPQgetlength(PGresult *res, int tup_num, int field_num){ if (!check_tuple_field_number("PQgetlength", res, tup_num, field_num)) return 0; if (res->tuples[tup_num][field_num].len != NULL_LEN) return res->tuples[tup_num][field_num].len; else return 0;}/* PQgetisnull: returns the null status of a field value.*/intPQgetisnull(PGresult *res, int tup_num, int field_num){ if (!check_tuple_field_number("PQgetisnull", res, tup_num, field_num)) return 1; /* pretend it is null */ if (res->tuples[tup_num][field_num].len == NULL_LEN) return 1; else return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -