fe-exec.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,443 行 · 第 1/4 页
C
2,443 行
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 { if (isupper((unsigned char) c)) c = 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 *PQoidStatus(const PGresult *res){ /* * This must be enough to hold the result. Don't laugh, this is better * than what this function used to do. */ static char buf[24]; size_t len; if (!res || !res->cmdStatus || strncmp(res->cmdStatus, "INSERT ", 7) != 0) return ""; len = strspn(res->cmdStatus + 7, "0123456789"); if (len > 23) len = 23; strncpy(buf, res->cmdStatus + 7, len); buf[len] = '\0'; return buf;}/* * PQoidValue - * a perhaps preferable form of the above which just returns * an Oid type */OidPQoidValue(const PGresult *res){ char *endptr = NULL; unsigned long result; if (!res || !res->cmdStatus || strncmp(res->cmdStatus, "INSERT ", 7) != 0) return InvalidOid;#ifdef WIN32 SetLastError(0);#else errno = 0;#endif result = strtoul(res->cmdStatus + 7, &endptr, 10); if (!endptr || (*endptr != ' ' && *endptr != '\0') || errno == ERANGE) return InvalidOid; else return (Oid) result;}/* * PQcmdTuples - * If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a * string containing the number of inserted/affected tuples. If not, * return "". * * XXX: this should probably return an int */char *PQcmdTuples(PGresult *res){ char *p; if (!res) return ""; if (strncmp(res->cmdStatus, "INSERT ", 7) == 0) { p = res->cmdStatus + 6; p++; /* INSERT: skip oid */ while (*p != ' ' && *p) p++; } else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 || strncmp(res->cmdStatus, "UPDATE ", 7) == 0) p = res->cmdStatus + 6; else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0) p = res->cmdStatus + 5; else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0) p = res->cmdStatus + 4; else return ""; p++; if (*p == 0) { pqInternalNotice(&res->noticeHooks, "could not interpret result from server: %s", res->cmdStatus); return ""; } return p;}/* * PQgetvalue: * return the value of field 'field_num' of row 'tup_num' */char *PQgetvalue(const PGresult *res, int tup_num, int field_num){ if (!check_tuple_field_number(res, tup_num, field_num)) return NULL; return res->tuples[tup_num][field_num].value;}/* PQgetlength: * returns the actual length of a field value in bytes. */intPQgetlength(const PGresult *res, int tup_num, int field_num){ if (!check_tuple_field_number(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(const PGresult *res, int tup_num, int field_num){ if (!check_tuple_field_number(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;}/* PQsetnonblocking: * sets the PGconn's database connection non-blocking if the arg is TRUE * or makes it non-blocking if the arg is FALSE, this will not protect * you from PQexec(), you'll only be safe when using the non-blocking API. * Needs to be called only on a connected database connection. */intPQsetnonblocking(PGconn *conn, int arg){ bool barg; if (!conn || conn->status == CONNECTION_BAD) return -1; barg = (arg ? TRUE : FALSE); /* early out if the socket is already in the state requested */ if (barg == conn->nonblocking) return (0); /* * to guarantee constancy for flushing/query/result-polling behavior * we need to flush the send queue at this point in order to guarantee * proper behavior. this is ok because either they are making a * transition _from_ or _to_ blocking mode, either way we can block * them. */ /* if we are going from blocking to non-blocking flush here */ if (pqFlush(conn)) return (-1); conn->nonblocking = barg; return (0);}/* * return the blocking status of the database connection * TRUE == nonblocking, FALSE == blocking */intPQisnonblocking(const PGconn *conn){ return (pqIsnonblocking(conn));}/* try to force data out, really only useful for non-blocking users */intPQflush(PGconn *conn){ return (pqFlush(conn));}/* * PQfreemem - safely frees memory allocated * * Needed mostly by Win32, unless multithreaded DLL (/MD in VC6) * Used for freeing memory from PQescapeByte()a/PQunescapeBytea() */voidPQfreemem(void *ptr){ free(ptr);}/* * PQfreeNotify - free's the memory associated with a PGnotify * * This function is here only for binary backward compatibility. * New code should use PQfreemem(). A macro will automatically map * calls to PQfreemem. It should be removed in the future. bjm 2003-03-24 */#undef PQfreeNotifyvoid PQfreeNotify(PGnotify *notify);voidPQfreeNotify(PGnotify *notify){ PQfreemem(notify);}/* * Escaping arbitrary strings to get valid SQL literal strings. * * Replaces "\\" with "\\\\" and "'" with "''". * * length is the length of the source string. (Note: if a terminating NUL * is encountered sooner, PQescapeString stops short of "length"; the behavior * is thus rather like strncpy.) * * For safety the buffer at "to" must be at least 2*length + 1 bytes long. * A terminating NUL character is added to the output string, whether the * input is NUL-terminated or not. * * Returns the actual length of the output (not counting the terminating NUL). */size_tPQescapeString(char *to, const char *from, size_t length){ const char *source = from; char *target = to; size_t remaining = length; while (remaining > 0 && *source != '\0') { switch (*source) { case '\\': *target++ = '\\'; *target++ = '\\'; break; case '\'': *target++ = '\''; *target++ = '\''; break; default: *target++ = *source; break; } source++; remaining--; } /* Write the terminating NUL character. */ *target = '\0'; return target - to;}/* * PQescapeBytea - converts from binary string to the * minimal encoding necessary to include the string in an SQL * INSERT statement with a bytea type column as the target. * * The following transformations are applied * '\0' == ASCII 0 == \\000 * '\'' == ASCII 39 == \' * '\\' == ASCII 92 == \\\\ * anything < 0x20, or > 0x7e ---> \\ooo * (where ooo is an octal expression) */unsigned char *PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen){ const unsigned char *vp; unsigned char *rp; unsigned char *result; size_t i; size_t len; /* * empty string has 1 char ('\0') */ len = 1; vp = bintext; for (i = binlen; i > 0; i--, vp++) { if (*vp < 0x20 || *vp > 0x7e) len += 5; /* '5' is for '\\ooo' */ else if (*vp == '\'') len += 2; else if (*vp == '\\') len += 4; else len++; } rp = result = (unsigned char *) malloc(len); if (rp == NULL) return NULL; vp = bintext; *bytealen = len; for (i = binlen; i > 0; i--, vp++) { if (*vp < 0x20 || *vp > 0x7e) { (void) sprintf(rp, "\\\\%03o", *vp); rp += 5; } else if (*vp == '\'') { rp[0] = '\\'; rp[1] = '\''; rp += 2; } else if (*vp == '\\') { rp[0] = '\\'; rp[1] = '\\'; rp[2] = '\\'; rp[3] = '\\'; rp += 4; } else *rp++ = *vp; } *rp = '\0'; return result;}#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')#define OCTVAL(CH) ((CH) - '0')/* * PQunescapeBytea - converts the null terminated string representation * of a bytea, strtext, into binary, filling a buffer. It returns a * pointer to the buffer (or NULL on error), and the size of the * buffer in retbuflen. The pointer may subsequently be used as an * argument to the function free(3). It is the reverse of PQescapeBytea. * * The following transformations are made: * \\ == ASCII 92 == \ * \ooo == a byte whose value = ooo (ooo is an octal number) * \x == x (x is any character not matched by the above transformations) */unsigned char *PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen){ size_t strtextlen, buflen; unsigned char *buffer, *tmpbuf; size_t i, j; if (strtext == NULL) return NULL; strtextlen = strlen(strtext); /* * Length of input is max length of output, but add one to avoid * unportable malloc(0) if input is zero-length. */ buffer = (unsigned char *) malloc(strtextlen + 1); if (buffer == NULL) return NULL; for (i = j = 0; i < strtextlen; ) { switch (strtext[i]) { case '\\': i++; if (strtext[i] == '\\') buffer[j++] = strtext[i++]; else { if ((ISFIRSTOCTDIGIT(strtext[i])) && (ISOCTDIGIT(strtext[i + 1])) && (ISOCTDIGIT(strtext[i + 2]))) { int byte; byte = OCTVAL(strtext[i++]); byte = (byte << 3) + OCTVAL(strtext[i++]); byte = (byte << 3) + OCTVAL(strtext[i++]); buffer[j++] = byte; } } /* * Note: if we see '\' followed by something that isn't * a recognized escape sequence, we loop around having * done nothing except advance i. Therefore the something * will be emitted as ordinary data on the next cycle. * Corner case: '\' at end of string will just be discarded. */ break; default: buffer[j++] = strtext[i++]; break; } } buflen = j; /* buflen is the length of the dequoted * data */ /* Shrink the buffer to be no larger than necessary */ /* +1 avoids unportable behavior when buflen==0 */ tmpbuf = realloc(buffer, buflen + 1); /* It would only be a very brain-dead realloc that could fail, but... */ if (!tmpbuf) { free(buffer); return NULL; } *retbuflen = buflen; return tmpbuf;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?