📄 fe-exec.c
字号:
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 || res->cmdStatus[7] < '0' || res->cmdStatus[7] > '9') return InvalidOid; result = strtoul(res->cmdStatus + 7, &endptr, 10); if (!endptr || (*endptr != ' ' && *endptr != '\0')) 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 if not std_strings, replaces "\" 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). */static size_tPQescapeStringInternal(PGconn *conn, char *to, const char *from, size_t length, int *error, int encoding, bool std_strings){ const char *source = from; char *target = to; size_t remaining = length; if (error) *error = 0; while (remaining > 0 && *source != '\0') { char c = *source; int len; int i; /* Fast path for plain ASCII */ if (!IS_HIGHBIT_SET(c)) { /* Apply quoting if needed */ if (c == '\'' || (c == '\\' && !std_strings)) *target++ = c; /* Copy the character */ *target++ = c; source++; remaining--; continue; } /* Slow path for possible multibyte characters */ len = pg_encoding_mblen(encoding, source); /* Copy the character */ for (i = 0; i < len; i++) { if (remaining == 0 || *source == '\0') break; *target++ = *source++; remaining--; } /* * If we hit premature end of string (ie, incomplete multibyte * character), try to pad out to the correct length with spaces. * We may not be able to pad completely, but we will always be able * to insert at least one pad space (since we'd not have quoted a * multibyte character). This should be enough to make a string that * the server will error out on. */ if (i < len) { if (error) *error = 1; if (conn) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("incomplete multibyte character\n")); for (; i < len; i++) { if (((size_t) (target - to)) / 2 >= length) break; *target++ = ' '; } break; } } /* Write the terminating NUL character. */ *target = '\0'; return target - to;}size_tPQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error){ if (!conn) { /* force empty-string result */ *to = '\0'; if (error) *error = 1; return 0; } return PQescapeStringInternal(conn, to, from, length, error, conn->client_encoding, conn->std_strings);}size_tPQescapeString(char *to, const char *from, size_t length){ return PQescapeStringInternal(NULL, to, from, length, NULL, static_client_encoding, static_std_strings);}/* * 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) * If not std_strings, all backslashes sent to the output are doubled. */static unsigned char *PQescapeByteaInternal(PGconn *conn, const unsigned char *from, size_t from_length, size_t *to_length, bool std_strings){ const unsigned char *vp; unsigned char *rp; unsigned char *result; size_t i; size_t len; size_t bslash_len = (std_strings ? 1 : 2); /* * empty string has 1 char ('\0') */ len = 1; vp = from; for (i = from_length; i > 0; i--, vp++) { if (*vp < 0x20 || *vp > 0x7e) len += bslash_len + 3; else if (*vp == '\'') len += 2; else if (*vp == '\\') len += bslash_len + bslash_len; else len++; } *to_length = len; rp = result = (unsigned char *) malloc(len); if (rp == NULL) { if (conn) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return NULL; } vp = from; for (i = from_length; i > 0; i--, vp++) { if (*vp < 0x20 || *vp > 0x7e) { if (!std_strings) *rp++ = '\\'; (void) sprintf((char *) rp, "\\%03o", *vp); rp += 4; } else if (*vp == '\'') { *rp++ = '\''; *rp++ = '\''; } else if (*vp == '\\') { if (!std_strings) { *rp++ = '\\'; *rp++ = '\\'; } *rp++ = '\\'; *rp++ = '\\'; } else *rp++ = *vp; } *rp = '\0'; return result;}unsigned char *PQescapeByteaConn(PGconn *conn, const unsigned char *from, size_t from_length, size_t *to_length){ if (!conn) return NULL; return PQescapeByteaInternal(conn, from, from_length, to_length, conn->std_strings);}unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length){ return PQescapeByteaInternal(NULL, from, from_length, to_length, static_std_strings);}#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 PQfreemem. * * 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((const char *) 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -