Skip to content

Commit

Permalink
Add option to automatically try all parse modes
Browse files Browse the repository at this point in the history
  • Loading branch information
seanlinsley committed Dec 21, 2023
1 parent db39825 commit 5e8e676
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 9 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ examples/normalize_error: examples/normalize_error.c $(ARLIB)
examples/simple_plpgsql: examples/simple_plpgsql.c $(ARLIB)
$(CC) $(TEST_CFLAGS) -o $@ -g examples/simple_plpgsql.c $(ARLIB) $(TEST_LDFLAGS)

TESTS = test/complex test/concurrency test/deparse test/fingerprint test/fingerprint_opts test/normalize test/parse test/parse_opts test/parse_protobuf test/parse_protobuf_opts test/parse_plpgsql test/scan test/split
TESTS = test/complex test/concurrency test/deparse test/fingerprint test/fingerprint_opts test/normalize test/normalize_opts test/parse test/parse_opts test/parse_protobuf test/parse_protobuf_opts test/parse_plpgsql test/scan test/split
test: $(TESTS)
ifeq ($(VALGRIND),1)
$(VALGRIND_MEMCHECK) test/complex || (cat test/valgrind.log && false)
Expand All @@ -239,6 +239,7 @@ ifeq ($(VALGRIND),1)
$(VALGRIND_MEMCHECK) test/fingerprint || (cat test/valgrind.log && false)
$(VALGRIND_MEMCHECK) test/fingerprint_opts || (cat test/valgrind.log && false)
$(VALGRIND_MEMCHECK) test/normalize || (cat test/valgrind.log && false)
$(VALGRIND_MEMCHECK) test/normalize_opts || (cat test/valgrind.log && false)
$(VALGRIND_MEMCHECK) test/parse || (cat test/valgrind.log && false)
$(VALGRIND_MEMCHECK) test/parse_opts || (cat test/valgrind.log && false)
$(VALGRIND_MEMCHECK) test/parse_protobuf || (cat test/valgrind.log && false)
Expand All @@ -255,6 +256,7 @@ else
test/fingerprint
test/fingerprint_opts
test/normalize
test/normalize_opts
test/parse
test/parse_opts
test/parse_protobuf
Expand Down Expand Up @@ -287,6 +289,9 @@ test/fingerprint_opts: test/fingerprint_opts.c test/fingerprint_opts_tests.c $(A
test/normalize: test/normalize.c test/normalize_tests.c $(ARLIB)
$(CC) $(TEST_CFLAGS) -o $@ test/normalize.c $(ARLIB) $(TEST_LDFLAGS)

test/normalize_opts: test/normalize_opts.c test/normalize_opts_tests.c $(ARLIB)
$(CC) $(TEST_CFLAGS) -o $@ test/normalize_opts.c $(ARLIB) $(TEST_LDFLAGS)

test/parse: test/parse.c test/parse_tests.c $(ARLIB)
$(CC) $(TEST_CFLAGS) -o $@ test/parse.c $(ARLIB) $(TEST_LDFLAGS)

Expand Down
4 changes: 3 additions & 1 deletion pg_query.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ typedef enum
PG_QUERY_PARSE_PLPGSQL_EXPR,
PG_QUERY_PARSE_PLPGSQL_ASSIGN1,
PG_QUERY_PARSE_PLPGSQL_ASSIGN2,
PG_QUERY_PARSE_PLPGSQL_ASSIGN3
PG_QUERY_PARSE_PLPGSQL_ASSIGN3,
PG_QUERY_PARSE_ALL
} PgQueryParseMode;

