Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to automatically try all parse modes #228

Open
wants to merge 1 commit into
base: 15-latest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading