66 const char *unescaped,
size_t unescaped_len,
91 const char *unescaped,
size_t unescaped_len,
101 escape_err->
data[escape_err->
len - 1] = 0;
115 const char *unescaped,
size_t unescaped_len,
125 escape_err->
data[escape_err->
len - 1] = 0;
139 const char *unescaped,
size_t unescaped_len,
148 unescaped, unescaped_len,
158 escape_err->
data[escape_err->
len - 1] = 0;
170 const char *unescaped,
size_t unescaped_len,
178 unescaped, unescaped_len);
193 const char *unescaped,
size_t unescaped_len,
196 const char *s = unescaped;
200 for (
int i = 0;
i < unescaped_len;
i++)
219 const char *unescaped,
size_t unescaped_len,
229 const char *unescaped,
size_t unescaped_len,
241 .
name =
"PQescapeLiteral",
242 .reports_errors =
true,
243 .supports_input_length =
true,
247 .name =
"PQescapeIdentifier",
248 .reports_errors =
true,
249 .supports_input_length =
true,
253 .name =
"PQescapeStringConn",
254 .reports_errors =
true,
255 .supports_input_length =
true,
259 .name =
"PQescapeString",
260 .reports_errors =
false,
261 .supports_input_length =
true,
266 .reports_errors =
false,
267 .supports_only_valid =
true,
268 .supports_only_ascii_overlap =
true,
269 .supports_input_length =
true,
273 .name =
"appendStringLiteral",
274 .reports_errors =
false,
279 .reports_errors =
false,
285#define TV(enc, string) {.client_encoding = (enc), .escape=string, .escape_len=sizeof(string) - 1, }
286#define TV_LEN(enc, string, len) {.client_encoding = (enc), .escape=string, .escape_len=len, }
303 TV(
"UTF-8",
"1\xC0"),
304 TV(
"UTF-8",
"1\xE0 "),
305 TV(
"UTF-8",
"1\xF0 "),
306 TV(
"UTF-8",
"1\xF0 "),
307 TV(
"UTF-8",
"1\xF0 "),
310 TV(
"UTF-8",
"1\xE0"),
311 TV(
"UTF-8",
"1\xF0"),
315 TV(
"UTF-8",
"1\xE0'"),
316 TV(
"UTF-8",
"1\xE0\""),
317 TV(
"UTF-8",
"1\xF0'"),
318 TV(
"UTF-8",
"1\xF0\""),
319 TV(
"UTF-8",
"1\xF0'; "),
320 TV(
"UTF-8",
"1\xF0\"; "),
321 TV(
"UTF-8",
"1\xF0';;;;"),
322 TV(
"UTF-8",
"1\xF0 ';;;;"),
323 TV(
"UTF-8",
"1\xF0 \";;;;"),
324 TV(
"UTF-8",
"1\xE0'; \\l ; "),
325 TV(
"UTF-8",
"1\xE0\"; \\l ; "),
328 TV(
"UTF-8",
"some\0thing"),
329 TV(
"UTF-8",
"some\0"),
330 TV(
"UTF-8",
"some\xF0'\0"),
331 TV(
"UTF-8",
"some\xF0'\0'"),
332 TV(
"UTF-8",
"some\xF0" "ab\0'"),
335 TV(
"GB18030",
"\x90\x31"),
336 TV(
"GB18030",
"\\\x81\x5c'"),
337 TV(
"GB18030",
"\\\x81\x5c\""),
338 TV(
"GB18030",
"\\\x81\x5c\0'"),
345 TV(
"GB18030",
"\\\x81';"),
346 TV(
"GB18030",
"\\\x81\";"),
351 TV(
"GB18030",
"\\\x81\\';"),
352 TV(
"GB18030",
"\\\x81\\\";"),
353 TV(
"GB18030",
"\\\x81\0;"),
354 TV(
"GB18030",
"\\\x81\0'"),
355 TV(
"GB18030",
"\\\x81'\0"),
357 TV(
"SJIS",
"\xF0\x40;"),
359 TV(
"SJIS",
"\xF0';"),
360 TV(
"SJIS",
"\xF0\";"),
361 TV(
"SJIS",
"\xF0\0'"),
362 TV(
"SJIS",
"\\\xF0\\';"),
363 TV(
"SJIS",
"\\\xF0\\\";"),
371 TV(
"mule_internal",
"\\\x9c';\0;"),
373 TV(
"sql_ascii",
"1\xC0'"),
381 TV_LEN(
"UTF-8",
"\xC3\xb6 ", 1),
382 TV_LEN(
"UTF-8",
"\xC3\xb6 ", 2),
396 for (
size_t i = 0;
i <
len;
i++)
418 const char *resultdesc)
421 bool print_details =
true;
422 bool print_result =
true;
427 print_details =
false;
429 print_result =
false;
438 printf(
"%s %d - %s: %s: %s\n",
440 test_id, testname->
data,
464#define TOSTR_CASE(sym) case sym: return #sym
510 scan_result =
psql_scan(scan_state, query_buf,
514 "#\t\t %d: scan_result: %s prompt: %u, query_buf: ",
515 matches,
scan_res_s(scan_result), prompt_status);
526 test_fails = matches > 1 || scan_result !=
PSCAN_EOL;
529 resdesc =
"more than one match";
531 resdesc =
"unexpected end state";
548 size_t input_encoding_validlen;
549 bool input_encoding_valid;
550 size_t input_encoding0_validlen;
551 bool input_encoding0_valid;
553 size_t escape_encoding_length;
554 bool escape_encoding_valid;
587 input_encoding_valid = input_encoding_validlen == tv->
escape_len;
589 input_encoding_valid);
596 input_encoding0_valid);
620#define NEVER_ACCESS_STR "\xff never-to-be-touched"
643 escape_success = ef->
escape(tc->
conn, escape_buf,
652 if (escape_buf->
len > 0)
663 escape_encoding_valid = escape_encoding_length == escape_buf->
len;
666 escape_encoding_valid);
675 "escaped data beyond end of input",
676 contains_never ?
"no" :
"all secrets revealed");
680 escape_encoding_length = 0;
681 escape_encoding_valid = 1;
694 const char *resdesc =
"ok";
698 if (!input_encoding0_valid)
701 resdesc =
"invalid input escaped successfully";
703 else if (!input_encoding_valid)
704 resdesc =
"invalid input escaped successfully, due to zero byte";
708 if (input_encoding0_valid)
711 resdesc =
"valid input failed to escape";
713 else if (input_encoding_valid)
714 resdesc =
"valid input failed to escape, due to zero byte";
718 "input validity vs escape success",
728 const char *resdesc =
"ok";
730 if (input_encoding0_valid && !input_encoding_valid && escape_encoding_valid)
732 resdesc =
"invalid input produced valid output, due to zero byte";
734 else if (input_encoding0_valid && !escape_encoding_valid)
737 resdesc =
"valid input produced invalid output";
739 else if (!input_encoding0_valid &&
741 escape_encoding_valid)
744 resdesc =
"invalid input produced valid output";
748 "input and escaped encoding validity",
756 if (escape_buf->
len > 0)
759 escape_buf, details);
775 fprintf(stderr,
"failed to set encoding to %s:\n%s\n",
792 fprintf(stderr,
"Error: %s\n\n", hint);
794 printf(
"PostgreSQL escape function test\n"
797 " test_escape --conninfo=CONNINFO [OPTIONS]\n"
800 " -h, --help show this help\n"
801 " -c, --conninfo=CONNINFO connection information to use\n"
802 " -v, --verbose show test details even for successes\n"
803 " -q, --quiet only show failures\n"
804 " -f, --force-unsupported test invalid input even if unsupported\n"
818 static const struct option long_options[] = {
827 while ((
c =
getopt_long(argc, argv,
"c:fhqv", long_options, &option_index)) != -1)
851 usage(
"unused option(s) specified");
854 usage(
"--conninfo needs to be specified");
860 fprintf(stderr,
"could not connect: %s\n",
#define fprintf(file, fmt, msg)
PGconn * PQconnectdb(const char *conninfo)
ConnStatusType PQstatus(const PGconn *conn)
int PQclientEncoding(const PGconn *conn)
void PQfinish(PGconn *conn)
char * PQerrorMessage(const PGconn *conn)
int PQsetClientEncoding(PGconn *conn, const char *encoding)
void PQfreemem(void *ptr)
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
size_t PQescapeString(char *to, const char *from, size_t length)
char * PQescapeLiteral(PGconn *conn, const char *str, size_t len)
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
PGDLLIMPORT char * optarg
#define PG_ENCODING_BE_LAST
size_t strnlen(const char *str, size_t maxlen)
PQExpBuffer createPQExpBuffer(void)
int enlargePQExpBuffer(PQExpBuffer str, size_t needed)
void resetPQExpBuffer(PQExpBuffer str)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
void destroyPQExpBuffer(PQExpBuffer str)
void appendPQExpBufferChar(PQExpBuffer str, char ch)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
enum _promptStatus promptStatus_t
void psql_scan_destroy(PsqlScanState state)
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
const char * fmtId(const char *rawid)
void setFmtEncoding(int encoding)
void appendStringLiteral(PQExpBuffer buf, const char *str, int encoding, bool std_strings)
bool supports_only_ascii_overlap
bool supports_input_length
bool(* escape)(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
const char * client_encoding
int main(int argc, char *argv[])
static bool escape_replace(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
static void escapify(PQExpBuffer buf, const char *str, size_t len)
static bool escape_string(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
static bool escape_literal(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
#define TV_LEN(enc, string, len)
static bool escape_append_literal(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
struct pe_test_config pe_test_config
static void test_one_vector(pe_test_config *tc, const pe_test_vector *tv)
static pe_test_escape_func pe_test_escape_funcs[]
static const char * scan_res_s(PsqlScanResult res)
static pe_test_vector pe_test_vectors[]
static void test_psql_parse(pe_test_config *tc, PQExpBuffer testname, PQExpBuffer input_buf, PQExpBuffer details)
struct pe_test_vector pe_test_vector
static bool escape_string_conn(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
static bool escape_identifier(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
static void usage(const char *hint)
static void test_one_vector_escape(pe_test_config *tc, const pe_test_vector *tv, const pe_test_escape_func *ef)
struct pe_test_escape_func pe_test_escape_func
static bool encoding_conflicts_ascii(int encoding)
static const PsqlScanCallbacks test_scan_callbacks
static void report_result(pe_test_config *tc, bool success, PQExpBuffer testname, PQExpBuffer details, const char *subname, const char *resultdesc)
static bool escape_fmt_id(PGconn *conn, PQExpBuffer target, const char *unescaped, size_t unescaped_len, PQExpBuffer escape_err)
int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len)