// We technically only need 3 bits to store parse mode, but
Expand All @@ -96,6 +97,7 @@ extern "C" {
#endif

PgQueryNormalizeResult pg_query_normalize(const char* input);
PgQueryNormalizeResult pg_query_normalize_opts(const char* input, int parser_options);
PgQueryScanResult pg_query_scan(const char* input);
PgQueryParseResult pg_query_parse(const char* input);
PgQueryParseResult pg_query_parse_opts(const char* input, int parser_options);
Expand Down
33 changes: 32 additions & 1 deletion src/pg_query_fingerprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,38 @@ PgQueryFingerprintResult pg_query_fingerprint(const char* input)

PgQueryFingerprintResult pg_query_fingerprint_opts(const char* input, int parser_options)
{
return pg_query_fingerprint_with_opts(input, parser_options, false);
if ((parser_options & PG_QUERY_PARSE_ALL) == PG_QUERY_PARSE_ALL) {
parser_options = (parser_options & ~PG_QUERY_PARSE_ALL) | PG_QUERY_PARSE_DEFAULT;
PgQueryFingerprintResult result = pg_query_fingerprint_with_opts(input, parser_options, false);
if (result.error) {
pg_query_free_fingerprint_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_DEFAULT) | PG_QUERY_PARSE_TYPE_NAME;
result = pg_query_fingerprint_with_opts(input, parser_options, false);
}
if (result.error) {
pg_query_free_fingerprint_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_TYPE_NAME) | PG_QUERY_PARSE_PLPGSQL_EXPR;
result = pg_query_fingerprint_with_opts(input, parser_options, false);
}
if (result.error) {
pg_query_free_fingerprint_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_EXPR) | PG_QUERY_PARSE_PLPGSQL_ASSIGN1;
result = pg_query_fingerprint_with_opts(input, parser_options, false);
}
if (result.error) {
pg_query_free_fingerprint_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN1) | PG_QUERY_PARSE_PLPGSQL_ASSIGN2;
result = pg_query_fingerprint_with_opts(input, parser_options, false);
}
if (result.error) {
pg_query_free_fingerprint_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN2) | PG_QUERY_PARSE_PLPGSQL_ASSIGN3;
result = pg_query_fingerprint_with_opts(input, parser_options, false);
}
return result;
} else {
return pg_query_fingerprint_with_opts(input, parser_options, false);
}
}

void pg_query_free_fingerprint_result(PgQueryFingerprintResult result)
Expand Down
77 changes: 75 additions & 2 deletions src/pg_query_normalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ static bool const_record_walker(Node *node, pgssConstLocations *jstate)
return false;
}

PgQueryNormalizeResult pg_query_normalize(const char* input)
PgQueryNormalizeResult pg_query_normalize_opts_internal(const char* input, int parser_options)
{
MemoryContext ctx = NULL;
PgQueryNormalizeResult result = {0};
Expand All @@ -571,8 +571,40 @@ PgQueryNormalizeResult pg_query_normalize(const char* input)
pgssConstLocations jstate;
int query_len;

RawParseMode rawParseMode = RAW_PARSE_DEFAULT;
switch (parser_options & PG_QUERY_PARSE_MODE_BITMASK)
{
case PG_QUERY_PARSE_TYPE_NAME:
rawParseMode = RAW_PARSE_TYPE_NAME;
break;
case PG_QUERY_PARSE_PLPGSQL_EXPR:
rawParseMode = RAW_PARSE_PLPGSQL_EXPR;
break;
case PG_QUERY_PARSE_PLPGSQL_ASSIGN1:
rawParseMode = RAW_PARSE_PLPGSQL_ASSIGN1;
break;
case PG_QUERY_PARSE_PLPGSQL_ASSIGN2:
rawParseMode = RAW_PARSE_PLPGSQL_ASSIGN2;
break;
case PG_QUERY_PARSE_PLPGSQL_ASSIGN3:
rawParseMode = RAW_PARSE_PLPGSQL_ASSIGN3;
break;
}

if ((parser_options & PG_QUERY_DISABLE_BACKSLASH_QUOTE) == PG_QUERY_DISABLE_BACKSLASH_QUOTE) {
backslash_quote = BACKSLASH_QUOTE_OFF;
} else {
backslash_quote = BACKSLASH_QUOTE_SAFE_ENCODING;
}
standard_conforming_strings = !((parser_options & PG_QUERY_DISABLE_STANDARD_CONFORMING_STRINGS) == PG_QUERY_DISABLE_STANDARD_CONFORMING_STRINGS);
escape_string_warning = !((parser_options & PG_QUERY_DISABLE_ESCAPE_STRING_WARNING) == PG_QUERY_DISABLE_ESCAPE_STRING_WARNING);

/* Parse query */
tree = raw_parser(input, RAW_PARSE_DEFAULT);
tree = raw_parser(input, rawParseMode);

backslash_quote = BACKSLASH_QUOTE_SAFE_ENCODING;
standard_conforming_strings = true;
escape_string_warning = true;

query_len = (int) strlen(input);

Expand Down Expand Up @@ -621,6 +653,47 @@ PgQueryNormalizeResult pg_query_normalize(const char* input)
return result;
}

