* Escape arbitrary strings. If as_ident is true, we escape the result * as an identifier; if false, as a literal. The result is returned in * a newly allocated buffer. If we fail due to an encoding violation or out * of memory condition, we return NULL, storing an error message into conn. */
| 4021 | * of memory condition, we return NULL, storing an error message into conn. |
| 4022 | */ |
| 4023 | static char * |
| 4024 | PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) |
| 4025 | { |
| 4026 | const char *s; |
| 4027 | char *result; |
| 4028 | char *rp; |
| 4029 | int num_quotes = 0; /* single or double, depending on as_ident */ |
| 4030 | int num_backslashes = 0; |
| 4031 | size_t input_len = strlen(str); |
| 4032 | size_t result_size; |
| 4033 | char quote_char = as_ident ? '"' : '\''; |
| 4034 | bool validated_mb = false; |
| 4035 | |
| 4036 | /* We must have a connection, else fail immediately. */ |
| 4037 | if (!conn) |
| 4038 | return NULL; |
| 4039 | |
| 4040 | resetPQExpBuffer(&conn->errorMessage); |
| 4041 | |
| 4042 | /* |
| 4043 | * Scan the string for characters that must be escaped and for invalidly |
| 4044 | * encoded data. |
| 4045 | */ |
| 4046 | s = str; |
| 4047 | for (size_t remaining = input_len; remaining > 0; remaining--, s++) |
| 4048 | { |
| 4049 | if (*s == quote_char) |
| 4050 | ++num_quotes; |
| 4051 | else if (*s == '\\') |
| 4052 | ++num_backslashes; |
| 4053 | else if (IS_HIGHBIT_SET(*s)) |
| 4054 | { |
| 4055 | int charlen; |
| 4056 | |
| 4057 | /* Slow path for possible multibyte characters */ |
| 4058 | charlen = pg_encoding_mblen(conn->client_encoding, s); |
| 4059 | |
| 4060 | if (charlen > remaining) |
| 4061 | { |
| 4062 | appendPQExpBufferStr(&conn->errorMessage, |
| 4063 | libpq_gettext("incomplete multibyte character\n")); |
| 4064 | return NULL; |
| 4065 | } |
| 4066 | |
| 4067 | /* |
| 4068 | * If we haven't already, check that multibyte characters are |
| 4069 | * valid. It's important to verify that as invalid multi-byte |
| 4070 | * characters could e.g. be used to "skip" over quote characters, |
| 4071 | * e.g. when parsing character-by-character. |
| 4072 | * |
| 4073 | * We check validity once, for the whole remainder of the string, |
| 4074 | * when we first encounter any multi-byte character. Some |
| 4075 | * encodings have optimized implementations for longer strings. |
| 4076 | */ |
| 4077 | if (!validated_mb) |
| 4078 | { |
| 4079 | if (pg_encoding_verifymbstr(conn->client_encoding, s, remaining) |
| 4080 | != strlen(s)) |
no test coverage detected