66 const char *unescaped,
size_t unescaped_len,
91 const char *unescaped,
size_t unescaped_len,
100 escape_err->
data[escape_err->
len - 1] = 0;
114 const char *unescaped,
size_t unescaped_len,
123 escape_err->
data[escape_err->
len - 1] = 0;
137 const char *unescaped,
size_t unescaped_len,
146 unescaped, unescaped_len,
155 escape_err->
data[escape_err->
len - 1] = 0;
167 const char *unescaped,
size_t unescaped_len,
175 unescaped, unescaped_len);
190 const char *unescaped,
size_t unescaped_len,
193 const char *s = unescaped;
197 for (
int i = 0;
i < unescaped_len;
i++)
216 const char *unescaped,
size_t unescaped_len,
226 const char *unescaped,
size_t unescaped_len,
238 .
name =
"PQescapeLiteral",
239 .reports_errors =
true,
240 .supports_input_length =
true,
244 .name =
"PQescapeIdentifier",
245 .reports_errors =
true,
246 .supports_input_length =
true,
250 .name =
"PQescapeStringConn",
251 .reports_errors =
true,
252 .supports_input_length =
true,
256 .name =
"PQescapeString",
257 .reports_errors =
false,
258 .supports_input_length =
true,
263 .reports_errors =
false,
264 .supports_only_valid =
true,
265 .supports_only_ascii_overlap =
true,
266 .supports_input_length =
true,
270 .name =
"appendStringLiteral",
271 .reports_errors =
false,
276 .reports_errors =
false,
282#define TV(enc, string) {.client_encoding = (enc), .escape=string, .escape_len=sizeof(string) - 1, }
283#define TV_LEN(enc, string, len) {.client_encoding = (enc), .escape=string, .escape_len=len, }
300 TV(
"UTF-8",
"1\xC0"),
301 TV(
"UTF-8",
"1\xE0 "),
302 TV(
"UTF-8",
"1\xF0 "),
303 TV(
"UTF-8",
"1\xF0 "),
304 TV(
"UTF-8",
"1\xF0 "),
307 TV(
"UTF-8",
"1\xE0"),
308 TV(
"UTF-8",
"1\xF0"),
312 TV(
"UTF-8",
"1\xE0'"),
313 TV(
"UTF-8",
"1\xE0\""),
314 TV(
"UTF-8",
"1\xF0'"),
315 TV(
"UTF-8",
"1\xF0\""),
316 TV(
"UTF-8",
"1\xF0'; "),
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\xE0'; \\l ; "),
322 TV(
"UTF-8",
"1\xE0\"; \\l ; "),
325 TV(
"UTF-8",
"some\0thing"),
326 TV(
"UTF-8",
"some\0"),
327 TV(
"UTF-8",
"some\xF0'\0"),
328 TV(
"UTF-8",
"some\xF0'\0'"),
329 TV(
"UTF-8",
"some\xF0" "ab\0'"),
332 TV(
"GB18030",
"\x90\x31"),
333 TV(
"GB18030",
"\\\x81\x5c'"),
334 TV(
"GB18030",
"\\\x81\x5c\""),
335 TV(
"GB18030",
"\\\x81\x5c\0'"),
342 TV(
"GB18030",
"\\\x81';"),
343 TV(
"GB18030",
"\\\x81\";"),
348 TV(
"GB18030",
"\\\x81\\';"),
349 TV(
"GB18030",
"\\\x81\\\";"),
350 TV(
"GB18030",
"\\\x81\0;"),
351 TV(
"GB18030",
"\\\x81\0'"),
352 TV(
"GB18030",
"\\\x81'\0"),
354 TV(
"SJIS",
"\xF0\x40;"),
356 TV(
"SJIS",
"\xF0';"),
357 TV(
"SJIS",
"\xF0\";"),
358 TV(
"SJIS",
"\xF0\0'"),
359 TV(
"SJIS",
"\\\xF0\\';"),
360 TV(
"SJIS",
"\\\xF0\\\";"),
368 TV(
"mule_internal",
"\\\x9c';\0;"),
370 TV(
"sql_ascii",
"1\xC0'"),
378 TV_LEN(
"UTF-8",
"\xC3\xb6 ", 1),
379 TV_LEN(
"UTF-8",
"\xC3\xb6 ", 2),
393 for (
size_t i = 0;
i <
len;
i++)
415 const char *resultdesc)
418 bool print_details =
true;
419 bool print_result =
true;
424 print_details =
false;
426 print_result =
false;
435 printf(
"%s %d - %s: %s: %s\n",
437 test_id, testname->
data,
461#define TOSTR_CASE(sym) case sym: return #sym
507 scan_result =
psql_scan(scan_state, query_buf,
511 "#\t\t %d: scan_result: %s prompt: %u, query_buf: ",
512 matches,
scan_res_s(scan_result), prompt_status);
523 test_fails = matches > 1 || scan_result !=
PSCAN_EOL;
526 resdesc =
"more than one match";
528 resdesc =
"unexpected end state";
545 size_t input_encoding_validlen;
546 bool input_encoding_valid;
547 size_t input_encoding0_validlen;
548 bool input_encoding0_valid;
550 size_t escape_encoding_length;
551 bool escape_encoding_valid;
584 input_encoding_valid = input_encoding_validlen == tv->
escape_len;
586 input_encoding_valid);
593 input_encoding0_valid);
617#define NEVER_ACCESS_STR "\xff never-to-be-touched"
640 escape_success = ef->
escape(tc->
conn, escape_buf,
649 if (escape_buf->
len > 0)
660 escape_encoding_valid = escape_encoding_length == escape_buf->
len;
663 escape_encoding_valid);
672 "escaped data beyond end of input",
673 contains_never ?
"no" :
"all secrets revealed");
677 escape_encoding_length = 0;
678 escape_encoding_valid = 1;
691 const char *resdesc =
"ok";
695 if (!input_encoding0_valid)
698 resdesc =
"invalid input escaped successfully";
700 else if (!input_encoding_valid)
701 resdesc =
"invalid input escaped successfully, due to zero byte";
705 if (input_encoding0_valid)
708 resdesc =
"valid input failed to escape";
710 else if (input_encoding_valid)
711 resdesc =
"valid input failed to escape, due to zero byte";
715 "input validity vs escape success",
725 const char *resdesc =
"ok";
727 if (input_encoding0_valid && !input_encoding_valid && escape_encoding_valid)
729 resdesc =
"invalid input produced valid output, due to zero byte";
731 else if (input_encoding0_valid && !escape_encoding_valid)
734 resdesc =
"valid input produced invalid output";
736 else if (!input_encoding0_valid &&
738 escape_encoding_valid)
741 resdesc =
"invalid input produced valid output";
745 "input and escaped encoding validity",
753 if (escape_buf->
len > 0)
756 escape_buf, details);
772 fprintf(stderr,
"failed to set encoding to %s:\n%s\n",
789 fprintf(stderr,
"Error: %s\n\n", hint);
791 printf(
"PostgreSQL escape function test\n"
794 " test_escape --conninfo=CONNINFO [OPTIONS]\n"
797 " -h, --help show this help\n"
798 " -c, --conninfo=CONNINFO connection information to use\n"
799 " -v, --verbose show test details even for successes\n"
800 " -q, --quiet only show failures\n"
801 " -f, --force-unsupported test invalid input even if unsupported\n"
815 static const struct option long_options[] = {
824 while ((
c =
getopt_long(argc, argv,
"c:fhqv", long_options, &option_index)) != -1)
848 usage(
"unused option(s) specified");
851 usage(
"--conninfo needs to be specified");
857 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)