PgQueryNormalizeResult pg_query_normalize_opts(const char* input, int parser_options)
{
if ((parser_options & PG_QUERY_PARSE_ALL) == PG_QUERY_PARSE_ALL) {
parser_options = (parser_options & ~PG_QUERY_PARSE_ALL) | PG_QUERY_PARSE_DEFAULT;
PgQueryNormalizeResult result = pg_query_normalize_opts_internal(input, parser_options);
if (result.error) {
pg_query_free_normalize_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_DEFAULT) | PG_QUERY_PARSE_TYPE_NAME;
result = pg_query_normalize_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_normalize_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_TYPE_NAME) | PG_QUERY_PARSE_PLPGSQL_EXPR;
result = pg_query_normalize_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_normalize_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_EXPR) | PG_QUERY_PARSE_PLPGSQL_ASSIGN1;
result = pg_query_normalize_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_normalize_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN1) | PG_QUERY_PARSE_PLPGSQL_ASSIGN2;
result = pg_query_normalize_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_normalize_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN2) | PG_QUERY_PARSE_PLPGSQL_ASSIGN3;
result = pg_query_normalize_opts_internal(input, parser_options);
}
return result;
} else {
return pg_query_normalize_opts_internal(input, parser_options);
}
}

PgQueryNormalizeResult pg_query_normalize(const char* input)
{
return pg_query_normalize_opts(input, PG_QUERY_PARSE_DEFAULT);
}

void pg_query_free_normalize_result(PgQueryNormalizeResult result)
{
if (result.error) {
Expand Down
76 changes: 74 additions & 2 deletions src/pg_query_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ PgQueryParseResult pg_query_parse(const char* input)
return pg_query_parse_opts(input, PG_QUERY_PARSE_DEFAULT);
}

PgQueryParseResult pg_query_parse_opts(const char* input, int parser_options)
PgQueryParseResult pg_query_parse_opts_internal(const char* input, int parser_options)
{
MemoryContext ctx = NULL;
PgQueryInternalParsetreeAndError parsetree_and_error;
Expand All @@ -144,12 +144,48 @@ PgQueryParseResult pg_query_parse_opts(const char* input, int parser_options)
return result;
}

PgQueryParseResult pg_query_parse_opts(const char* input, int parser_options)
{
if ((parser_options & PG_QUERY_PARSE_ALL) == PG_QUERY_PARSE_ALL) {
parser_options = (parser_options & ~PG_QUERY_PARSE_ALL) | PG_QUERY_PARSE_DEFAULT;
PgQueryParseResult result = pg_query_parse_opts_internal(input, parser_options);
if (result.error) {
pg_query_free_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_DEFAULT) | PG_QUERY_PARSE_TYPE_NAME;
result = pg_query_parse_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_TYPE_NAME) | PG_QUERY_PARSE_PLPGSQL_EXPR;
result = pg_query_parse_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_EXPR) | PG_QUERY_PARSE_PLPGSQL_ASSIGN1;
result = pg_query_parse_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN1) | PG_QUERY_PARSE_PLPGSQL_ASSIGN2;
result = pg_query_parse_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN2) | PG_QUERY_PARSE_PLPGSQL_ASSIGN3;
result = pg_query_parse_opts_internal(input, parser_options);
}
return result;
} else {
return pg_query_parse_opts_internal(input, parser_options);
}
}

PgQueryProtobufParseResult pg_query_parse_protobuf(const char* input)
{
return pg_query_parse_protobuf_opts(input, PG_QUERY_PARSE_DEFAULT);
}

PgQueryProtobufParseResult pg_query_parse_protobuf_opts(const char* input, int parser_options)
PgQueryProtobufParseResult pg_query_parse_protobuf_opts_internal(const char* input, int parser_options)
{
MemoryContext ctx = NULL;
PgQueryInternalParsetreeAndError parsetree_and_error;
Expand All @@ -169,6 +205,42 @@ PgQueryProtobufParseResult pg_query_parse_protobuf_opts(const char* input, int p
return result;
}

PgQueryProtobufParseResult pg_query_parse_protobuf_opts(const char* input, int parser_options)
{
if ((parser_options & PG_QUERY_PARSE_ALL) == PG_QUERY_PARSE_ALL) {
parser_options = (parser_options & ~PG_QUERY_PARSE_ALL) | PG_QUERY_PARSE_DEFAULT;
PgQueryProtobufParseResult result = pg_query_parse_protobuf_opts_internal(input, parser_options);
if (result.error) {
pg_query_free_protobuf_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_DEFAULT) | PG_QUERY_PARSE_TYPE_NAME;
result = pg_query_parse_protobuf_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_protobuf_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_TYPE_NAME) | PG_QUERY_PARSE_PLPGSQL_EXPR;
result = pg_query_parse_protobuf_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_protobuf_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_EXPR) | PG_QUERY_PARSE_PLPGSQL_ASSIGN1;
result = pg_query_parse_protobuf_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_protobuf_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN1) | PG_QUERY_PARSE_PLPGSQL_ASSIGN2;
result = pg_query_parse_protobuf_opts_internal(input, parser_options);
}
if (result.error) {
pg_query_free_protobuf_parse_result(result);
parser_options = (parser_options & ~PG_QUERY_PARSE_PLPGSQL_ASSIGN2) | PG_QUERY_PARSE_PLPGSQL_ASSIGN3;
result = pg_query_parse_protobuf_opts_internal(input, parser_options);
}
return result;
} else {
return pg_query_parse_protobuf_opts_internal(input, parser_options);
}
}

void pg_query_free_parse_result(PgQueryParseResult result)
{
if (result.error) {
Expand Down
33 changes: 32 additions & 1 deletion test/fingerprint_opts_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,37 @@ const char* tests[] = {
"NEW.author.first_name = upper(cleanString(NEW.author.first_name))",
"5",
"a148e3f78b53c252",
// PG_QUERY_PARSE_ALL
"SELECT 1",
"6",
"50fde20626009aba",
"integer",
"6",
"c71927729d707de5",
"character varying(32)",
"6",
"453ab4df8fd3eea9",
"EXISTS(SELECT 1)",
"6",
"976a797c8ca2985b",
"v_version IS NULL",
"6",
"6b292a26fcb78b1c",
"pos:= instr($1, $2, 1)",
"6",
"786552659cc61f6f",
"temp_str := substring(string FROM beg_index)",
"6",
"d6671d73f1654866",
"v3.c1 := 4",
"6",
"7f65202632663ba0",
"NEW.name = upper(cleanString(NEW.name))",
"6",
"184cff1a84037010",
"NEW.author.first_name = upper(cleanString(NEW.author.first_name))",
"6",
"b7de0b0d4f636a16",
};

size_t testsLength = __LINE__ - 4;
size_t testsLength = __LINE__ - 5;
36 changes: 36 additions & 0 deletions test/normalize_opts.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <pg_query.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include "normalize_opts_tests.c"

int main() {
size_t i;
bool ret_code = 0;

for (i = 0; i < testsLength; i += 3) {
PgQueryParseMode mode = atoi(tests[i + 1]);
PgQueryNormalizeResult result = pg_query_normalize_opts(tests[i], mode);

if (result.error) {
ret_code = -1;
printf("%s\n", result.error->message);
} else if (strcmp(result.normalized_query, tests[i + 2]) == 0) {
printf(".");
} else {
ret_code = -1;
printf("INVALID result for \"%s\" with %d mode\nexpected: %s\nactual: %s\n", tests[i], mode, tests[i + 2], result.normalized_query);
}

pg_query_free_normalize_result(result);
}

printf("\n");

pg_query_exit();

return ret_code;
}
Loading

0 comments on commit 5e8e676

Please sign in to comment.