diff --git a/.gitignore b/.gitignore index 5f320877..ee36d506 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,12 @@ pg_query-*.tar # compiled nif priv/*.so + +# Fuzz build outputs (compiled binaries) +fuzz/_build/ + +# Generated deparse corpus - rebuild with: make fuzz-corpus +fuzz/corpus/deparse/ + +# libFuzzer-discovered corpus entries (hash-named files added during fuzzing runs) +fuzz/corpus/parse/[0-9a-f][0-9a-f][0-9a-f][0-9a-f]* diff --git a/Makefile b/Makefile index b5bbccf3..c5ccb921 100644 --- a/Makefile +++ b/Makefile @@ -11,19 +11,75 @@ ifeq ($(shell uname -s),Darwin) LDFLAGS += -undefined dynamic_lookup endif -.PHONY: all libpg_query_ex clean update-libpg_query +FUZZ_CC = clang +FUZZ_CFLAGS = -g -O1 -fsanitize=fuzzer,address -I$(LIBPG_QUERY_PATH) +FUZZ_LDFLAGS = -fsanitize=fuzzer,address -lpthread +FUZZ_SRCS = fuzz/fuzz_parse_protobuf.c \ + fuzz/fuzz_scan.c \ + fuzz/fuzz_deparse.c \ + fuzz/fuzz_roundtrip.c +FUZZ_BINS = $(patsubst fuzz/%.c,fuzz/_build/%,$(FUZZ_SRCS)) + +.PHONY: all libpg_query_ex clean fuzz fuzz-corpus fuzz-clean patch update-libpg_query all: priv/libpg_query_ex.so -priv: - mkdir -p priv + +fuzz/_build: + mkdir -p fuzz/_build $(LIBPG_QUERY_PATH)/libpg_query.a: $(MAKE) -B -C $(LIBPG_QUERY_PATH) libpg_query.a -priv/libpg_query_ex.so: priv $(LIBPG_QUERY_PATH)/libpg_query.a c_src/libpg_query_ex.c +priv/libpg_query_ex.so: $(LIBPG_QUERY_PATH)/libpg_query.a c_src/libpg_query_ex.c + mkdir -p priv $(CC) $(CFLAGS) $(LDFLAGS) -o $@ c_src/libpg_query_ex.c $(LIBPG_QUERY_PATH)/libpg_query.a +# Build all fuzz targets (requires clang with libFuzzer) +fuzz: fuzz/_build $(LIBPG_QUERY_PATH)/libpg_query.a $(FUZZ_BINS) + @echo "" + @echo "Fuzz targets built in fuzz/_build/. Next steps:" + @echo " 1. Populate the deparse corpus: make fuzz-corpus" + @echo " 2. Run a fuzzer, e.g.:" + @echo " fuzz/_build/fuzz_parse_protobuf -max_len=65536 fuzz/corpus/parse/" + @echo " fuzz/_build/fuzz_deparse -max_len=65536 fuzz/corpus/deparse/" + +fuzz/_build/%: fuzz/%.c $(LIBPG_QUERY_PATH)/libpg_query.a + $(FUZZ_CC) $(FUZZ_CFLAGS) -o $@ $< $(LIBPG_QUERY_PATH)/libpg_query.a $(FUZZ_LDFLAGS) + +# Also build the corpus generator (not a fuzz target, no -fsanitize=fuzzer) +fuzz/_build/gen_deparse_corpus: fuzz/gen_deparse_corpus.c $(LIBPG_QUERY_PATH)/libpg_query.a + $(FUZZ_CC) -g -O1 -fsanitize=address -I$(LIBPG_QUERY_PATH) -o $@ $< \ + $(LIBPG_QUERY_PATH)/libpg_query.a -fsanitize=address -lpthread + +# Generate binary protobuf seeds for fuzz_deparse from the SQL corpus +fuzz-corpus: fuzz/_build/gen_deparse_corpus + @mkdir -p fuzz/corpus/deparse + fuzz/_build/gen_deparse_corpus fuzz/corpus/deparse \ + "SELECT 1" \ + "SELECT id, name FROM users WHERE active = true" \ + "SELECT u.id, o.total FROM users u JOIN orders o ON u.id = o.user_id" \ + "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')" \ + "UPDATE users SET active = false WHERE last_login < NOW() - INTERVAL '90 days'" \ + "DELETE FROM sessions WHERE expires_at < NOW()" \ + "WITH recent AS (SELECT * FROM events WHERE created_at > NOW() - INTERVAL '1 hour') SELECT count(*) FROM recent" \ + "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100)" \ + "SELECT department, count(*), avg(salary) FROM employees GROUP BY department HAVING count(*) > 5" \ + "SELECT id, salary, rank() OVER (PARTITION BY department ORDER BY salary DESC) FROM employees" \ + "SELECT id::text, created_at::date, price::numeric(10,2) FROM products" \ + "SELECT CASE WHEN status = 1 THEN 'active' WHEN status = 2 THEN 'pending' ELSE 'unknown' END FROM orders" \ + "SELECT ARRAY[1,2,3], unnest(tags) FROM posts" \ + "SELECT data->>'name', data->'address'->>'city' FROM profiles WHERE data @> '{\"active\":true}'" \ + "SELECT id FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id)" \ + "SELECT * FROM events WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'" \ + "SELECT * FROM users WHERE email ILIKE '%@example.com' AND name NOT LIKE 'test%'" \ + "SELECT * FROM users WHERE deleted_at IS NULL AND parent_id IS NOT NULL" \ + "SELECT * FROM users WHERE id = \$$1 AND status = \$$2" \ + "SELECT id FROM admins UNION ALL SELECT id FROM moderators EXCEPT SELECT id FROM banned_users" + +fuzz-clean: + $(RM) -r fuzz/_build fuzz/corpus/deparse fuzz/crashes + protobuf: MIX_ENV=prod mix protox.generate --output-path=lib/pg_query/proto --multiple-files c_src/libpg_query/protobuf/pg_query.proto @@ -32,6 +88,15 @@ clean: $(MAKE) -C $(LIBPG_QUERY_PATH) clean $(RM) priv/libpg_query_ex.so +# Apply all local patches to the vendored libpg_query source +patch: + @for p in patches/*.patch; do \ + echo "Applying $$p ..."; \ + git apply "$$p" || { echo "FAILED: $$p"; exit 1; }; \ + done + @echo "All patches applied." + update-libpg_query: - git subtree pull -P "c_src/libpg_query" --squash https://github.com/pganalyze/libpg_query.git 15-latest + git subtree pull -P "c_src/libpg_query" --squash https://github.com/pganalyze/libpg_query.git 17-latest + $(MAKE) patch diff --git a/README.md b/README.md index 9006e878..48f6da63 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,46 @@ def deps do end ``` +## Fuzzing + +The `fuzz/` directory contains [libFuzzer](https://llvm.org/docs/LibFuzzer.html) harnesses that exercise the NIF boundary. You need clang with libFuzzer support (standard in most LLVM distributions). + +Build all four targets: + +```bash +make fuzz +``` + +Optionally seed the deparse corpus from known-good SQL strings: + +```bash +make fuzz-corpus +``` + +Then run a target, for example: + +```bash +# Fuzz the parse → deparse round-trip (highest-value target) +fuzz/_build/fuzz_roundtrip -max_len=4096 -artifact_prefix=fuzz/crashes/ fuzz/corpus/parse/ + +# Fuzz raw protobuf bytes fed directly into the deparser +fuzz/_build/fuzz_deparse -max_len=65536 -artifact_prefix=fuzz/crashes/ fuzz/corpus/deparse/ + +# Fuzz the SQL parser +fuzz/_build/fuzz_parse_protobuf -max_len=4096 -artifact_prefix=fuzz/crashes/ fuzz/corpus/parse/ + +# Fuzz the SQL scanner +fuzz/_build/fuzz_scan -max_len=4096 -artifact_prefix=fuzz/crashes/ fuzz/corpus/parse/ +``` + +Crash artifacts are written to `fuzz/crashes/` (the `-artifact_prefix` flag controls this; without it libFuzzer writes to the current directory). Replay a crash by passing the file as a positional argument: + +```bash +fuzz/_build/fuzz_roundtrip fuzz/crashes/ +``` + +Clean up build artefacts and generated corpus with `make fuzz-clean`. + ## License This Elixir interface is distributed under the terms of the [Apache 2.0 license](./LICENSE). diff --git a/c_src/libpg_query/.gitattributes b/c_src/libpg_query/.gitattributes index 0c9fe52d..d9268bdd 100644 --- a/c_src/libpg_query/.gitattributes +++ b/c_src/libpg_query/.gitattributes @@ -1 +1,2 @@ -*.sql binary \ No newline at end of file +*.sql binary +*.psql binary \ No newline at end of file diff --git a/c_src/libpg_query/.github/workflows/ci.yml b/c_src/libpg_query/.github/workflows/ci.yml index 5e2c1147..c5632e25 100644 --- a/c_src/libpg_query/.github/workflows/ci.yml +++ b/c_src/libpg_query/.github/workflows/ci.yml @@ -8,10 +8,15 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04] + os: [ubuntu-24.04] compiler: [clang, gcc] protobuf_lib: [protobuf-c, protobuf-cpp] valgrind: [valgrind,no-valgrind] + exclude: + # this combination hits linking errors: see https://github.com/pganalyze/libpg_query/pull/289 + - compiler: clang + protobuf_lib: protobuf-cpp + valgrind: valgrind steps: - name: Check out code uses: actions/checkout@v4 @@ -21,7 +26,7 @@ jobs: uses: actions/cache@v4 with: path: protobuf-25.1 - key: ${{ runner.os }}-protobuf-25.1 + key: ${{ runner.os }}-${{ matrix.compiler }}-protobuf-25.1 - name: Build protobuf library if: matrix.protobuf_lib == 'protobuf-cpp' && steps.cache-protobuf.outputs.cache-hit != 'true' run: | diff --git a/c_src/libpg_query/CHANGELOG.md b/c_src/libpg_query/CHANGELOG.md index 739674c7..87c8e5b8 100644 --- a/c_src/libpg_query/CHANGELOG.md +++ b/c_src/libpg_query/CHANGELOG.md @@ -2,6 +2,50 @@ All versions are tagged by the major Postgres version, plus an individual semver for this library itself. +## 17-6.2.2 2026-01-26 + +* pg_query_normalize: Fix handling of special strings in DefElem [#325](https://github.com/pganalyze/libpg_query/pull/325) + - This avoids a crash when running the normalize function on certain utility statements +* pg_query_deparse_comments_for_query: Add missing initialization [#324](https://github.com/pganalyze/libpg_query/pull/324) + - This avoids a crash for callers that read the error field of the result when there is no error + +## 17-6.2.1 2026-01-14 + +* Add pg_query_is_utility_stmt function to determine if query text contains utility statements [#313](https://github.com/pganalyze/libpg_query/pull/313) + * This is a fast check for callers that don't actually need the parse tree itself +* Add missing top-level postgres_deparse.h in Makefile install step + - This was an oversight from the previous 6.2.0 release +* Improve pg_query_summary function: + - Speed up summary truncate replacement logic + - Correctly handle `GRANT .. ON ALL TABLES IN SCHEMA` statements + - Correctly handle schema qualified filter columns + +## 17-6.2.0 2025-12-10 + +* Add fast summary information function (pg_query_summary) + - This allows gathering certain information, for example which tables are referenced in a + statement, without requiring a Protobuf serialization step in a higher level library + - Additionally this can also be used to perform "smart truncation" of a query by + omitting deeply nested information (e.g. a CTE definition, or a target list) whilst + preserving more essential parts like the FROM claus +* Deparser: + - Introduce pretty printing / formatting + - Introduces a new optional pretty print mode that emits a human readable + output. A detailed explanation of the mechanism can be found at the start + of the deparser file. + - Rework handling of expressions inside typecasts + - Prefer (..)::type syntax, unless we are already in a function call. + - Use lowercase keywords in xmlroot functions + - This matches other XML functions as well as the Postgres documentation, + since these are closer to function argument names than regular keywords. + - Fix deparse of ALTER TABLE a ALTER b SET STATISTICS DEFAULT + - Fix the null pointer dereference when handling identity columns +* Allow alternate definitions of NAMEDATALEN identifier limit + - This allows building libpg_query with an override of the built-time limit of + Postgres identifiers (typically 63 characters) +* Normalization: Add support for CALL statements +* Bump Postgres to 17.7 and switch back to release tarballs + ## 17-6.1.0 2025-04-02 * Update to Postgres 17.4, and add recent patches scheduled for Postgres 17.5 (not yet released) diff --git a/c_src/libpg_query/Makefile b/c_src/libpg_query/Makefile index 2e224986..328036c4 100644 --- a/c_src/libpg_query/Makefile +++ b/c_src/libpg_query/Makefile @@ -7,13 +7,12 @@ PGDIR = $(root_dir)/tmp/postgres PGDIRBZ2 = $(root_dir)/tmp/postgres.tar.bz2 PGDIRZIP = $(root_dir)/tmp/postgres.zip -PG_VERSION = 17.4 +PG_VERSION = 17.7 PG_VERSION_MAJOR = $(call word-dot,$(PG_VERSION),1) -PG_VERSION_NUM = 170004 -PG_BRANCH = REL_17_STABLE +PG_VERSION_NUM = 170007 PROTOC_VERSION = 25.1 -VERSION = 6.1.0 +VERSION = 6.2.2 VERSION_MAJOR = $(call word-dot,$(VERSION),1) VERSION_MINOR = $(call word-dot,$(VERSION),2) VERSION_PATCH = $(call word-dot,$(VERSION),3) @@ -39,6 +38,7 @@ override CFLAGS += -g -I. -I./vendor -I./src/include -I./src/postgres/include -W ifeq ($(OS),Windows_NT) override CFLAGS += -I./src/postgres/include/port/win32 +override TEST_CFLAGS += -I./src/postgres/include/port/win32 endif override PG_CONFIGURE_FLAGS += -q --without-readline --without-zlib --without-icu @@ -116,14 +116,9 @@ clean: .PHONY: all clean build build_shared extract_source examples test install $(PGDIR): -# We temporarily build off REL_17_STABLE to pull in https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=6da2ba1d8a031984eb016fed6741bb2ac945f19d -# TODO: Go back to upstream tarball once 17.5 is released -# tar -xjf $(PGDIRBZ2) -# curl -o $(PGDIRBZ2) https://ftp.postgresql.org/pub/source/v$(PG_VERSION)/postgresql-$(PG_VERSION).tar.bz2 -# mv $(root_dir)/postgresql-$(PG_VERSION) $(PGDIR) - curl -L -o $(PGDIRZIP) https://github.com/postgres/postgres/archive/refs/heads/$(PG_BRANCH).zip - unzip $(PGDIRZIP) - mv $(root_dir)/postgres-$(PG_BRANCH) $(PGDIR) + curl -o $(PGDIRBZ2) https://ftp.postgresql.org/pub/source/v$(PG_VERSION)/postgresql-$(PG_VERSION).tar.bz2 + tar -xjf $(PGDIRBZ2) + mv $(root_dir)/postgresql-$(PG_VERSION) $(PGDIR) cd $(PGDIR); patch -p1 < $(root_dir)/patches/01_parser_additional_param_ref_support.patch cd $(PGDIR); patch -p1 < $(root_dir)/patches/03_lexer_track_yyllocend.patch cd $(PGDIR); patch -p1 < $(root_dir)/patches/04_lexer_comments_as_tokens.patch @@ -133,6 +128,7 @@ $(PGDIR): cd $(PGDIR); patch -p1 < $(root_dir)/patches/08_avoid_zero_length_delimiter_in_regression_tests.patch cd $(PGDIR); patch -p1 < $(root_dir)/patches/09_allow_param_junk.patch cd $(PGDIR); patch -p1 < $(root_dir)/patches/10_avoid_namespace_hashtab_impl_gen.patch + cd $(PGDIR); patch -p1 < $(root_dir)/patches/11_ifndef_namedatalen.patch cd $(PGDIR); ./configure $(PG_CONFIGURE_FLAGS) cd $(PGDIR); make -C src/pl/plpgsql/src pl_gram.h plerrcodes.h pl_reserved_kwlist_d.h pl_unreserved_kwlist_d.h cd $(PGDIR); make -C src/port pg_config_paths.h @@ -241,7 +237,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/normalize_utility 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/is_utility_stmt test/normalize test/normalize_utility test/parse test/parse_opts test/parse_protobuf test/parse_protobuf_opts test/parse_plpgsql test/scan test/split test/summary test/summary_truncate test: $(TESTS) ifeq ($(VALGRIND),1) $(VALGRIND_MEMCHECK) test/complex || (cat test/valgrind.log && false) @@ -249,6 +245,7 @@ ifeq ($(VALGRIND),1) $(VALGRIND_MEMCHECK) test/deparse || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/fingerprint || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/fingerprint_opts || (cat test/valgrind.log && false) + $(VALGRIND_MEMCHECK) test/is_utility_stmt || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/normalize || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/normalize_utility || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/parse || (cat test/valgrind.log && false) @@ -257,6 +254,8 @@ ifeq ($(VALGRIND),1) $(VALGRIND_MEMCHECK) test/parse_protobuf_opts || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/scan || (cat test/valgrind.log && false) $(VALGRIND_MEMCHECK) test/split || (cat test/valgrind.log && false) + $(VALGRIND_MEMCHECK) test/summary || (cat test/valgrind.log && false) + $(VALGRIND_MEMCHECK) test/summary_truncate || (cat test/valgrind.log && false) # Output-based tests $(VALGRIND_MEMCHECK) test/parse_plpgsql || (cat test/valgrind.log && false) diff -Naur test/plpgsql_samples.expected.json test/plpgsql_samples.actual.json @@ -266,6 +265,7 @@ else test/deparse test/fingerprint test/fingerprint_opts + test/is_utility_stmt test/normalize test/normalize_utility test/parse @@ -274,6 +274,8 @@ else test/parse_protobuf_opts test/scan test/split + test/summary + test/summary_truncate # Output-based tests test/parse_plpgsql diff -Naur test/plpgsql_samples.expected.json test/plpgsql_samples.actual.json @@ -297,6 +299,10 @@ test/fingerprint_opts: test/fingerprint_opts.c test/fingerprint_opts_tests.c $(A # We have "-Isrc/" because this test uses pg_query_fingerprint_with_opts $(CC) $(TEST_CFLAGS) -o $@ -Isrc/ test/fingerprint_opts.c $(ARLIB) $(TEST_LDFLAGS) +test/is_utility_stmt: test/framework/main.c test/is_utility_stmt.c $(ARLIB) + # We have "-Isrc/postgres/include" because this test uses pg_query_summary_direct + $(CC) $(TEST_CFLAGS) -o $@ -Isrc/postgres/include test/framework/main.c test/is_utility_stmt.c $(ARLIB) $(TEST_LDFLAGS) + test/normalize: test/normalize.c test/normalize_tests.c $(ARLIB) $(CC) $(TEST_CFLAGS) -o $@ test/normalize.c $(ARLIB) $(TEST_LDFLAGS) @@ -306,6 +312,14 @@ test/normalize_utility: test/normalize_utility.c test/normalize_utility_tests.c test/parse: test/parse.c test/parse_tests.c $(ARLIB) $(CC) $(TEST_CFLAGS) -o $@ test/parse.c $(ARLIB) $(TEST_LDFLAGS) +test/summary: test/framework/main.c test/summary.c test/summary_tests.c test/summary_tests_list.c $(ARLIB) + # We have "-Isrc/postgres/include" because this test uses pg_query_summary_direct + $(CC) $(TEST_CFLAGS) -o $@ -Isrc/postgres/include test/framework/main.c test/summary.c $(ARLIB) $(TEST_LDFLAGS) + +test/summary_truncate: test/framework/main.c test/summary_truncate.c $(ARLIB) + # We have "-Isrc/postgres/include" because this test uses pg_query_summary_direct + $(CC) $(TEST_CFLAGS) -o $@ -Isrc/postgres/include test/framework/main.c test/summary_truncate.c $(ARLIB) $(TEST_LDFLAGS) + test/parse_opts: test/parse_opts.c test/parse_opts_tests.c $(ARLIB) $(CC) $(TEST_CFLAGS) -o $@ test/parse_opts.c $(ARLIB) $(TEST_LDFLAGS) @@ -336,4 +350,5 @@ install: $(ARLIB) $(SOLIB) $(LN_S) $(SOLIBVER) "$(DESTDIR)"$(libdir)/$(SOLIB) $(INSTALL) -d "$(DESTDIR)"$(includedir)/$(TARGET) $(INSTALL) -m 644 pg_query.h "$(DESTDIR)"$(includedir)/pg_query.h + $(INSTALL) -m 644 postgres_deparse.h "$(DESTDIR)"$(includedir)/postgres_deparse.h $(INSTALL) -m 644 protobuf/pg_query.proto "$(DESTDIR)"$(includedir)/$(TARGET)/pg_query.proto diff --git a/c_src/libpg_query/Makefile.msvc b/c_src/libpg_query/Makefile.msvc index 0e5d0332..8ed84b8d 100644 --- a/c_src/libpg_query/Makefile.msvc +++ b/c_src/libpg_query/Makefile.msvc @@ -50,11 +50,12 @@ examples/normalize_error: examples/normalize_error.c $(ARLIB) examples/simple_plpgsql: examples/simple_plpgsql.c $(ARLIB) $(CC) $(CFLAGS) -o $@ examples/simple_plpgsql.c $(ARLIB) -TESTS = 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/deparse test/fingerprint test/fingerprint_opts test/is_utility_stmt test/normalize test/parse test/parse_opts test/parse_protobuf test/parse_protobuf_opts test/parse_plpgsql test/scan test/split test/summary test/summary_truncate test: $(TESTS) .\test\deparse .\test\fingerprint .\test\fingerprint_opts + .\test\is_utility_stmt .\test\normalize .\test\parse .\test\parse_opts @@ -62,6 +63,8 @@ test: $(TESTS) .\test\parse_protobuf_opts .\test\scan .\test\split + .\test\summary + .\test\summary_truncate # Doesn't work because of C2026: string too big, trailing characters truncated #test/complex: test/complex.c $(ARLIB) @@ -83,6 +86,9 @@ test/fingerprint_opts: test/fingerprint_opts.c test/fingerprint_opts_tests.c $(A # We have "-Isrc/" because this test uses pg_query_fingerprint_with_opts $(CC) $(CFLAGS) -o $@ -Isrc/ test/fingerprint_opts.c $(ARLIB) +test/is_utility_stmt: test/framework/main.c test/is_utility_stmt.c $(ARLIB) + $(CC) $(CFLAGS) -o $@ test/framework/main.c test/is_utility_stmt.c $(ARLIB) + test/normalize: test/normalize.c test/normalize_tests.c $(ARLIB) $(CC) $(CFLAGS) -o $@ test/normalize.c $(ARLIB) @@ -106,3 +112,9 @@ test/scan: test/scan.c test/scan_tests.c $(ARLIB) test/split: test/split.c test/split_tests.c $(ARLIB) $(CC) $(CFLAGS) -o $@ test/split.c $(ARLIB) + +test/summary: test/framework/main.c test/summary.c test/summary_tests.c test/summary_tests_list.c $(ARLIB) + $(CC) $(CFLAGS) -o $@ test/framework/main.c test/summary.c $(ARLIB) + +test/summary_truncate: test/framework/main.c test/summary_truncate.c $(ARLIB) + $(CC) $(CFLAGS) -o $@ test/framework/main.c test/summary_truncate.c $(ARLIB) diff --git a/c_src/libpg_query/README.md b/c_src/libpg_query/README.md index c35af470..5e195f11 100644 --- a/c_src/libpg_query/README.md +++ b/c_src/libpg_query/README.md @@ -44,6 +44,8 @@ int main() { printf("%s\n", result.parse_tree); pg_query_free_parse_result(result); + + return 0; } ``` @@ -57,7 +59,7 @@ This will output the parse tree (whitespace adjusted here for better readability ```json { - "version": 170004, + "version": 170007, "stmts": [ { "stmt": { @@ -110,9 +112,9 @@ int main() { const char *input = "SELECT update AS left /* comment */ FROM between"; result = pg_query_scan(input); - scan_result = pg_query__scan_result__unpack(NULL, result.pbuf.len, (void *) result.pbuf.data); + scan_result = pg_query__scan_result__unpack(NULL, result.pbuf.len, (const uint8_t *) result.pbuf.data); - printf(" version: %d, tokens: %ld, size: %d\n", scan_result->version, scan_result->n_tokens, result.pbuf.len); + printf(" version: %d, tokens: %ld, size: %zu\n", scan_result->version, scan_result->n_tokens, result.pbuf.len); for (size_t j = 0; j < scan_result->n_tokens; j++) { scan_token = scan_result->tokens[j]; token_kind = protobuf_c_enum_descriptor_get_value(&pg_query__token__descriptor, scan_token->token); @@ -130,7 +132,7 @@ int main() { This will output the following: ``` - version: 170004, tokens: 7, size: 77 + version: 170007, tokens: 7, size: 77 "SELECT" = [ 0, 6, SELECT, RESERVED_KEYWORD ] "update" = [ 7, 13, UPDATE, UNRESERVED_KEYWORD ] "AS" = [ 14, 16, AS, RESERVED_KEYWORD ] @@ -174,6 +176,8 @@ int main() { printf("%s\n", result.fingerprint_str); pg_query_free_fingerprint_result(result); + + return 0; } ``` diff --git a/c_src/libpg_query/patches/11_ifndef_namedatalen.patch b/c_src/libpg_query/patches/11_ifndef_namedatalen.patch new file mode 100644 index 00000000..7aade806 --- /dev/null +++ b/c_src/libpg_query/patches/11_ifndef_namedatalen.patch @@ -0,0 +1,14 @@ +diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h +index a1a93ad..c978d76 100644 +--- a/src/include/pg_config_manual.h ++++ b/src/include/pg_config_manual.h +@@ -26,7 +26,9 @@ + * + * Changing this requires an initdb. + */ ++#ifndef NAMEDATALEN + #define NAMEDATALEN 64 ++#endif + + /* + * Maximum number of arguments to a function. diff --git a/c_src/libpg_query/pg_query.h b/c_src/libpg_query/pg_query.h index e8353fe3..def0254e 100644 --- a/c_src/libpg_query/pg_query.h +++ b/c_src/libpg_query/pg_query.h @@ -1,9 +1,12 @@ #ifndef PG_QUERY_H #define PG_QUERY_H +#include #include #include +#include "postgres_deparse.h" + typedef struct { char* message; // exception message char* funcname; // source function of exception (e.g. SearchSysCache) @@ -13,6 +16,12 @@ typedef struct { char* context; // additional context (optional, can be NULL) } PgQueryError; +typedef struct { + int length; + bool *items; + PgQueryError* error; +} PgQueryIsUtilityResult; + typedef struct { size_t len; char* data; @@ -53,6 +62,12 @@ typedef struct { PgQueryError* error; } PgQueryDeparseResult; +typedef struct { + PostgresDeparseComment **comments; + size_t comment_count; + PgQueryError* error; +} PgQueryDeparseCommentsResult; + typedef struct { char* plpgsql_funcs; PgQueryError* error; @@ -70,6 +85,12 @@ typedef struct { PgQueryError* error; } PgQueryNormalizeResult; +typedef struct { + PgQueryProtobuf summary; + char* stderr_buffer; + PgQueryError* error; +} PgQuerySummaryParseResult; + // Postgres parser options (parse mode and GUCs that affect parsing) typedef enum @@ -118,23 +139,32 @@ PgQuerySplitResult pg_query_split_with_scanner(const char *input); PgQuerySplitResult pg_query_split_with_parser(const char *input); PgQueryDeparseResult pg_query_deparse_protobuf(PgQueryProtobuf parse_tree); +PgQueryDeparseResult pg_query_deparse_protobuf_opts(PgQueryProtobuf parse_tree, struct PostgresDeparseOpts opts); +PgQueryDeparseCommentsResult pg_query_deparse_comments_for_query(const char *query); + +PgQueryIsUtilityResult pg_query_is_utility_stmt(const char *query); + +PgQuerySummaryParseResult pg_query_summary(const char* input, int parser_options, int truncate_limit); void pg_query_free_normalize_result(PgQueryNormalizeResult result); void pg_query_free_scan_result(PgQueryScanResult result); void pg_query_free_parse_result(PgQueryParseResult result); void pg_query_free_split_result(PgQuerySplitResult result); void pg_query_free_deparse_result(PgQueryDeparseResult result); +void pg_query_free_deparse_comments_result(PgQueryDeparseCommentsResult result); void pg_query_free_protobuf_parse_result(PgQueryProtobufParseResult result); void pg_query_free_plpgsql_parse_result(PgQueryPlpgsqlParseResult result); void pg_query_free_fingerprint_result(PgQueryFingerprintResult result); +void pg_query_free_is_utility_result(PgQueryIsUtilityResult result); +void pg_query_free_summary_parse_result(PgQuerySummaryParseResult result); // Optional, cleans up the top-level memory context (automatically done for threads that exit) void pg_query_exit(void); // Postgres version information #define PG_MAJORVERSION "17" -#define PG_VERSION "17.4" -#define PG_VERSION_NUM 170004 +#define PG_VERSION "17.7" +#define PG_VERSION_NUM 170007 // Deprecated APIs below diff --git a/c_src/libpg_query/postgres_deparse.h b/c_src/libpg_query/postgres_deparse.h new file mode 100644 index 00000000..05d7490c --- /dev/null +++ b/c_src/libpg_query/postgres_deparse.h @@ -0,0 +1,34 @@ +#ifndef POSTGRES_DEPARSE_H +#define POSTGRES_DEPARSE_H + +#include +#include + +typedef struct PostgresDeparseComment { + int match_location; // Insert comment before a node, once we find a node whose location field is equal-or-higher than this location + int newlines_before_comment; // Insert newlines before inserting the comment (set to non-zero if the source comment was separated from the prior token by at least one newline) + int newlines_after_comment; // Insert newlines after inserting the comment (set to non-zero if the source comment was separated from the next token by at least one newline) + char *str; // The actual comment string, including comment start/end tokens, and newline characters in comment (if any) +} PostgresDeparseComment; + +typedef struct PostgresDeparseOpts { + PostgresDeparseComment **comments; + size_t comment_count; + + // Pretty print options + bool pretty_print; + int indent_size; // Indentation size (Default 4 spaces) + int max_line_length; // Restricts the line length of certain lists of items (Default 80 characters) + bool trailing_newline; // Whether to add a trailing newline at the end of the output (Default off) + bool commas_start_of_line; // Place separating commas at start of line (Default off) +} PostgresDeparseOpts; + +/* Forward declarations to allow referencing the structs in this include file without needing Postgres includes */ +struct StringInfoData; +typedef struct StringInfoData *StringInfo; +struct RawStmt; + +extern void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt); +extern void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts opts); + +#endif diff --git a/c_src/libpg_query/protobuf/pg_query.pb-c.c b/c_src/libpg_query/protobuf/pg_query.pb-c.c index 64470632..b485bf83 100644 --- a/c_src/libpg_query/protobuf/pg_query.pb-c.c +++ b/c_src/libpg_query/protobuf/pg_query.pb-c.c @@ -12247,6 +12247,75 @@ void pg_query__scan_token__free_unpacked assert(message->base.descriptor == &pg_query__scan_token__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } +void pg_query__summary_result__table__init + (PgQuery__SummaryResult__Table *message) +{ + static const PgQuery__SummaryResult__Table init_value = PG_QUERY__SUMMARY_RESULT__TABLE__INIT; + *message = init_value; +} +void pg_query__summary_result__aliases_entry__init + (PgQuery__SummaryResult__AliasesEntry *message) +{ + static const PgQuery__SummaryResult__AliasesEntry init_value = PG_QUERY__SUMMARY_RESULT__ALIASES_ENTRY__INIT; + *message = init_value; +} +void pg_query__summary_result__function__init + (PgQuery__SummaryResult__Function *message) +{ + static const PgQuery__SummaryResult__Function init_value = PG_QUERY__SUMMARY_RESULT__FUNCTION__INIT; + *message = init_value; +} +void pg_query__summary_result__filter_column__init + (PgQuery__SummaryResult__FilterColumn *message) +{ + static const PgQuery__SummaryResult__FilterColumn init_value = PG_QUERY__SUMMARY_RESULT__FILTER_COLUMN__INIT; + *message = init_value; +} +void pg_query__summary_result__init + (PgQuery__SummaryResult *message) +{ + static const PgQuery__SummaryResult init_value = PG_QUERY__SUMMARY_RESULT__INIT; + *message = init_value; +} +size_t pg_query__summary_result__get_packed_size + (const PgQuery__SummaryResult *message) +{ + assert(message->base.descriptor == &pg_query__summary_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t pg_query__summary_result__pack + (const PgQuery__SummaryResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &pg_query__summary_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t pg_query__summary_result__pack_to_buffer + (const PgQuery__SummaryResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &pg_query__summary_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +PgQuery__SummaryResult * + pg_query__summary_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (PgQuery__SummaryResult *) + protobuf_c_message_unpack (&pg_query__summary_result__descriptor, + allocator, len, data); +} +void pg_query__summary_result__free_unpacked + (PgQuery__SummaryResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &pg_query__summary_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} static const ProtobufCFieldDescriptor pg_query__parse_result__field_descriptors[2] = { { @@ -40673,6 +40742,425 @@ const ProtobufCMessageDescriptor pg_query__scan_token__descriptor = (ProtobufCMessageInit) pg_query__scan_token__init, NULL,NULL,NULL /* reserved[123] */ }; +static const ProtobufCFieldDescriptor pg_query__summary_result__table__field_descriptors[4] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Table, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "schema_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Table, schema_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "table_name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Table, table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "context", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Table, context), + &pg_query__summary_result__context__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned pg_query__summary_result__table__field_indices_by_name[] = { + 3, /* field[3] = context */ + 0, /* field[0] = name */ + 1, /* field[1] = schema_name */ + 2, /* field[2] = table_name */ +}; +static const ProtobufCIntRange pg_query__summary_result__table__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor pg_query__summary_result__table__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "pg_query.SummaryResult.Table", + "Table", + "PgQuery__SummaryResult__Table", + "pg_query", + sizeof(PgQuery__SummaryResult__Table), + 4, + pg_query__summary_result__table__field_descriptors, + pg_query__summary_result__table__field_indices_by_name, + 1, pg_query__summary_result__table__number_ranges, + (ProtobufCMessageInit) pg_query__summary_result__table__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor pg_query__summary_result__aliases_entry__field_descriptors[2] = +{ + { + "key", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__AliasesEntry, key), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "value", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__AliasesEntry, value), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned pg_query__summary_result__aliases_entry__field_indices_by_name[] = { + 0, /* field[0] = key */ + 1, /* field[1] = value */ +}; +static const ProtobufCIntRange pg_query__summary_result__aliases_entry__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor pg_query__summary_result__aliases_entry__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "pg_query.SummaryResult.AliasesEntry", + "AliasesEntry", + "PgQuery__SummaryResult__AliasesEntry", + "pg_query", + sizeof(PgQuery__SummaryResult__AliasesEntry), + 2, + pg_query__summary_result__aliases_entry__field_descriptors, + pg_query__summary_result__aliases_entry__field_indices_by_name, + 1, pg_query__summary_result__aliases_entry__number_ranges, + (ProtobufCMessageInit) pg_query__summary_result__aliases_entry__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor pg_query__summary_result__function__field_descriptors[4] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Function, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "function_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Function, function_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "schema_name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Function, schema_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "context", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__Function, context), + &pg_query__summary_result__context__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned pg_query__summary_result__function__field_indices_by_name[] = { + 3, /* field[3] = context */ + 1, /* field[1] = function_name */ + 0, /* field[0] = name */ + 2, /* field[2] = schema_name */ +}; +static const ProtobufCIntRange pg_query__summary_result__function__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor pg_query__summary_result__function__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "pg_query.SummaryResult.Function", + "Function", + "PgQuery__SummaryResult__Function", + "pg_query", + sizeof(PgQuery__SummaryResult__Function), + 4, + pg_query__summary_result__function__field_descriptors, + pg_query__summary_result__function__field_indices_by_name, + 1, pg_query__summary_result__function__number_ranges, + (ProtobufCMessageInit) pg_query__summary_result__function__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor pg_query__summary_result__filter_column__field_descriptors[3] = +{ + { + "schema_name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__FilterColumn, schema_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "table_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__FilterColumn, table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "column", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult__FilterColumn, column), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned pg_query__summary_result__filter_column__field_indices_by_name[] = { + 2, /* field[2] = column */ + 0, /* field[0] = schema_name */ + 1, /* field[1] = table_name */ +}; +static const ProtobufCIntRange pg_query__summary_result__filter_column__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor pg_query__summary_result__filter_column__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "pg_query.SummaryResult.FilterColumn", + "FilterColumn", + "PgQuery__SummaryResult__FilterColumn", + "pg_query", + sizeof(PgQuery__SummaryResult__FilterColumn), + 3, + pg_query__summary_result__filter_column__field_descriptors, + pg_query__summary_result__filter_column__field_indices_by_name, + 1, pg_query__summary_result__filter_column__number_ranges, + (ProtobufCMessageInit) pg_query__summary_result__filter_column__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue pg_query__summary_result__context__enum_values_by_number[5] = +{ + { "None", "PG_QUERY__SUMMARY_RESULT__CONTEXT__None", 0 }, + { "Select", "PG_QUERY__SUMMARY_RESULT__CONTEXT__Select", 1 }, + { "DML", "PG_QUERY__SUMMARY_RESULT__CONTEXT__DML", 2 }, + { "DDL", "PG_QUERY__SUMMARY_RESULT__CONTEXT__DDL", 3 }, + { "Call", "PG_QUERY__SUMMARY_RESULT__CONTEXT__Call", 4 }, +}; +static const ProtobufCIntRange pg_query__summary_result__context__value_ranges[] = { +{0, 0},{0, 5} +}; +static const ProtobufCEnumValueIndex pg_query__summary_result__context__enum_values_by_name[5] = +{ + { "Call", 4 }, + { "DDL", 3 }, + { "DML", 2 }, + { "None", 0 }, + { "Select", 1 }, +}; +const ProtobufCEnumDescriptor pg_query__summary_result__context__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "pg_query.SummaryResult.Context", + "Context", + "PgQuery__SummaryResult__Context", + "pg_query", + 5, + pg_query__summary_result__context__enum_values_by_number, + 5, + pg_query__summary_result__context__enum_values_by_name, + 1, + pg_query__summary_result__context__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; +static const ProtobufCFieldDescriptor pg_query__summary_result__field_descriptors[7] = +{ + { + "tables", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(PgQuery__SummaryResult, n_tables), + offsetof(PgQuery__SummaryResult, tables), + &pg_query__summary_result__table__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "aliases", + 2, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(PgQuery__SummaryResult, n_aliases), + offsetof(PgQuery__SummaryResult, aliases), + &pg_query__summary_result__aliases_entry__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cte_names", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(PgQuery__SummaryResult, n_cte_names), + offsetof(PgQuery__SummaryResult, cte_names), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "functions", + 4, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(PgQuery__SummaryResult, n_functions), + offsetof(PgQuery__SummaryResult, functions), + &pg_query__summary_result__function__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "filter_columns", + 5, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(PgQuery__SummaryResult, n_filter_columns), + offsetof(PgQuery__SummaryResult, filter_columns), + &pg_query__summary_result__filter_column__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "statement_types", + 6, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(PgQuery__SummaryResult, n_statement_types), + offsetof(PgQuery__SummaryResult, statement_types), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "truncated_query", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PgQuery__SummaryResult, truncated_query), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned pg_query__summary_result__field_indices_by_name[] = { + 1, /* field[1] = aliases */ + 2, /* field[2] = cte_names */ + 4, /* field[4] = filter_columns */ + 3, /* field[3] = functions */ + 5, /* field[5] = statement_types */ + 0, /* field[0] = tables */ + 6, /* field[6] = truncated_query */ +}; +static const ProtobufCIntRange pg_query__summary_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 7 } +}; +const ProtobufCMessageDescriptor pg_query__summary_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "pg_query.SummaryResult", + "SummaryResult", + "PgQuery__SummaryResult", + "pg_query", + sizeof(PgQuery__SummaryResult), + 7, + pg_query__summary_result__field_descriptors, + pg_query__summary_result__field_indices_by_name, + 1, pg_query__summary_result__number_ranges, + (ProtobufCMessageInit) pg_query__summary_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; static const ProtobufCEnumValue pg_query__query_source__enum_values_by_number[6] = { { "QUERY_SOURCE_UNDEFINED", "PG_QUERY__QUERY_SOURCE__QUERY_SOURCE_UNDEFINED", 0 }, diff --git a/c_src/libpg_query/protobuf/pg_query.pb-c.h b/c_src/libpg_query/protobuf/pg_query.pb-c.h index ca37769d..f5a872a9 100644 --- a/c_src/libpg_query/protobuf/pg_query.pb-c.h +++ b/c_src/libpg_query/protobuf/pg_query.pb-c.h @@ -9,9 +9,9 @@ PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1003000 -# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. -#elif 1005000 < PROTOBUF_C_MIN_COMPILER_VERSION -# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +# error This file was generated by a newer version of protobuf-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1005002 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protobuf-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protobuf-c. #endif @@ -287,10 +287,23 @@ typedef struct PgQuery__CreateSubscriptionStmt PgQuery__CreateSubscriptionStmt; typedef struct PgQuery__AlterSubscriptionStmt PgQuery__AlterSubscriptionStmt; typedef struct PgQuery__DropSubscriptionStmt PgQuery__DropSubscriptionStmt; typedef struct PgQuery__ScanToken PgQuery__ScanToken; +typedef struct PgQuery__SummaryResult PgQuery__SummaryResult; +typedef struct PgQuery__SummaryResult__Table PgQuery__SummaryResult__Table; +typedef struct PgQuery__SummaryResult__AliasesEntry PgQuery__SummaryResult__AliasesEntry; +typedef struct PgQuery__SummaryResult__Function PgQuery__SummaryResult__Function; +typedef struct PgQuery__SummaryResult__FilterColumn PgQuery__SummaryResult__FilterColumn; /* --- enums --- */ +typedef enum _PgQuery__SummaryResult__Context { + PG_QUERY__SUMMARY_RESULT__CONTEXT__None = 0, + PG_QUERY__SUMMARY_RESULT__CONTEXT__Select = 1, + PG_QUERY__SUMMARY_RESULT__CONTEXT__DML = 2, + PG_QUERY__SUMMARY_RESULT__CONTEXT__DDL = 3, + PG_QUERY__SUMMARY_RESULT__CONTEXT__Call = 4 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(PG_QUERY__SUMMARY_RESULT__CONTEXT) +} PgQuery__SummaryResult__Context; typedef enum _PgQuery__QuerySource { PG_QUERY__QUERY_SOURCE__QUERY_SOURCE_UNDEFINED = 0, PG_QUERY__QUERY_SOURCE__QSRC_ORIGINAL = 1, @@ -1943,274 +1956,274 @@ struct PgQuery__Node ProtobufCMessage base; PgQuery__Node__NodeCase node_case; union { - PgQuery__Alias *alias; - PgQuery__RangeVar *range_var; - PgQuery__TableFunc *table_func; - PgQuery__IntoClause *into_clause; - PgQuery__Var *var; - PgQuery__Param *param; + PgQuery__AArrayExpr *a_array_expr; + PgQuery__AConst *a_const; + PgQuery__AExpr *a_expr; + PgQuery__AIndices *a_indices; + PgQuery__AIndirection *a_indirection; + PgQuery__AStar *a_star; + PgQuery__AccessPriv *access_priv; PgQuery__Aggref *aggref; - PgQuery__GroupingFunc *grouping_func; - PgQuery__WindowFunc *window_func; - PgQuery__WindowFuncRunCondition *window_func_run_condition; - PgQuery__MergeSupportFunc *merge_support_func; - PgQuery__SubscriptingRef *subscripting_ref; - PgQuery__FuncExpr *func_expr; - PgQuery__NamedArgExpr *named_arg_expr; - PgQuery__OpExpr *op_expr; - PgQuery__DistinctExpr *distinct_expr; - PgQuery__NullIfExpr *null_if_expr; - PgQuery__ScalarArrayOpExpr *scalar_array_op_expr; - PgQuery__BoolExpr *bool_expr; - PgQuery__SubLink *sub_link; - PgQuery__SubPlan *sub_plan; + PgQuery__Alias *alias; + PgQuery__AlterCollationStmt *alter_collation_stmt; + PgQuery__AlterDatabaseRefreshCollStmt *alter_database_refresh_coll_stmt; + PgQuery__AlterDatabaseSetStmt *alter_database_set_stmt; + PgQuery__AlterDatabaseStmt *alter_database_stmt; + PgQuery__AlterDefaultPrivilegesStmt *alter_default_privileges_stmt; + PgQuery__AlterDomainStmt *alter_domain_stmt; + PgQuery__AlterEnumStmt *alter_enum_stmt; + PgQuery__AlterEventTrigStmt *alter_event_trig_stmt; + PgQuery__AlterExtensionContentsStmt *alter_extension_contents_stmt; + PgQuery__AlterExtensionStmt *alter_extension_stmt; + PgQuery__AlterFdwStmt *alter_fdw_stmt; + PgQuery__AlterForeignServerStmt *alter_foreign_server_stmt; + PgQuery__AlterFunctionStmt *alter_function_stmt; + PgQuery__AlterObjectDependsStmt *alter_object_depends_stmt; + PgQuery__AlterObjectSchemaStmt *alter_object_schema_stmt; + PgQuery__AlterOpFamilyStmt *alter_op_family_stmt; + PgQuery__AlterOperatorStmt *alter_operator_stmt; + PgQuery__AlterOwnerStmt *alter_owner_stmt; + PgQuery__AlterPolicyStmt *alter_policy_stmt; + PgQuery__AlterPublicationStmt *alter_publication_stmt; + PgQuery__AlterRoleSetStmt *alter_role_set_stmt; + PgQuery__AlterRoleStmt *alter_role_stmt; + PgQuery__AlterSeqStmt *alter_seq_stmt; + PgQuery__AlterStatsStmt *alter_stats_stmt; + PgQuery__AlterSubscriptionStmt *alter_subscription_stmt; + PgQuery__AlterSystemStmt *alter_system_stmt; + PgQuery__AlterTableCmd *alter_table_cmd; + PgQuery__AlterTableMoveAllStmt *alter_table_move_all_stmt; + PgQuery__AlterTableSpaceOptionsStmt *alter_table_space_options_stmt; + PgQuery__AlterTableStmt *alter_table_stmt; + PgQuery__AlterTSConfigurationStmt *alter_tsconfiguration_stmt; + PgQuery__AlterTSDictionaryStmt *alter_tsdictionary_stmt; + PgQuery__AlterTypeStmt *alter_type_stmt; + PgQuery__AlterUserMappingStmt *alter_user_mapping_stmt; PgQuery__AlternativeSubPlan *alternative_sub_plan; - PgQuery__FieldSelect *field_select; - PgQuery__FieldStore *field_store; - PgQuery__RelabelType *relabel_type; - PgQuery__CoerceViaIO *coerce_via_io; PgQuery__ArrayCoerceExpr *array_coerce_expr; - PgQuery__ConvertRowtypeExpr *convert_rowtype_expr; - PgQuery__CollateExpr *collate_expr; + PgQuery__ArrayExpr *array_expr; + PgQuery__BitString *bit_string; + PgQuery__BoolExpr *bool_expr; + PgQuery__Boolean *boolean; + PgQuery__BooleanTest *boolean_test; + PgQuery__CallContext *call_context; + PgQuery__CallStmt *call_stmt; PgQuery__CaseExpr *case_expr; - PgQuery__CaseWhen *case_when; PgQuery__CaseTestExpr *case_test_expr; - PgQuery__ArrayExpr *array_expr; - PgQuery__RowExpr *row_expr; - PgQuery__RowCompareExpr *row_compare_expr; + PgQuery__CaseWhen *case_when; + PgQuery__CheckPointStmt *check_point_stmt; + PgQuery__ClosePortalStmt *close_portal_stmt; + PgQuery__ClusterStmt *cluster_stmt; PgQuery__CoalesceExpr *coalesce_expr; - PgQuery__MinMaxExpr *min_max_expr; - PgQuery__SQLValueFunction *sqlvalue_function; - PgQuery__XmlExpr *xml_expr; - PgQuery__JsonFormat *json_format; - PgQuery__JsonReturning *json_returning; - PgQuery__JsonValueExpr *json_value_expr; - PgQuery__JsonConstructorExpr *json_constructor_expr; - PgQuery__JsonIsPredicate *json_is_predicate; - PgQuery__JsonBehavior *json_behavior; - PgQuery__JsonExpr *json_expr; - PgQuery__JsonTablePath *json_table_path; - PgQuery__JsonTablePathScan *json_table_path_scan; - PgQuery__JsonTableSiblingJoin *json_table_sibling_join; - PgQuery__NullTest *null_test; - PgQuery__BooleanTest *boolean_test; - PgQuery__MergeAction *merge_action; PgQuery__CoerceToDomain *coerce_to_domain; PgQuery__CoerceToDomainValue *coerce_to_domain_value; - PgQuery__SetToDefault *set_to_default; - PgQuery__CurrentOfExpr *current_of_expr; - PgQuery__NextValueExpr *next_value_expr; - PgQuery__InferenceElem *inference_elem; - PgQuery__TargetEntry *target_entry; - PgQuery__RangeTblRef *range_tbl_ref; - PgQuery__JoinExpr *join_expr; - PgQuery__FromExpr *from_expr; - PgQuery__OnConflictExpr *on_conflict_expr; - PgQuery__Query *query; - PgQuery__TypeName *type_name; - PgQuery__ColumnRef *column_ref; - PgQuery__ParamRef *param_ref; - PgQuery__AExpr *a_expr; - PgQuery__TypeCast *type_cast; + PgQuery__CoerceViaIO *coerce_via_io; PgQuery__CollateClause *collate_clause; - PgQuery__RoleSpec *role_spec; - PgQuery__FuncCall *func_call; - PgQuery__AStar *a_star; - PgQuery__AIndices *a_indices; - PgQuery__AIndirection *a_indirection; - PgQuery__AArrayExpr *a_array_expr; - PgQuery__ResTarget *res_target; - PgQuery__MultiAssignRef *multi_assign_ref; - PgQuery__SortBy *sort_by; - PgQuery__WindowDef *window_def; - PgQuery__RangeSubselect *range_subselect; - PgQuery__RangeFunction *range_function; - PgQuery__RangeTableFunc *range_table_func; - PgQuery__RangeTableFuncCol *range_table_func_col; - PgQuery__RangeTableSample *range_table_sample; + PgQuery__CollateExpr *collate_expr; PgQuery__ColumnDef *column_def; - PgQuery__TableLikeClause *table_like_clause; - PgQuery__IndexElem *index_elem; - PgQuery__DefElem *def_elem; - PgQuery__LockingClause *locking_clause; - PgQuery__XmlSerialize *xml_serialize; - PgQuery__PartitionElem *partition_elem; - PgQuery__PartitionSpec *partition_spec; - PgQuery__PartitionBoundSpec *partition_bound_spec; - PgQuery__PartitionRangeDatum *partition_range_datum; - PgQuery__SinglePartitionSpec *single_partition_spec; - PgQuery__PartitionCmd *partition_cmd; - PgQuery__RangeTblEntry *range_tbl_entry; - PgQuery__RTEPermissionInfo *rtepermission_info; - PgQuery__RangeTblFunction *range_tbl_function; - PgQuery__TableSampleClause *table_sample_clause; - PgQuery__WithCheckOption *with_check_option; - PgQuery__SortGroupClause *sort_group_clause; - PgQuery__GroupingSet *grouping_set; - PgQuery__WindowClause *window_clause; - PgQuery__RowMarkClause *row_mark_clause; - PgQuery__WithClause *with_clause; - PgQuery__InferClause *infer_clause; - PgQuery__OnConflictClause *on_conflict_clause; - PgQuery__CTESearchClause *ctesearch_clause; - PgQuery__CTECycleClause *ctecycle_clause; + PgQuery__ColumnRef *column_ref; + PgQuery__CommentStmt *comment_stmt; PgQuery__CommonTableExpr *common_table_expr; - PgQuery__MergeWhenClause *merge_when_clause; - PgQuery__TriggerTransition *trigger_transition; - PgQuery__JsonOutput *json_output; - PgQuery__JsonArgument *json_argument; - PgQuery__JsonFuncExpr *json_func_expr; - PgQuery__JsonTablePathSpec *json_table_path_spec; - PgQuery__JsonTable *json_table; - PgQuery__JsonTableColumn *json_table_column; - PgQuery__JsonKeyValue *json_key_value; - PgQuery__JsonParseExpr *json_parse_expr; - PgQuery__JsonScalarExpr *json_scalar_expr; - PgQuery__JsonSerializeExpr *json_serialize_expr; - PgQuery__JsonObjectConstructor *json_object_constructor; - PgQuery__JsonArrayConstructor *json_array_constructor; - PgQuery__JsonArrayQueryConstructor *json_array_query_constructor; - PgQuery__JsonAggConstructor *json_agg_constructor; - PgQuery__JsonObjectAgg *json_object_agg; - PgQuery__JsonArrayAgg *json_array_agg; - PgQuery__RawStmt *raw_stmt; - PgQuery__InsertStmt *insert_stmt; - PgQuery__DeleteStmt *delete_stmt; - PgQuery__UpdateStmt *update_stmt; - PgQuery__MergeStmt *merge_stmt; - PgQuery__SelectStmt *select_stmt; - PgQuery__SetOperationStmt *set_operation_stmt; - PgQuery__ReturnStmt *return_stmt; - PgQuery__PLAssignStmt *plassign_stmt; - PgQuery__CreateSchemaStmt *create_schema_stmt; - PgQuery__AlterTableStmt *alter_table_stmt; - PgQuery__ReplicaIdentityStmt *replica_identity_stmt; - PgQuery__AlterTableCmd *alter_table_cmd; - PgQuery__AlterCollationStmt *alter_collation_stmt; - PgQuery__AlterDomainStmt *alter_domain_stmt; - PgQuery__GrantStmt *grant_stmt; - PgQuery__ObjectWithArgs *object_with_args; - PgQuery__AccessPriv *access_priv; - PgQuery__GrantRoleStmt *grant_role_stmt; - PgQuery__AlterDefaultPrivilegesStmt *alter_default_privileges_stmt; - PgQuery__CopyStmt *copy_stmt; - PgQuery__VariableSetStmt *variable_set_stmt; - PgQuery__VariableShowStmt *variable_show_stmt; - PgQuery__CreateStmt *create_stmt; + PgQuery__CompositeTypeStmt *composite_type_stmt; PgQuery__Constraint *constraint; - PgQuery__CreateTableSpaceStmt *create_table_space_stmt; - PgQuery__DropTableSpaceStmt *drop_table_space_stmt; - PgQuery__AlterTableSpaceOptionsStmt *alter_table_space_options_stmt; - PgQuery__AlterTableMoveAllStmt *alter_table_move_all_stmt; + PgQuery__ConstraintsSetStmt *constraints_set_stmt; + PgQuery__ConvertRowtypeExpr *convert_rowtype_expr; + PgQuery__CopyStmt *copy_stmt; + PgQuery__CreateAmStmt *create_am_stmt; + PgQuery__CreateCastStmt *create_cast_stmt; + PgQuery__CreateConversionStmt *create_conversion_stmt; + PgQuery__CreateDomainStmt *create_domain_stmt; + PgQuery__CreateEnumStmt *create_enum_stmt; + PgQuery__CreateEventTrigStmt *create_event_trig_stmt; PgQuery__CreateExtensionStmt *create_extension_stmt; - PgQuery__AlterExtensionStmt *alter_extension_stmt; - PgQuery__AlterExtensionContentsStmt *alter_extension_contents_stmt; PgQuery__CreateFdwStmt *create_fdw_stmt; - PgQuery__AlterFdwStmt *alter_fdw_stmt; PgQuery__CreateForeignServerStmt *create_foreign_server_stmt; - PgQuery__AlterForeignServerStmt *alter_foreign_server_stmt; PgQuery__CreateForeignTableStmt *create_foreign_table_stmt; - PgQuery__CreateUserMappingStmt *create_user_mapping_stmt; - PgQuery__AlterUserMappingStmt *alter_user_mapping_stmt; - PgQuery__DropUserMappingStmt *drop_user_mapping_stmt; - PgQuery__ImportForeignSchemaStmt *import_foreign_schema_stmt; - PgQuery__CreatePolicyStmt *create_policy_stmt; - PgQuery__AlterPolicyStmt *alter_policy_stmt; - PgQuery__CreateAmStmt *create_am_stmt; - PgQuery__CreateTrigStmt *create_trig_stmt; - PgQuery__CreateEventTrigStmt *create_event_trig_stmt; - PgQuery__AlterEventTrigStmt *alter_event_trig_stmt; + PgQuery__CreateFunctionStmt *create_function_stmt; + PgQuery__CreateOpClassItem *create_op_class_item; + PgQuery__CreateOpClassStmt *create_op_class_stmt; + PgQuery__CreateOpFamilyStmt *create_op_family_stmt; PgQuery__CreatePLangStmt *create_plang_stmt; + PgQuery__CreatePolicyStmt *create_policy_stmt; + PgQuery__CreatePublicationStmt *create_publication_stmt; + PgQuery__CreateRangeStmt *create_range_stmt; PgQuery__CreateRoleStmt *create_role_stmt; - PgQuery__AlterRoleStmt *alter_role_stmt; - PgQuery__AlterRoleSetStmt *alter_role_set_stmt; - PgQuery__DropRoleStmt *drop_role_stmt; + PgQuery__CreateSchemaStmt *create_schema_stmt; PgQuery__CreateSeqStmt *create_seq_stmt; - PgQuery__AlterSeqStmt *alter_seq_stmt; + PgQuery__CreateStatsStmt *create_stats_stmt; + PgQuery__CreateStmt *create_stmt; + PgQuery__CreateSubscriptionStmt *create_subscription_stmt; + PgQuery__CreateTableAsStmt *create_table_as_stmt; + PgQuery__CreateTableSpaceStmt *create_table_space_stmt; + PgQuery__CreateTransformStmt *create_transform_stmt; + PgQuery__CreateTrigStmt *create_trig_stmt; + PgQuery__CreateUserMappingStmt *create_user_mapping_stmt; + PgQuery__CreatedbStmt *createdb_stmt; + PgQuery__CTECycleClause *ctecycle_clause; + PgQuery__CTESearchClause *ctesearch_clause; + PgQuery__CurrentOfExpr *current_of_expr; + PgQuery__DeallocateStmt *deallocate_stmt; + PgQuery__DeclareCursorStmt *declare_cursor_stmt; + PgQuery__DefElem *def_elem; PgQuery__DefineStmt *define_stmt; - PgQuery__CreateDomainStmt *create_domain_stmt; - PgQuery__CreateOpClassStmt *create_op_class_stmt; - PgQuery__CreateOpClassItem *create_op_class_item; - PgQuery__CreateOpFamilyStmt *create_op_family_stmt; - PgQuery__AlterOpFamilyStmt *alter_op_family_stmt; + PgQuery__DeleteStmt *delete_stmt; + PgQuery__DiscardStmt *discard_stmt; + PgQuery__DistinctExpr *distinct_expr; + PgQuery__DoStmt *do_stmt; + PgQuery__DropOwnedStmt *drop_owned_stmt; + PgQuery__DropRoleStmt *drop_role_stmt; PgQuery__DropStmt *drop_stmt; - PgQuery__TruncateStmt *truncate_stmt; - PgQuery__CommentStmt *comment_stmt; - PgQuery__SecLabelStmt *sec_label_stmt; - PgQuery__DeclareCursorStmt *declare_cursor_stmt; - PgQuery__ClosePortalStmt *close_portal_stmt; + PgQuery__DropSubscriptionStmt *drop_subscription_stmt; + PgQuery__DropTableSpaceStmt *drop_table_space_stmt; + PgQuery__DropUserMappingStmt *drop_user_mapping_stmt; + PgQuery__DropdbStmt *dropdb_stmt; + PgQuery__ExecuteStmt *execute_stmt; + PgQuery__ExplainStmt *explain_stmt; PgQuery__FetchStmt *fetch_stmt; - PgQuery__IndexStmt *index_stmt; - PgQuery__CreateStatsStmt *create_stats_stmt; - PgQuery__StatsElem *stats_elem; - PgQuery__AlterStatsStmt *alter_stats_stmt; - PgQuery__CreateFunctionStmt *create_function_stmt; + PgQuery__FieldSelect *field_select; + PgQuery__FieldStore *field_store; + PgQuery__Float *float_; + PgQuery__FromExpr *from_expr; + PgQuery__FuncCall *func_call; + PgQuery__FuncExpr *func_expr; PgQuery__FunctionParameter *function_parameter; - PgQuery__AlterFunctionStmt *alter_function_stmt; - PgQuery__DoStmt *do_stmt; + PgQuery__GrantRoleStmt *grant_role_stmt; + PgQuery__GrantStmt *grant_stmt; + PgQuery__GroupingFunc *grouping_func; + PgQuery__GroupingSet *grouping_set; + PgQuery__ImportForeignSchemaStmt *import_foreign_schema_stmt; + PgQuery__IndexElem *index_elem; + PgQuery__IndexStmt *index_stmt; + PgQuery__InferClause *infer_clause; + PgQuery__InferenceElem *inference_elem; PgQuery__InlineCodeBlock *inline_code_block; - PgQuery__CallStmt *call_stmt; - PgQuery__CallContext *call_context; - PgQuery__RenameStmt *rename_stmt; - PgQuery__AlterObjectDependsStmt *alter_object_depends_stmt; - PgQuery__AlterObjectSchemaStmt *alter_object_schema_stmt; - PgQuery__AlterOwnerStmt *alter_owner_stmt; - PgQuery__AlterOperatorStmt *alter_operator_stmt; - PgQuery__AlterTypeStmt *alter_type_stmt; - PgQuery__RuleStmt *rule_stmt; - PgQuery__NotifyStmt *notify_stmt; + PgQuery__InsertStmt *insert_stmt; + PgQuery__IntList *int_list; + PgQuery__Integer *integer; + PgQuery__IntoClause *into_clause; + PgQuery__JoinExpr *join_expr; + PgQuery__JsonAggConstructor *json_agg_constructor; + PgQuery__JsonArgument *json_argument; + PgQuery__JsonArrayAgg *json_array_agg; + PgQuery__JsonArrayConstructor *json_array_constructor; + PgQuery__JsonArrayQueryConstructor *json_array_query_constructor; + PgQuery__JsonBehavior *json_behavior; + PgQuery__JsonConstructorExpr *json_constructor_expr; + PgQuery__JsonExpr *json_expr; + PgQuery__JsonFormat *json_format; + PgQuery__JsonFuncExpr *json_func_expr; + PgQuery__JsonIsPredicate *json_is_predicate; + PgQuery__JsonKeyValue *json_key_value; + PgQuery__JsonObjectAgg *json_object_agg; + PgQuery__JsonObjectConstructor *json_object_constructor; + PgQuery__JsonOutput *json_output; + PgQuery__JsonParseExpr *json_parse_expr; + PgQuery__JsonReturning *json_returning; + PgQuery__JsonScalarExpr *json_scalar_expr; + PgQuery__JsonSerializeExpr *json_serialize_expr; + PgQuery__JsonTable *json_table; + PgQuery__JsonTableColumn *json_table_column; + PgQuery__JsonTablePath *json_table_path; + PgQuery__JsonTablePathScan *json_table_path_scan; + PgQuery__JsonTablePathSpec *json_table_path_spec; + PgQuery__JsonTableSiblingJoin *json_table_sibling_join; + PgQuery__JsonValueExpr *json_value_expr; + PgQuery__List *list; PgQuery__ListenStmt *listen_stmt; - PgQuery__UnlistenStmt *unlisten_stmt; - PgQuery__TransactionStmt *transaction_stmt; - PgQuery__CompositeTypeStmt *composite_type_stmt; - PgQuery__CreateEnumStmt *create_enum_stmt; - PgQuery__CreateRangeStmt *create_range_stmt; - PgQuery__AlterEnumStmt *alter_enum_stmt; - PgQuery__ViewStmt *view_stmt; PgQuery__LoadStmt *load_stmt; - PgQuery__CreatedbStmt *createdb_stmt; - PgQuery__AlterDatabaseStmt *alter_database_stmt; - PgQuery__AlterDatabaseRefreshCollStmt *alter_database_refresh_coll_stmt; - PgQuery__AlterDatabaseSetStmt *alter_database_set_stmt; - PgQuery__DropdbStmt *dropdb_stmt; - PgQuery__AlterSystemStmt *alter_system_stmt; - PgQuery__ClusterStmt *cluster_stmt; - PgQuery__VacuumStmt *vacuum_stmt; - PgQuery__VacuumRelation *vacuum_relation; - PgQuery__ExplainStmt *explain_stmt; - PgQuery__CreateTableAsStmt *create_table_as_stmt; - PgQuery__RefreshMatViewStmt *refresh_mat_view_stmt; - PgQuery__CheckPointStmt *check_point_stmt; - PgQuery__DiscardStmt *discard_stmt; PgQuery__LockStmt *lock_stmt; - PgQuery__ConstraintsSetStmt *constraints_set_stmt; - PgQuery__ReindexStmt *reindex_stmt; - PgQuery__CreateConversionStmt *create_conversion_stmt; - PgQuery__CreateCastStmt *create_cast_stmt; - PgQuery__CreateTransformStmt *create_transform_stmt; + PgQuery__LockingClause *locking_clause; + PgQuery__MergeAction *merge_action; + PgQuery__MergeStmt *merge_stmt; + PgQuery__MergeSupportFunc *merge_support_func; + PgQuery__MergeWhenClause *merge_when_clause; + PgQuery__MinMaxExpr *min_max_expr; + PgQuery__MultiAssignRef *multi_assign_ref; + PgQuery__NamedArgExpr *named_arg_expr; + PgQuery__NextValueExpr *next_value_expr; + PgQuery__NotifyStmt *notify_stmt; + PgQuery__NullIfExpr *null_if_expr; + PgQuery__NullTest *null_test; + PgQuery__ObjectWithArgs *object_with_args; + PgQuery__OidList *oid_list; + PgQuery__OnConflictClause *on_conflict_clause; + PgQuery__OnConflictExpr *on_conflict_expr; + PgQuery__OpExpr *op_expr; + PgQuery__Param *param; + PgQuery__ParamRef *param_ref; + PgQuery__PartitionBoundSpec *partition_bound_spec; + PgQuery__PartitionCmd *partition_cmd; + PgQuery__PartitionElem *partition_elem; + PgQuery__PartitionRangeDatum *partition_range_datum; + PgQuery__PartitionSpec *partition_spec; + PgQuery__PLAssignStmt *plassign_stmt; PgQuery__PrepareStmt *prepare_stmt; - PgQuery__ExecuteStmt *execute_stmt; - PgQuery__DeallocateStmt *deallocate_stmt; - PgQuery__DropOwnedStmt *drop_owned_stmt; - PgQuery__ReassignOwnedStmt *reassign_owned_stmt; - PgQuery__AlterTSDictionaryStmt *alter_tsdictionary_stmt; - PgQuery__AlterTSConfigurationStmt *alter_tsconfiguration_stmt; - PgQuery__PublicationTable *publication_table; PgQuery__PublicationObjSpec *publication_obj_spec; - PgQuery__CreatePublicationStmt *create_publication_stmt; - PgQuery__AlterPublicationStmt *alter_publication_stmt; - PgQuery__CreateSubscriptionStmt *create_subscription_stmt; - PgQuery__AlterSubscriptionStmt *alter_subscription_stmt; - PgQuery__DropSubscriptionStmt *drop_subscription_stmt; - PgQuery__Integer *integer; - PgQuery__Float *float_; - PgQuery__Boolean *boolean; + PgQuery__PublicationTable *publication_table; + PgQuery__Query *query; + PgQuery__RangeFunction *range_function; + PgQuery__RangeSubselect *range_subselect; + PgQuery__RangeTableFunc *range_table_func; + PgQuery__RangeTableFuncCol *range_table_func_col; + PgQuery__RangeTableSample *range_table_sample; + PgQuery__RangeTblEntry *range_tbl_entry; + PgQuery__RangeTblFunction *range_tbl_function; + PgQuery__RangeTblRef *range_tbl_ref; + PgQuery__RangeVar *range_var; + PgQuery__RawStmt *raw_stmt; + PgQuery__ReassignOwnedStmt *reassign_owned_stmt; + PgQuery__RefreshMatViewStmt *refresh_mat_view_stmt; + PgQuery__ReindexStmt *reindex_stmt; + PgQuery__RelabelType *relabel_type; + PgQuery__RenameStmt *rename_stmt; + PgQuery__ReplicaIdentityStmt *replica_identity_stmt; + PgQuery__ResTarget *res_target; + PgQuery__ReturnStmt *return_stmt; + PgQuery__RoleSpec *role_spec; + PgQuery__RowCompareExpr *row_compare_expr; + PgQuery__RowExpr *row_expr; + PgQuery__RowMarkClause *row_mark_clause; + PgQuery__RTEPermissionInfo *rtepermission_info; + PgQuery__RuleStmt *rule_stmt; + PgQuery__ScalarArrayOpExpr *scalar_array_op_expr; + PgQuery__SecLabelStmt *sec_label_stmt; + PgQuery__SelectStmt *select_stmt; + PgQuery__SetOperationStmt *set_operation_stmt; + PgQuery__SetToDefault *set_to_default; + PgQuery__SinglePartitionSpec *single_partition_spec; + PgQuery__SortBy *sort_by; + PgQuery__SortGroupClause *sort_group_clause; + PgQuery__SQLValueFunction *sqlvalue_function; + PgQuery__StatsElem *stats_elem; PgQuery__String *string; - PgQuery__BitString *bit_string; - PgQuery__List *list; - PgQuery__IntList *int_list; - PgQuery__OidList *oid_list; - PgQuery__AConst *a_const; + PgQuery__SubLink *sub_link; + PgQuery__SubPlan *sub_plan; + PgQuery__SubscriptingRef *subscripting_ref; + PgQuery__TableFunc *table_func; + PgQuery__TableLikeClause *table_like_clause; + PgQuery__TableSampleClause *table_sample_clause; + PgQuery__TargetEntry *target_entry; + PgQuery__TransactionStmt *transaction_stmt; + PgQuery__TriggerTransition *trigger_transition; + PgQuery__TruncateStmt *truncate_stmt; + PgQuery__TypeCast *type_cast; + PgQuery__TypeName *type_name; + PgQuery__UnlistenStmt *unlisten_stmt; + PgQuery__UpdateStmt *update_stmt; + PgQuery__VacuumRelation *vacuum_relation; + PgQuery__VacuumStmt *vacuum_stmt; + PgQuery__Var *var; + PgQuery__VariableSetStmt *variable_set_stmt; + PgQuery__VariableShowStmt *variable_show_stmt; + PgQuery__ViewStmt *view_stmt; + PgQuery__WindowClause *window_clause; + PgQuery__WindowDef *window_def; + PgQuery__WindowFunc *window_func; + PgQuery__WindowFuncRunCondition *window_func_run_condition; + PgQuery__WithCheckOption *with_check_option; + PgQuery__WithClause *with_clause; + PgQuery__XmlExpr *xml_expr; + PgQuery__XmlSerialize *xml_serialize; }; }; #define PG_QUERY__NODE__INIT \ @@ -2330,11 +2343,11 @@ struct PgQuery__AConst int32_t location; PgQuery__AConst__ValCase val_case; union { - PgQuery__Integer *ival; - PgQuery__Float *fval; PgQuery__Boolean *boolval; - PgQuery__String *sval; PgQuery__BitString *bsval; + PgQuery__Float *fval; + PgQuery__Integer *ival; + PgQuery__String *sval; }; }; #define PG_QUERY__A__CONST__INIT \ @@ -6370,6 +6383,98 @@ struct PgQuery__ScanToken , 0, 0, PG_QUERY__TOKEN__NUL, PG_QUERY__KEYWORD_KIND__NO_KEYWORD } +struct PgQuery__SummaryResult__Table +{ + ProtobufCMessage base; + char *name; + char *schema_name; + char *table_name; + PgQuery__SummaryResult__Context context; +}; +#define PG_QUERY__SUMMARY_RESULT__TABLE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&pg_query__summary_result__table__descriptor) \ +, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, PG_QUERY__SUMMARY_RESULT__CONTEXT__None } + + +struct PgQuery__SummaryResult__AliasesEntry +{ + ProtobufCMessage base; + char *key; + char *value; +}; +#define PG_QUERY__SUMMARY_RESULT__ALIASES_ENTRY__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&pg_query__summary_result__aliases_entry__descriptor) \ +, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +struct PgQuery__SummaryResult__Function +{ + ProtobufCMessage base; + char *name; + char *function_name; + /* + * optional + */ + char *schema_name; + PgQuery__SummaryResult__Context context; +}; +#define PG_QUERY__SUMMARY_RESULT__FUNCTION__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&pg_query__summary_result__function__descriptor) \ +, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, PG_QUERY__SUMMARY_RESULT__CONTEXT__None } + + +struct PgQuery__SummaryResult__FilterColumn +{ + ProtobufCMessage base; + /* + * optional + */ + char *schema_name; + /* + * optional + */ + char *table_name; + char *column; +}; +#define PG_QUERY__SUMMARY_RESULT__FILTER_COLUMN__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&pg_query__summary_result__filter_column__descriptor) \ +, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +/* + * protobuf-c doesn't support optional fields, so any optional strings + * are just an empty string if it should be the equivalent of None/nil. + * These fields have `// optional` at the end of the line. + * Upstream issue: https://github.com/protobuf-c/protobuf-c/issues/476 + */ +struct PgQuery__SummaryResult +{ + ProtobufCMessage base; + size_t n_tables; + PgQuery__SummaryResult__Table **tables; + /* + * The value here is the table name (i.e. schema.table or just table). + */ + size_t n_aliases; + PgQuery__SummaryResult__AliasesEntry **aliases; + size_t n_cte_names; + char **cte_names; + size_t n_functions; + PgQuery__SummaryResult__Function **functions; + size_t n_filter_columns; + PgQuery__SummaryResult__FilterColumn **filter_columns; + size_t n_statement_types; + char **statement_types; + /* + * optional, empty if truncation limit is -1 + */ + char *truncated_query; +}; +#define PG_QUERY__SUMMARY_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&pg_query__summary_result__descriptor) \ +, 0,NULL, 0,NULL, 0,NULL, 0,NULL, 0,NULL, 0,NULL, (char *)protobuf_c_empty_string } + + /* PgQuery__ParseResult methods */ void pg_query__parse_result__init (PgQuery__ParseResult *message); @@ -11538,6 +11643,37 @@ PgQuery__ScanToken * void pg_query__scan_token__free_unpacked (PgQuery__ScanToken *message, ProtobufCAllocator *allocator); +/* PgQuery__SummaryResult__Table methods */ +void pg_query__summary_result__table__init + (PgQuery__SummaryResult__Table *message); +/* PgQuery__SummaryResult__AliasesEntry methods */ +void pg_query__summary_result__aliases_entry__init + (PgQuery__SummaryResult__AliasesEntry *message); +/* PgQuery__SummaryResult__Function methods */ +void pg_query__summary_result__function__init + (PgQuery__SummaryResult__Function *message); +/* PgQuery__SummaryResult__FilterColumn methods */ +void pg_query__summary_result__filter_column__init + (PgQuery__SummaryResult__FilterColumn *message); +/* PgQuery__SummaryResult methods */ +void pg_query__summary_result__init + (PgQuery__SummaryResult *message); +size_t pg_query__summary_result__get_packed_size + (const PgQuery__SummaryResult *message); +size_t pg_query__summary_result__pack + (const PgQuery__SummaryResult *message, + uint8_t *out); +size_t pg_query__summary_result__pack_to_buffer + (const PgQuery__SummaryResult *message, + ProtobufCBuffer *buffer); +PgQuery__SummaryResult * + pg_query__summary_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void pg_query__summary_result__free_unpacked + (PgQuery__SummaryResult *message, + ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*PgQuery__ParseResult_Closure) @@ -12356,6 +12492,21 @@ typedef void (*PgQuery__DropSubscriptionStmt_Closure) typedef void (*PgQuery__ScanToken_Closure) (const PgQuery__ScanToken *message, void *closure_data); +typedef void (*PgQuery__SummaryResult__Table_Closure) + (const PgQuery__SummaryResult__Table *message, + void *closure_data); +typedef void (*PgQuery__SummaryResult__AliasesEntry_Closure) + (const PgQuery__SummaryResult__AliasesEntry *message, + void *closure_data); +typedef void (*PgQuery__SummaryResult__Function_Closure) + (const PgQuery__SummaryResult__Function *message, + void *closure_data); +typedef void (*PgQuery__SummaryResult__FilterColumn_Closure) + (const PgQuery__SummaryResult__FilterColumn *message, + void *closure_data); +typedef void (*PgQuery__SummaryResult_Closure) + (const PgQuery__SummaryResult *message, + void *closure_data); /* --- services --- */ @@ -12705,6 +12856,12 @@ extern const ProtobufCMessageDescriptor pg_query__create_subscription_stmt__desc extern const ProtobufCMessageDescriptor pg_query__alter_subscription_stmt__descriptor; extern const ProtobufCMessageDescriptor pg_query__drop_subscription_stmt__descriptor; extern const ProtobufCMessageDescriptor pg_query__scan_token__descriptor; +extern const ProtobufCMessageDescriptor pg_query__summary_result__descriptor; +extern const ProtobufCMessageDescriptor pg_query__summary_result__table__descriptor; +extern const ProtobufCMessageDescriptor pg_query__summary_result__aliases_entry__descriptor; +extern const ProtobufCMessageDescriptor pg_query__summary_result__function__descriptor; +extern const ProtobufCMessageDescriptor pg_query__summary_result__filter_column__descriptor; +extern const ProtobufCEnumDescriptor pg_query__summary_result__context__descriptor; PROTOBUF_C__END_DECLS diff --git a/c_src/libpg_query/protobuf/pg_query.proto b/c_src/libpg_query/protobuf/pg_query.proto index 24a8f14c..5f7af30a 100644 --- a/c_src/libpg_query/protobuf/pg_query.proto +++ b/c_src/libpg_query/protobuf/pg_query.proto @@ -4108,3 +4108,50 @@ enum Token { MODE_PLPGSQL_ASSIGN3 = 777; UMINUS = 778; } + + +// protobuf-c doesn't support optional fields, so any optional strings +// are just an empty string if it should be the equivalent of None/nil. +// +// These fields have `// optional` at the end of the line. +// +// Upstream issue: https://github.com/protobuf-c/protobuf-c/issues/476 +message SummaryResult { + enum Context { + None = 0; + Select = 1; + DML = 2; + DDL = 3; + Call = 4; + } + + message Table { + string name = 1; + string schema_name = 2; + string table_name = 3; + Context context = 4; + } + repeated Table tables = 1; + + // The value here is the table name (i.e. schema.table or just table). + map aliases = 2; + + repeated string cte_names = 3; + + message Function { + string name = 1; + string function_name = 2; + string schema_name = 3; // optional + Context context = 4; + } + repeated Function functions = 4; + + message FilterColumn { + string schema_name = 1; // optional + string table_name = 2; // optional + string column = 3; + } + repeated FilterColumn filter_columns = 5; + repeated string statement_types = 6; + string truncated_query = 7; /* optional, empty if truncation limit is -1 */ +} diff --git a/c_src/libpg_query/scripts/extract_source.rb b/c_src/libpg_query/scripts/extract_source.rb index 098d4cf2..c9990ab1 100644 --- a/c_src/libpg_query/scripts/extract_source.rb +++ b/c_src/libpg_query/scripts/extract_source.rb @@ -724,6 +724,11 @@ def write_out # Needed for deparse runner.deep_resolve('pg_toupper') +runner.deep_resolve('makeStringInfo') +runner.deep_resolve('list_delete_last') +runner.deep_resolve('list_insert_nth') +runner.deep_resolve('bms_add_member') +runner.deep_resolve('bms_is_member') # Needed for normalize runner.deep_resolve('pg_qsort') @@ -734,6 +739,13 @@ def write_out runner.deep_resolve('hash_bytes') runner.deep_resolve('MemoryContextAllocExtended') +# Needed for summary +runner.deep_resolve('makeRangeVarFromNameList') +runner.deep_resolve('list_sort') +runner.deep_resolve('pg_mbcharcliplen') +runner.deep_resolve('pg_mbstrlen') +runner.deep_resolve('destroyStringInfo') + # Other required functions runner.deep_resolve('pg_printf') runner.deep_resolve('pg_strncasecmp') diff --git a/c_src/libpg_query/scripts/generate_protobuf_and_funcs.rb b/c_src/libpg_query/scripts/generate_protobuf_and_funcs.rb index 6c932c44..19d01c70 100755 --- a/c_src/libpg_query/scripts/generate_protobuf_and_funcs.rb +++ b/c_src/libpg_query/scripts/generate_protobuf_and_funcs.rb @@ -441,6 +441,53 @@ def generate! // Named tokens in scan.l #{@scan_protobuf_tokens.join("\n ")} } + + +// protobuf-c doesn't support optional fields, so any optional strings +// are just an empty string if it should be the equivalent of None/nil. +// +// These fields have `// optional` at the end of the line. +// +// Upstream issue: https://github.com/protobuf-c/protobuf-c/issues/476 +message SummaryResult { + enum Context { + None = 0; + Select = 1; + DML = 2; + DDL = 3; + Call = 4; + } + + message Table { + string name = 1; + string schema_name = 2; + string table_name = 3; + Context context = 4; + } + repeated Table tables = 1; + + // The value here is the table name (i.e. schema.table or just table). + map aliases = 2; + + repeated string cte_names = 3; + + message Function { + string name = 1; + string function_name = 2; + string schema_name = 3; // optional + Context context = 4; + } + repeated Function functions = 4; + + message FilterColumn { + string schema_name = 1; // optional + string table_name = 2; // optional + string column = 3; + } + repeated FilterColumn filter_columns = 5; + repeated string statement_types = 6; + string truncated_query = 7; /* optional, empty if truncation limit is -1 */ +} " File.write('./protobuf/pg_query.proto', protobuf) diff --git a/c_src/libpg_query/scripts/update_summary_tests_list.rb b/c_src/libpg_query/scripts/update_summary_tests_list.rb new file mode 100755 index 00000000..95005001 --- /dev/null +++ b/c_src/libpg_query/scripts/update_summary_tests_list.rb @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +summary_tests = File.join(__dir__, "..", "test", "summary_tests.c") +summary_tests_list = File.join(__dir__, "..", "test", "summary_tests_list.c") + +is_fn_decl = -> (l) { l.start_with?('void ') } +get_fn_name = -> (l) { l.split(' ')[1].split('(')[0] } +to_ref = -> (n) { "&#{n}," } + +fns = File.readlines(summary_tests).filter(&is_fn_decl).map(&get_fn_name).map(&to_ref) + +lines = ["// Generated by #{__FILE__}", "", *fns, ""] + +File.write(summary_tests_list, lines.join("\n")) diff --git a/c_src/libpg_query/src/pg_query_deparse.c b/c_src/libpg_query/src/pg_query_deparse.c index 6bf5e340..326ae687 100644 --- a/c_src/libpg_query/src/pg_query_deparse.c +++ b/c_src/libpg_query/src/pg_query_deparse.c @@ -4,13 +4,29 @@ #include "postgres_deparse.h" -PgQueryDeparseResult pg_query_deparse_protobuf(PgQueryProtobuf parse_tree) +#include "postgres.h" +#include "lib/stringinfo.h" +#include "nodes/parsenodes.h" + +#include "protobuf/pg_query.pb-c.h" + +PgQueryDeparseResult +pg_query_deparse_protobuf(PgQueryProtobuf parse_tree) +{ + PostgresDeparseOpts opts; + + MemSet(&opts, 0, sizeof(PostgresDeparseOpts)); + return pg_query_deparse_protobuf_opts(parse_tree, opts); +} + +PgQueryDeparseResult +pg_query_deparse_protobuf_opts(PgQueryProtobuf parse_tree, PostgresDeparseOpts opts) { PgQueryDeparseResult result = {0}; StringInfoData str; MemoryContext ctx; - List *stmts; - ListCell *lc; + List *stmts; + ListCell *lc; ctx = pg_query_enter_memory_context(); @@ -20,8 +36,9 @@ PgQueryDeparseResult pg_query_deparse_protobuf(PgQueryProtobuf parse_tree) initStringInfo(&str); - foreach(lc, stmts) { - deparseRawStmt(&str, castNode(RawStmt, lfirst(lc))); + foreach(lc, stmts) + { + deparseRawStmtOpts(&str, castNode(RawStmt, lfirst(lc)), opts); if (lnext(stmts, lc)) appendStringInfoString(&str, "; "); } @@ -29,19 +46,22 @@ PgQueryDeparseResult pg_query_deparse_protobuf(PgQueryProtobuf parse_tree) } PG_CATCH(); { - ErrorData* error_data; - PgQueryError* error; + ErrorData *error_data; + PgQueryError *error; MemoryContextSwitchTo(ctx); error_data = CopyErrorData(); - // Note: This is intentionally malloc so exiting the memory context doesn't free this + /* + * Note: This is intentionally malloc so exiting the memory context + * doesn't free this + */ error = malloc(sizeof(PgQueryError)); - error->message = strdup(error_data->message); - error->filename = strdup(error_data->filename); - error->funcname = strdup(error_data->funcname); - error->context = NULL; - error->lineno = error_data->lineno; + error->message = strdup(error_data->message); + error->filename = strdup(error_data->filename); + error->funcname = strdup(error_data->funcname); + error->context = NULL; + error->lineno = error_data->lineno; error->cursorpos = error_data->cursorpos; result.error = error; @@ -54,11 +74,124 @@ PgQueryDeparseResult pg_query_deparse_protobuf(PgQueryProtobuf parse_tree) return result; } -void pg_query_free_deparse_result(PgQueryDeparseResult result) +void +pg_query_free_deparse_result(PgQueryDeparseResult result) { - if (result.error) { + if (result.error) + { pg_query_free_error(result.error); } free(result.query); } + +PgQueryDeparseCommentsResult +pg_query_deparse_comments_for_query(const char *query) +{ + PgQueryDeparseCommentsResult result = {0}; + PgQueryScanResult scan_result_raw = pg_query_scan(query); + + if (scan_result_raw.error) + { + result.error = scan_result_raw.error; + return result; + } + + PgQuery__ScanResult *scan_result = pg_query__scan_result__unpack(NULL, scan_result_raw.pbuf.len, (void *) scan_result_raw.pbuf.data); + bool prior_token_was_comment = false; + int32_t prior_non_comment_end = 0; + int32_t prior_token_end = 0; + + result.comment_count = 0; + for (int i = 0; i < scan_result->n_tokens; i++) + { + PgQuery__ScanToken *token = scan_result->tokens[i]; + + if (token->token == PG_QUERY__TOKEN__SQL_COMMENT || token->token == PG_QUERY__TOKEN__C_COMMENT) + result.comment_count++; + } + + result.comments = malloc(result.comment_count * sizeof(PostgresDeparseComment *)); + size_t comment_idx = 0; + + for (int i = 0; i < scan_result->n_tokens; i++) + { + PgQuery__ScanToken *token = scan_result->tokens[i]; + + if (token->token == PG_QUERY__TOKEN__SQL_COMMENT || token->token == PG_QUERY__TOKEN__C_COMMENT) + { + size_t token_len = token->end - token->start; + PostgresDeparseComment *comment = malloc(sizeof(PostgresDeparseComment)); + + /* + * Set to the end of the prior non-comment token. + * + * We could alternatively set the match location to the start of + * the next non-comment token instead (which would be more in line + * with emitting that happens before the node once the location is + * matched). + * + * However, that doesn't work well in practice, specifically. + * RawStmt start locations are 0, even when there are comments at + * the start of the statement. + */ + comment->match_location = prior_non_comment_end; + + comment->newlines_before_comment = 0; + comment->newlines_after_comment = 0; + + /* + * Emit newlines before the comment if prior token was not a + * comment (otherwise that comment would have emitted them) + */ + if (!prior_token_was_comment) + { + for (int j = prior_token_end; j < token->start; j++) + { + if (query[j] == '\n') + comment->newlines_before_comment++; + } + } + + if (i < scan_result->n_tokens - 1) + { + for (int j = token->end; j < scan_result->tokens[i + 1]->start; j++) + { + if (query[j] == '\n') + comment->newlines_after_comment++; + } + } + + comment->str = malloc(token_len + 1); + memcpy(comment->str, &(query[token->start]), token_len); + comment->str[token_len] = '\0'; + + result.comments[comment_idx] = comment; + comment_idx++; + prior_token_was_comment = true; + } + else + { + prior_non_comment_end = token->end; + prior_token_was_comment = false; + } + prior_token_end = token->end; + } + + pg_query__scan_result__free_unpacked(scan_result, NULL); + pg_query_free_scan_result(scan_result_raw); + + return result; +} + +void +pg_query_free_deparse_comments_result(PgQueryDeparseCommentsResult result) +{ + for (int i = 0; i < result.comment_count; i++) + { + free(result.comments[i]->str); + free(result.comments[i]); + } + if (result.comments != NULL) + free(result.comments); +} diff --git a/c_src/libpg_query/src/pg_query_internal.h b/c_src/libpg_query/src/pg_query_internal.h index aacba633..3f797305 100644 --- a/c_src/libpg_query/src/pg_query_internal.h +++ b/c_src/libpg_query/src/pg_query_internal.h @@ -8,17 +8,18 @@ #define STDERR_BUFFER_LEN 4096 #define DEBUG -typedef struct { - List *tree; - char* stderr_buffer; - PgQueryError* error; -} PgQueryInternalParsetreeAndError; +typedef struct +{ + List *tree; + char *stderr_buffer; + PgQueryError *error; +} PgQueryInternalParsetreeAndError; -PgQueryInternalParsetreeAndError pg_query_raw_parse(const char* input, int parser_options); +PgQueryInternalParsetreeAndError pg_query_raw_parse(const char *input, int parser_options); -void pg_query_free_error(PgQueryError *error); +void pg_query_free_error(PgQueryError * error); MemoryContext pg_query_enter_memory_context(); -void pg_query_exit_memory_context(MemoryContext ctx); +void pg_query_exit_memory_context(MemoryContext ctx); #endif diff --git a/c_src/libpg_query/src/pg_query_is_utility_stmt.c b/c_src/libpg_query/src/pg_query_is_utility_stmt.c new file mode 100644 index 00000000..ef211eaf --- /dev/null +++ b/c_src/libpg_query/src/pg_query_is_utility_stmt.c @@ -0,0 +1,70 @@ +#include +#include +#include + +#include "pg_query.h" +#include "pg_query_internal.h" +#include +#include + +static +bool +is_utility_stmt_actual(RawStmt *raw_stmt) +{ + switch (nodeTag(raw_stmt->stmt)) + { + case T_SelectStmt: + case T_InsertStmt: + case T_UpdateStmt: + case T_DeleteStmt: + case T_MergeStmt: + return false; + + default: + return true; + } +} + +PgQueryIsUtilityResult +pg_query_is_utility_stmt(const char *query) +{ + PgQueryIsUtilityResult result = {0}; + MemoryContext ctx = pg_query_enter_memory_context(); + + PgQueryInternalParsetreeAndError parsetree_and_error = pg_query_raw_parse(query, 0); + + if (parsetree_and_error.error) + { + result.error = parsetree_and_error.error; + } + else + { + ListCell *lc; + + result.length = list_length(parsetree_and_error.tree); + result.items = malloc(sizeof(bool) * result.length); + + foreach(lc, parsetree_and_error.tree) + { + RawStmt *raw_stmt = lfirst_node(RawStmt, lc); + + result.items[foreach_current_index(lc)] = is_utility_stmt_actual(raw_stmt); + } + } + + if (parsetree_and_error.stderr_buffer) + free(parsetree_and_error.stderr_buffer); + + pg_query_exit_memory_context(ctx); + + return result; +} + +void +pg_query_free_is_utility_result(PgQueryIsUtilityResult result) +{ + if (result.error) + pg_query_free_error(result.error); + + free(result.items); +} diff --git a/c_src/libpg_query/src/pg_query_normalize.c b/c_src/libpg_query/src/pg_query_normalize.c index 460493fd..eaebd9da 100644 --- a/c_src/libpg_query/src/pg_query_normalize.c +++ b/c_src/libpg_query/src/pg_query_normalize.c @@ -336,10 +336,20 @@ static void RecordConstLocation(pgssConstLocations *jstate, int location) } } +static bool is_string_delimiter(char c) +{ + return c == '\'' || c == '$'; +} + +static bool is_special_string_start(char c) +{ + return c == 'b' || c == 'B' || c == 'x' || c == 'X' || c == 'n' || c == 'N' || c == 'e' || c == 'E'; +} + static void record_defelem_arg_location(pgssConstLocations *jstate, int location) { for (int i = location; i < jstate->query_len; i++) { - if (jstate->query[i] == '\'' || jstate->query[i] == '$') { + if (is_string_delimiter(jstate->query[i]) || (i + 1 < jstate->query_len && is_special_string_start(jstate->query[i]) && is_string_delimiter(jstate->query[i + 1]))) { RecordConstLocation(jstate, i); break; } @@ -406,6 +416,9 @@ static bool const_record_walker(Node *node, pgssConstLocations *jstate) case T_CopyStmt: if (jstate->normalize_utility_only) return false; return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate); + case T_CallStmt: + if (jstate->normalize_utility_only) return false; + return const_record_walker((Node *) ((CallStmt *) node)->funccall, jstate); case T_ExplainStmt: return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate); case T_CreateRoleStmt: diff --git a/c_src/libpg_query/src/pg_query_raw_tree_walker_supports.c b/c_src/libpg_query/src/pg_query_raw_tree_walker_supports.c new file mode 100644 index 00000000..ff20529a --- /dev/null +++ b/c_src/libpg_query/src/pg_query_raw_tree_walker_supports.c @@ -0,0 +1,117 @@ +#include + +#include "pg_query.h" +#include "pg_query_internal.h" +#include "pg_query_outfuncs.h" + +#include "parser/parser.h" +#include "parser/scanner.h" +#include "parser/scansup.h" + +#include "nodes/execnodes.h" +#include "nodes/nodeFuncs.h" +#include "nodes/pathnodes.h" + +#include "utils/builtins.h" + +/* + * Returns true if raw_expression_tree_walker() handles it, + * otherwise, returns false. + * + * Up-to-date with postgres 17' implementation as of Aug 19 2025. + * https://github.com/postgres/postgres/blob/REL_17_STABLE/src/backend/nodes/nodeFuncs.c#L3964 + */ +bool +pg_query_raw_tree_walker_supports(Node *node) +{ + switch (nodeTag(node)) + { + case T_JsonFormat: + case T_SetToDefault: + case T_CurrentOfExpr: + case T_SQLValueFunction: + case T_Integer: + case T_Float: + case T_Boolean: + case T_String: + case T_BitString: + case T_ParamRef: + case T_A_Const: + case T_A_Star: + case T_MergeSupportFunc: + case T_Alias: + case T_RangeVar: + case T_GroupingFunc: + case T_SubLink: + case T_CaseExpr: + case T_RowExpr: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_XmlExpr: + case T_JsonReturning: + case T_JsonValueExpr: + case T_JsonParseExpr: + case T_JsonScalarExpr: + case T_JsonSerializeExpr: + case T_JsonConstructorExpr: + case T_JsonIsPredicate: + case T_JsonArgument: + case T_JsonFuncExpr: + case T_JsonBehavior: + case T_JsonTable: + case T_JsonTableColumn: + case T_JsonTablePathSpec: + case T_NullTest: + case T_BooleanTest: + case T_JoinExpr: + case T_IntoClause: + case T_List: + case T_InsertStmt: + case T_DeleteStmt: + case T_UpdateStmt: + case T_MergeStmt: + case T_MergeWhenClause: + case T_SelectStmt: + case T_PLAssignStmt: + case T_A_Expr: + case T_BoolExpr: + case T_ColumnRef: + case T_FuncCall: + case T_NamedArgExpr: + case T_A_Indices: + case T_A_Indirection: + case T_A_ArrayExpr: + case T_ResTarget: + case T_MultiAssignRef: + case T_TypeCast: + case T_CollateClause: + case T_SortBy: + case T_WindowDef: + case T_RangeSubselect: + case T_RangeFunction: + case T_RangeTableSample: + case T_RangeTableFunc: + case T_RangeTableFuncCol: + case T_TypeName: + case T_ColumnDef: + case T_IndexElem: + case T_GroupingSet: + case T_LockingClause: + case T_XmlSerialize: + case T_WithClause: + case T_InferClause: + case T_OnConflictClause: + case T_CommonTableExpr: + case T_JsonOutput: + case T_JsonKeyValue: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonAggConstructor: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonArrayQueryConstructor: + return true; + default: + return false; + } +} diff --git a/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c b/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c index d0a7e21a..3e6f7cfa 100644 --- a/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c +++ b/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c @@ -96,8 +96,28 @@ static List * _readList(PgQuery__List *msg) static Node * _readNode(PgQuery__Node *msg) { + if (msg == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected NULL node in protobuf input"))); + switch (msg->node_case) { + /* + * Redefine READ_COND to guard against NULL inner struct pointers. + * When Elixir passes a tagged oneof value like {:column_ref, nil}, + * Protox may encode an empty sub-message, causing protobuf-c to set + * the inner pointer to a zeroed struct or NULL. Either way we must + * error cleanly rather than segfault inside the per-type reader. + */ +#undef READ_COND +#define READ_COND(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, outname) \ + case PG_QUERY__NODE__NODE_##typename_underscore_upcase: \ + if (msg->outname == NULL) \ + ereport(ERROR, \ + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ + errmsg("unexpected NULL inner struct in protobuf node"))); \ + return (Node *) _read##typename_c(msg->outname); #include "pg_query_readfuncs_conds.c" case PG_QUERY__NODE__NODE_INTEGER: @@ -145,7 +165,10 @@ static Node * _readNode(PgQuery__Node *msg) case PG_QUERY__NODE__NODE_LIST: return (Node *) _readList(msg->list); case PG_QUERY__NODE__NODE__NOT_SET: - return NULL; + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected unset node type in protobuf input"))); + return NULL; /* unreachable */ default: elog(ERROR, "unsupported protobuf node type: %d", (int) msg->node_case); @@ -160,11 +183,19 @@ List * pg_query_protobuf_to_nodes(PgQueryProtobuf protobuf) result = pg_query__parse_result__unpack(NULL, protobuf.len, (const uint8_t *) protobuf.data); - // TODO: Handle this by returning an error instead - Assert(result != NULL); + if (result == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("failed to unpack protobuf parse result: invalid or truncated input"))); - // TODO: Handle this by returning an error instead - Assert(result->version == PG_VERSION_NUM); + if (result->version != PG_VERSION_NUM) + { + pg_query__parse_result__free_unpacked(result, NULL); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("protobuf parse result version mismatch: expected %d, got %d", + PG_VERSION_NUM, result->version))); + } if (result->n_stmts > 0) list = list_make1(_readRawStmt(result->stmts[0])); diff --git a/c_src/libpg_query/src/pg_query_summary.c b/c_src/libpg_query/src/pg_query_summary.c new file mode 100644 index 00000000..b713bd5c --- /dev/null +++ b/c_src/libpg_query/src/pg_query_summary.c @@ -0,0 +1,941 @@ +#include "pg_query.h" +#include "pg_query_internal.h" +#include "pg_query_outfuncs.h" + +#include "catalog/namespace.h" + +#include "parser/parser.h" +#include "parser/scanner.h" +#include "parser/scansup.h" + +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "utils/builtins.h" + +#include "protobuf/pg_query.pb-c.h" + +#include +#include +#include + +#include "pg_query_summary.h" + +static char *range_var_to_name(RangeVar *rv); +static bool cte_names_include(WalkState * state, char *relname); + + +static PgQueryError * make_pg_query_error(const char *message) +{ + PgQueryError *error = malloc(sizeof(PgQueryError)); + + error->message = strdup(message); + return error; +} + +/* + * Given a Node (node) and WalkState (state), wraps node in a RangeVarWithContext + * and adds it to the state->range_vars list. + */ +static void +add_range_var(Node *node, ContextType context, WalkState * state) +{ + if (!node) + return; + + switch (node->type) + { + case T_JoinExpr: + { + JoinExpr *je = castNode(JoinExpr, node); + + add_range_var(je->larg, context, state); + add_range_var(je->rarg, context, state); + /* je->quals is handled by the regular tree walk. */ + break; + } + + case T_RangeTableSample: + { + RangeTableSample *rts = castNode(RangeTableSample, node); + + add_range_var(rts->relation, context, state); + break; + } + + case T_JsonTable: + case T_RangeTableFunc: + case T_RangeFunction: + case T_RangeSubselect: + /* These are handled by the tree walker. */ + break; + + case T_RangeVar: + { + RangeVarWithContext *rvwc = palloc(sizeof(RangeVarWithContext)); + + rvwc->node = castNode(RangeVar, node); + rvwc->context = context; + + state->range_vars = lappend(state->range_vars, rvwc); + break; + } + + default: + elog(ERROR, "unexpected node type: %d", nodeTag(node)); + } +} + +/* + * Given a List*-of-Nodes (clause) and WalkState (state), wrap them all + * in RangeVarWithContext structs and add them to the state->range_vars list. + */ +static void +add_range_var_list(List *clause, ContextType context, WalkState * state) +{ + if (!clause) + return; + + ListCell *lc = NULL; + + foreach(lc, clause) + { + add_range_var(lfirst(lc), context, state); + } +} + +static void +add_function(List *funcname, ContextType context, WalkState * state) +{ + SummaryFunction *func = palloc(sizeof(SummaryFunction)); + + func->name = NameListToString(funcname); + + if (list_length(funcname) == 3) + func->schema_name = lsecond_node(String, funcname)->sval; + else if (list_length(funcname) == 2) + func->schema_name = linitial_node(String, funcname)->sval; + else + func->schema_name = NULL; + + func->function_name = llast_node(String, funcname)->sval; + + func->context = context; + + state->functions = lappend(state->functions, func); +} + +bool +pg_query_summary_walk_impl(Node *node, WalkState * state) +{ + if (node == NULL) + return false; + + switch (nodeTag(node)) + { + case T_CommonTableExpr: + { + CommonTableExpr *cte = castNode(CommonTableExpr, node); + + state->cte_names = lappend(state->cte_names, pstrdup(cte->ctename)); + break; + } + + case T_CallStmt: + { + CallStmt *stmt = castNode(CallStmt, node); + + if (stmt->funccall) + return pg_query_summary_walk_impl((Node *) stmt->funccall, state); + } + + case T_SelectStmt: + { + /* + * Don't descend into sub-SELECTs in the WHERE clause when + * saving filter columns. + */ + if (state->save_filter_columns) + return true; + + SelectStmt *stmt = castNode(SelectStmt, node); + + if (stmt->op == SETOP_NONE) + add_range_var_list(stmt->fromClause, CONTEXT_SELECT, state); + + /* + * For SETOP_UNION, SETOP_EXCEPT, and SETOP_INTERSECT, the + * raw_expression_tree_walker() call at the end of this + * function will handle stmt->larg/stmt->rarg. + */ + + if (stmt->intoClause) + add_range_var((Node *) stmt->intoClause->rel, CONTEXT_DDL, state); + + if (stmt->whereClause) + { + /* + * If we have a WHERE clause, that means we have to check + * for filter columns. + * + * NOTE: the WHERE clause is intentionally walked twice, + * but when saving filter columns we don't descend into + * sub-SELECTs. + */ + state->save_filter_columns = true; + pg_query_summary_walk_impl((Node *) stmt->whereClause, state); + state->save_filter_columns = false; + } + + break; + } + + case T_InsertStmt: + { + add_range_var((Node *) castNode(InsertStmt, node)->relation, CONTEXT_DML, state); + break; + } + + case T_UpdateStmt: + { + UpdateStmt *stmt = castNode(UpdateStmt, node); + + add_range_var((Node *) stmt->relation, CONTEXT_DML, state); + add_range_var_list(stmt->fromClause, CONTEXT_SELECT, state); + break; + } + + case T_MergeStmt: + { + MergeStmt *stmt = castNode(MergeStmt, node); + + add_range_var((Node *) stmt->relation, CONTEXT_DML, state); + break; + } + + case T_DeleteStmt: + { + DeleteStmt *stmt = castNode(DeleteStmt, node); + + add_range_var((Node *) stmt->relation, CONTEXT_DML, state); + add_range_var_list(stmt->usingClause, CONTEXT_SELECT, state); + break; + } + + case T_CopyStmt: + { + CopyStmt *stmt = castNode(CopyStmt, node); + + add_range_var((Node *) stmt->relation, CONTEXT_SELECT, state); + pg_query_summary_walk_impl((Node *) stmt->query, state); + break; + } + + case T_AlterTableStmt: + { + AlterTableStmt *stmt = castNode(AlterTableStmt, node); + + /* `ALTER INDEX index_name` is ignored. */ + if (stmt->objtype != OBJECT_INDEX) + add_range_var((Node *) stmt->relation, CONTEXT_DDL, state); + + break; + } + + case T_CreateStmt: + add_range_var((Node *) castNode(CreateStmt, node)->relation, CONTEXT_DDL, state); + break; + + case T_CreateTableAsStmt: + { + CreateTableAsStmt *stmt = castNode(CreateTableAsStmt, node); + + if (stmt->into && stmt->into->rel) + add_range_var((Node *) stmt->into->rel, CONTEXT_DDL, state); + + pg_query_summary_walk_impl(stmt->query, state); + + break; + } + + case T_TruncateStmt: + add_range_var_list(castNode(TruncateStmt, node)->relations, CONTEXT_DDL, state); + break; + + case T_ViewStmt: + { + ViewStmt *stmt = castNode(ViewStmt, node); + + add_range_var((Node *) stmt->view, CONTEXT_DDL, state); + pg_query_summary_walk_impl(stmt->query, state); + break; + } + + case T_IndexStmt: + { + IndexStmt *stmt = castNode(IndexStmt, node); + + add_range_var((Node *) stmt->relation, CONTEXT_DDL, state); + + ListCell *lc = NULL; + + foreach(lc, stmt->indexParams) + { + IndexElem *index_elem = lfirst(lc); + + pg_query_summary_walk_impl(index_elem->expr, state); + } + + pg_query_summary_walk_impl(stmt->whereClause, state); + + break; + } + + case T_CreateTrigStmt: + add_range_var((Node *) castNode(CreateTrigStmt, node)->relation, CONTEXT_DDL, state); + break; + + case T_RuleStmt: + add_range_var((Node *) castNode(RuleStmt, node)->relation, CONTEXT_DDL, state); + break; + + case T_VacuumStmt: + { + VacuumStmt *stmt = castNode(VacuumStmt, node); + + ListCell *lc = NULL; + + foreach(lc, stmt->rels) + { + VacuumRelation *rel = lfirst(lc); + + add_range_var((Node *) rel->relation, CONTEXT_DDL, state); + } + + break; + } + + case T_RefreshMatViewStmt: + add_range_var((Node *) castNode(RefreshMatViewStmt, node)->relation, CONTEXT_DDL, state); + break; + + case T_DropStmt: + { + DropStmt *stmt = castNode(DropStmt, node); + + switch (stmt->removeType) + { + case OBJECT_TABLE: + { + ListCell *lc = NULL; + + foreach(lc, stmt->objects) + { + Node *obj = lfirst(lc); + + if (obj->type == T_List) + { + List *list = castNode(List, obj); + + if (list_length(list) == 0) + continue; + + RangeVar *range_var = makeRangeVarFromNameList(list); + + add_range_var((Node *) range_var, CONTEXT_DDL, state); + } + } + break; + } + case OBJECT_RULE: + case OBJECT_TRIGGER: + { + ListCell *lc = NULL; + + foreach(lc, stmt->objects) + { + Node *obj = lfirst(lc); + + if (obj->type == T_List) + { + List *olist = castNode(List, obj); + + /* + * Ignore the last string (the + * rule/trigger name) + */ + List *list = list_copy(olist); + + list = list_truncate(list, list_length(list) - 1); + + if (list_length(list) == 0) + continue; + + RangeVar *range_var = makeRangeVarFromNameList(list); + + add_range_var((Node *) range_var, CONTEXT_DDL, state); + } + } + break; + } + + case OBJECT_FUNCTION: + { + Node *obj_node = linitial(stmt->objects); + + if (obj_node != NULL && obj_node->type == T_ObjectWithArgs) + { + ObjectWithArgs *obj = castNode(ObjectWithArgs, obj_node); + + if (obj->objname) + add_function(obj->objname, CONTEXT_DDL, state); + } + + break; + } + + default: + break; + } + break; + } + + case T_GrantStmt: + { + GrantStmt *stmt = castNode(GrantStmt, node); + List *objects = stmt->objects; + + switch (stmt->objtype) + { + case OBJECT_TABLE: + { + ListCell *lc = NULL; + + foreach(lc, stmt->objects) + { + if (IsA(lfirst(lc), RangeVar)) + add_range_var(lfirst(lc), CONTEXT_DDL, state); + } + break; + } + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + { + ListCell *lc = NULL; + + foreach(lc, stmt->objects) + { + Node *obj_node = lfirst(lc); + + if (IsA(obj_node, ObjectWithArgs)) + { + ObjectWithArgs *obj = castNode(ObjectWithArgs, obj_node); + + if (obj->objname) + add_function(obj->objname, CONTEXT_DDL, state); + } + } + } + default: + + /* + * Do nothing. + * + * Other grant types don't contain table/function + * references. + */ + break; + } + break; + } + + case T_LockStmt: + add_range_var_list(castNode(LockStmt, node)->relations, CONTEXT_DDL, state); + break; + + case T_ExplainStmt: + return pg_query_summary_walk_impl(castNode(ExplainStmt, node)->query, state); + + case T_CreateFunctionStmt: + add_function(castNode(CreateFunctionStmt, node)->funcname, CONTEXT_DDL, state); + break; + + case T_RenameStmt: + { + RenameStmt *stmt = castNode(RenameStmt, node); + + switch (stmt->renameType) + { + case OBJECT_TABLE: + add_range_var((Node *) stmt->relation, CONTEXT_DDL, state); + add_range_var((Node *) makeRangeVar(stmt->relation->schemaname, stmt->newname, -1), CONTEXT_DDL, state); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + { + ObjectWithArgs *obj = castNode(ObjectWithArgs, stmt->object); + + add_function(obj->objname, CONTEXT_DDL, state); + add_function(list_make1(makeString(stmt->newname)), CONTEXT_DDL, state); + break; + } + default: + + /* + * Do nothing. + * + * Other rename types don't contain table/function + * references. + */ + break; + } + break; + } + + case T_PrepareStmt: + return pg_query_summary_walk_impl(castNode(PrepareStmt, node)->query, state); + + case T_RawStmt: + return pg_query_summary_walk_impl(castNode(RawStmt, node)->stmt, state); + + case T_FuncCall: + add_function(castNode(FuncCall, node)->funcname, CONTEXT_CALL, state); + break; + + /* + * The following are added to avoid needing subselect_items, + * + * like is used in Rust and Ruby. + */ + case T_ColumnRef: + { + if (!state->save_filter_columns) + break; + + ColumnRef *ref = castNode(ColumnRef, node); + + Node *column_node = llast(ref->fields); + + /* + * Check that we are not in the A_Star case here. (Columns can + * be stars, but nothing else can.) + */ + if (!IsA(column_node, String)) + break; + + String *schema_name = NULL; + String *table_name = NULL; + String *column = castNode(String, column_node); + + size_t num_fields = list_length(ref->fields); + + if (num_fields == 2) + { + table_name = linitial(ref->fields); + } + else if (num_fields == 3) + { + schema_name = linitial(ref->fields); + table_name = lsecond_node(String, ref->fields); + } + + FilterColumn *fc = palloc(sizeof(FilterColumn)); + + fc->schema_name = schema_name ? schema_name->sval : NULL; + fc->table_name = table_name ? table_name->sval : NULL; + fc->column = column ? column->sval : NULL; + + state->filter_columns = lappend(state->filter_columns, fc); + + break; + } + + default: + break; + } + + if (!pg_query_raw_tree_walker_supports(node)) + return false; + + return raw_expression_tree_walker(node, pg_query_summary_walk_impl, (void *) state); +} + +static char * +range_var_to_name(RangeVar *rv) +{ + StringInfoData buf; + + initStringInfo(&buf); + if (rv->schemaname != NULL) + { + appendStringInfoString(&buf, quote_identifier(rv->schemaname)); + appendStringInfoChar(&buf, '.'); + } + appendStringInfoString(&buf, quote_identifier(rv->relname)); + return buf.data; +} + +/* + * Walk through all collected cte_names, and compares them to relname. + * + * Returns true if any are an exact match, false otherwise. + */ +static bool +cte_names_include(WalkState * state, char *relname) +{ + if (relname == NULL) + return false; + + ListCell *lc = NULL; + + foreach(lc, state->cte_names) + { + char *ctename = lfirst(lc); + + if (strcmp(ctename, relname) == 0) + return true; + } + return false; +} + +static void +handle_range_var(RangeVar *node, ContextType context, WalkState * state) +{ + if (node == NULL) + return; + + RangeVar *rv = node; + + if (!cte_names_include(state, rv->relname)) + { + SummaryTable *table = palloc(sizeof(SummaryTable)); + + table->name = range_var_to_name(rv); + table->schema_name = pstrdup(rv->schemaname ? rv->schemaname : ""); + table->table_name = pstrdup(rv->relname ? rv->relname : ""); + table->context = context; + + state->tables = lappend(state->tables, table); + } + + if (rv->alias) + { + SummaryAlias *alias = palloc(sizeof(SummaryAlias)); + + alias->key = rv->alias->aliasname; + alias->value = range_var_to_name(rv); + state->aliases = lappend(state->aliases, alias); + } +} + +/* Walk the parse tree, storing the results in `summary`. */ +static void +pg_query_summary_walk(Summary * summary, Node *tree) +{ + WalkState state = {0}; + + /* + * NOTE regarding cte_names and range_vars: + * - We process cte_names as we iterate through the tree. + * - We only add items to tables if they are *not* in cte_names. + * - CTEs can be defined *after* they're referenced as names. + * - Due to this, we store range_vars and process it after the tree walk. + * + * If we try to do it entirely on the initial pass, we wind up with CTEs + * being included in state->tables, and thus in summary->tables. + */ + + pg_query_summary_walk_impl(tree, &state); + + ListCell *lc = NULL; + + foreach(lc, state.range_vars) + { + RangeVarWithContext *rvwc = lfirst(lc); + + handle_range_var(rvwc->node, rvwc->context, &state); + + pfree(rvwc); + } + + if (state.tables != NULL) + summary->tables = state.tables; + + if (state.aliases != NULL) + summary->aliases = state.aliases; + + if (state.cte_names != NULL) + summary->cte_names = state.cte_names; + + if (state.functions != NULL) + summary->functions = state.functions; + + if (state.filter_columns != NULL) + summary->filter_columns = state.filter_columns; +} + +static PgQuery__SummaryResult__Context ctx_to_protobuf_ctx(ContextType ctx) +{ + /* + * We're converting from an enum we control (ContextType) to an enum which + * is auto-generated by protobuf (PgQuery__SummaryResult__Context). + * + * While these should always be equivalent, we can't guarantee correctness + * with a simple cast. (It is theoretically possible for the internal + * representations to diverge while being functionally equivalent.) + * + * So, instead, we do a switch/case and manually convert it. + */ + switch (ctx) + { + case CONTEXT_NONE: + return PG_QUERY__SUMMARY_RESULT__CONTEXT__None; + case CONTEXT_SELECT: + return PG_QUERY__SUMMARY_RESULT__CONTEXT__Select; + case CONTEXT_DML: + return PG_QUERY__SUMMARY_RESULT__CONTEXT__DML; + case CONTEXT_DDL: + return PG_QUERY__SUMMARY_RESULT__CONTEXT__DDL; + case CONTEXT_CALL: + return PG_QUERY__SUMMARY_RESULT__CONTEXT__Call; + default: + return PG_QUERY__SUMMARY_RESULT__CONTEXT__None; + } +} + +/* Given the summarized query, convert it to protobuf, and store it in `result`. */ +static void +summary_to_protobuf(PgQuerySummaryParseResult * result, Summary * summary) +{ + PgQueryProtobuf protobuf; + PgQuery__SummaryResult sr = PG_QUERY__SUMMARY_RESULT__INIT; + + sr.n_tables = list_length(summary->tables); + sr.tables = palloc(sizeof(PgQuery__SummaryResult__Table *) * sr.n_tables); + + ListCell *lc = NULL; + + foreach(lc, summary->tables) + { + size_t i = foreach_current_index(lc); + SummaryTable *table = lfirst(lc); + + sr.tables[i] = palloc(sizeof(PgQuery__SummaryResult__Table)); + pg_query__summary_result__table__init(sr.tables[i]); + sr.tables[i]->name = table->name; + sr.tables[i]->schema_name = table->schema_name; + sr.tables[i]->table_name = table->table_name; + sr.tables[i]->context = ctx_to_protobuf_ctx(table->context); + } + + sr.n_aliases = list_length(summary->aliases); + sr.aliases = palloc(sizeof(PgQuery__SummaryResult__AliasesEntry *) * sr.n_aliases); + foreach(lc, summary->aliases) + { + size_t i = foreach_current_index(lc); + SummaryAlias *alias = lfirst(lc); + + sr.aliases[i] = palloc(sizeof(PgQuery__SummaryResult__AliasesEntry)); + pg_query__summary_result__aliases_entry__init(sr.aliases[i]); + sr.aliases[i]->key = alias->key; + sr.aliases[i]->value = alias->value; + } + + sr.n_cte_names = list_length(summary->cte_names); + sr.cte_names = palloc(sizeof(char *) * sr.n_cte_names); + foreach(lc, summary->cte_names) + { + size_t i = foreach_current_index(lc); + char *ctename = lfirst(lc); + + sr.cte_names[i] = ctename; + } + + sr.n_functions = list_length(summary->functions); + sr.functions = palloc(sizeof(PgQuery__SummaryResult__Function *) * sr.n_functions); + foreach(lc, summary->functions) + { + size_t i = foreach_current_index(lc); + SummaryFunction *fn = lfirst(lc); + + sr.functions[i] = palloc(sizeof(PgQuery__SummaryResult__Function)); + pg_query__summary_result__function__init(sr.functions[i]); + sr.functions[i]->name = fn->name; + sr.functions[i]->function_name = fn->function_name; + sr.functions[i]->schema_name = fn->schema_name; + sr.functions[i]->context = ctx_to_protobuf_ctx(fn->context); + } + + sr.n_filter_columns = list_length(summary->filter_columns); + sr.filter_columns = palloc(sizeof(PgQuery__SummaryResult__FilterColumn *) * sr.n_filter_columns); + foreach(lc, summary->filter_columns) + { + size_t i = foreach_current_index(lc); + FilterColumn *fc = lfirst(lc); + + sr.filter_columns[i] = palloc(sizeof(PgQuery__SummaryResult__FilterColumn)); + pg_query__summary_result__filter_column__init(sr.filter_columns[i]); + sr.filter_columns[i]->schema_name = fc->schema_name; + sr.filter_columns[i]->table_name = fc->table_name; + sr.filter_columns[i]->column = fc->column; + } + + sr.n_statement_types = list_length(summary->statement_types); + sr.statement_types = palloc(sizeof(char *) * sr.n_statement_types); + foreach(lc, summary->statement_types) + { + size_t i = foreach_current_index(lc); + char *st = lfirst(lc); + + sr.statement_types[i] = pstrdup(st); + } + + if (summary->truncated_query == NULL) + sr.truncated_query = pstrdup(""); + else + sr.truncated_query = summary->truncated_query; + + size_t len = pg_query__summary_result__get_packed_size(&sr); + + /* + * Note: This is intentionally malloc so exiting the memory context + * doesn't free this + */ + char *data = malloc(sizeof(char) * len); + + size_t written = pg_query__summary_result__pack(&sr, (void *) data); + + if (written == len) + { + result->summary.len = len; + result->summary.data = data; + } + else + { + result->error = make_pg_query_error("summary_to_protobuf() wrote wrong amount of data?"); + } + + for (size_t i = 0; i < sr.n_tables; i++) + pfree(sr.tables[i]); + pfree(sr.tables); + + for (size_t i = 0; i < sr.n_aliases; i++) + pfree(sr.aliases[i]); + pfree(sr.aliases); + + for (size_t i = 0; i < sr.n_functions; i++) + pfree(sr.functions[i]); + pfree(sr.functions); + + for (size_t i = 0; i < sr.n_filter_columns; i++) + pfree(sr.filter_columns[i]); + pfree(sr.filter_columns); + + pfree(sr.truncated_query); +} + +/* + * Given a query, parser options, and truncate limit, provide a summary of the query. + * + * If `truncate_limit` is -1, no truncation is performed. + */ +PgQuerySummaryParseResultInternal +pg_query_summary_internal(const char *input, int parser_options, int truncate_limit) +{ + PgQueryInternalParsetreeAndError parsetree_and_error; + PgQuerySummaryParseResultInternal result = {0}; + Summary summary = {0}; + PgQueryError *error = NULL; + bool should_truncate = (truncate_limit != -1); + + parsetree_and_error = pg_query_raw_parse(input, parser_options); + result.stderr_buffer = parsetree_and_error.stderr_buffer; + result.error = parsetree_and_error.error; + + if (result.error == NULL) + { + pg_query_summary_walk(&summary, (Node *) parsetree_and_error.tree); + pg_query_summary_statement_walk(&summary, (Node *) parsetree_and_error.tree); + } + + if (result.error == NULL && should_truncate) + pg_query_summary_truncate(&summary, (Node *) parsetree_and_error.tree, truncate_limit); + + result.summary = summary; + + return result; +} + +PgQuerySummaryParseResult +pg_query_summary(const char *input, int parser_options, int truncate_limit) +{ + PgQuerySummaryParseResult result = {0}; + MemoryContext ctx = pg_query_enter_memory_context(); + + PG_TRY(); + { + PgQuerySummaryParseResultInternal internal_result = + pg_query_summary_internal(input, parser_options, truncate_limit); + + result.stderr_buffer = internal_result.stderr_buffer; + result.error = internal_result.error; + + if (result.error == NULL) + summary_to_protobuf(&result, &internal_result.summary); + } + PG_CATCH(); + { + ErrorData *error_data; + PgQueryError *error; + + MemoryContextSwitchTo(ctx); + error_data = CopyErrorData(); + + /* + * Note: This is intentionally malloc so exiting the memory context + * doesn't free this + */ + error = malloc(sizeof(PgQueryError)); + error->message = strdup(error_data->message); + error->filename = strdup(error_data->filename); + error->funcname = strdup(error_data->funcname); + error->context = NULL; + error->lineno = error_data->lineno; + error->cursorpos = error_data->cursorpos; + + result.error = error; + FlushErrorState(); + } + PG_END_TRY(); + + pg_query_exit_memory_context(ctx); + + return result; +} + +/* Free all of the various parts of PgQuerySummaryParseResultInternal. */ +void +pg_query_free_summary_parse_result_internal(PgQuerySummaryParseResultInternal result) +{ + if (result.error) + pg_query_free_error(result.error); + + if (result.stderr_buffer) + free(result.stderr_buffer); +} + +/* Free all of the various parts of a PgQuerySummaryParseResult. */ +void +pg_query_free_summary_parse_result(PgQuerySummaryParseResult result) +{ + if (result.error) + pg_query_free_error(result.error); + + if (result.summary.data) + free(result.summary.data); + + /* This is allocated by strdup(), so it uses malloc() instead of palloc(). */ + if (result.stderr_buffer) + free(result.stderr_buffer); +} diff --git a/c_src/libpg_query/src/pg_query_summary.h b/c_src/libpg_query/src/pg_query_summary.h new file mode 100644 index 00000000..01fb54ed --- /dev/null +++ b/c_src/libpg_query/src/pg_query_summary.h @@ -0,0 +1,109 @@ +#ifndef PG_QUERY_SUMMARY_H +#define PG_QUERY_SUMMARY_H + +#include "pg_query.h" +#include "pg_query_internal.h" + +#include "nodes/primnodes.h" + +#include + +typedef enum +{ + CONTEXT_NONE = 0, + CONTEXT_SELECT = 1, + CONTEXT_DML = 2, + CONTEXT_DDL = 3, + CONTEXT_CALL = 4, +} ContextType; + +typedef struct +{ + char *name; + char *schema_name; + char *table_name; + ContextType context; +} SummaryTable; + +typedef struct +{ + char *key; + char *value; +} SummaryAlias; + +typedef struct +{ + char *name; + char *function_name; + char *schema_name; /* optional */ + + + ContextType context; +} SummaryFunction; + +typedef struct +{ + char *schema_name; + char *table_name; + char *column; +} FilterColumn; + +typedef struct +{ + List *tables; /* List of SummaryTable */ + + List *aliases; /* List of SummaryAlias */ + List *cte_names; /* List of char */ + List *functions; /* List of SummaryFunction */ + List *filter_columns; /* List of FilterColumn */ + List *statement_types; /* List of char * */ + + char *truncated_query; +} Summary; + +typedef struct +{ + List *tables; /* List of Table * */ + List *aliases; /* List of SummaryAlias * */ + List *functions; /* List of Function * */ + List *range_vars; /* List of RangeVarWithContext * */ + List *cte_names; /* list of CommonTableExpr */ + List *filter_columns; /* List of FilterColumn * */ + bool save_filter_columns; /* If true, we should be adding to + * filter columns. */ +} WalkState; + +typedef struct +{ + RangeVar *node; + ContextType context; +} RangeVarWithContext; + +/* + * This is like PgQuerySummaryParseResult, but the summary is not wrapped + * up in protobuf. + */ +typedef struct +{ + Summary summary; + char *stderr_buffer; + PgQueryError *error; +} PgQuerySummaryParseResultInternal; + +extern bool pg_query_raw_tree_walker_supports(Node *node); + +extern void pg_query_summary_statement_walk(Summary * summary, Node *node); + +extern void pg_query_summary_truncate(Summary * summary, Node *node, int truncate_limit); + +/* + * This is like pg_query_summary(), but returns a (non-protobuf) + * PgQuerySummaryParseResultInternal instead of the usual + * PgQuerySummaryParseResult which converts the summary to protobuf. + * + * This is used for tests, to avoid having to process protobuf in C. + */ +extern PgQuerySummaryParseResultInternal pg_query_summary_internal(const char *input, int parser_options, int truncate_limit); +extern void pg_query_free_summary_parse_result_internal(PgQuerySummaryParseResultInternal result); + +#endif diff --git a/c_src/libpg_query/src/pg_query_summary_statement_type.c b/c_src/libpg_query/src/pg_query_summary_statement_type.c new file mode 100644 index 00000000..ddd45076 --- /dev/null +++ b/c_src/libpg_query/src/pg_query_summary_statement_type.c @@ -0,0 +1,797 @@ +#include "pg_query.h" +#include "pg_query_internal.h" +#include "pg_query_outfuncs.h" + +#include "parser/parser.h" +#include "parser/scanner.h" +#include "parser/scansup.h" + +#include "nodes/nodeFuncs.h" +#include "utils/builtins.h" + +#include +#include +#include + +#include "pg_query_summary.h" + +/* Declare the huge function early so we can put it at the end of the file. */ +static bool pg_query_summary_stmt_walk_impl(Node *node, Summary * summary); + +/* + * Adds new_stmt_type to summary->statement_types, if it's not already in it. + * What we really want is a set, but I'd rather not implement one in C. + */ +void +add_stmt_type_if_needed(Summary * summary, char *new_stmt_type) +{ + ListCell *lc = NULL; + + foreach(lc, summary->statement_types) + { + char *stmt_type = lfirst(lc); + + if (strcmp(new_stmt_type, stmt_type) == 0) + return; + } + + summary->statement_types = lappend(summary->statement_types, new_stmt_type); +} + + +void +pg_query_summary_statement_walk(Summary * summary, Node *tree) +{ + pg_query_summary_stmt_walk_impl(tree, summary); +} + +static bool +pg_query_summary_stmt_walk_impl(Node *node, Summary * summary) +{ + if (node == NULL) + return false; + + switch (nodeTag(node)) + { + case T_AlterCollationStmt: + add_stmt_type_if_needed(summary, "AlterCollationStmt"); + break; + case T_AlterDatabaseSetStmt: + add_stmt_type_if_needed(summary, "AlterDatabaseSetStmt"); + break; + case T_AlterDatabaseStmt: + add_stmt_type_if_needed(summary, "AlterDatabaseStmt"); + break; + case T_AlterDefaultPrivilegesStmt: + add_stmt_type_if_needed(summary, "AlterDefaultPrivilegesStmt"); + break; + case T_AlterDomainStmt: + add_stmt_type_if_needed(summary, "AlterDomainStmt"); + break; + case T_AlterEnumStmt: + add_stmt_type_if_needed(summary, "AlterEnumStmt"); + break; + case T_AlterEventTrigStmt: + add_stmt_type_if_needed(summary, "AlterEventTrigStmt"); + break; + case T_AlterExtensionContentsStmt: + add_stmt_type_if_needed(summary, "AlterExtensionContentsStmt"); + break; + case T_AlterExtensionStmt: + add_stmt_type_if_needed(summary, "AlterExtensionStmt"); + break; + case T_AlterFdwStmt: + add_stmt_type_if_needed(summary, "AlterFdwStmt"); + break; + case T_AlterForeignServerStmt: + add_stmt_type_if_needed(summary, "AlterForeignServerStmt"); + break; + case T_AlterFunctionStmt: + add_stmt_type_if_needed(summary, "AlterFunctionStmt"); + break; + case T_AlterObjectDependsStmt: + add_stmt_type_if_needed(summary, "AlterObjectDependsStmt"); + break; + case T_AlterObjectSchemaStmt: + add_stmt_type_if_needed(summary, "AlterObjectSchemaStmt"); + break; + case T_AlterOpFamilyStmt: + add_stmt_type_if_needed(summary, "AlterOpFamilyStmt"); + break; + case T_AlterOperatorStmt: + add_stmt_type_if_needed(summary, "AlterOperatorStmt"); + break; + case T_AlterOwnerStmt: + add_stmt_type_if_needed(summary, "AlterOwnerStmt"); + break; + case T_AlterPolicyStmt: + add_stmt_type_if_needed(summary, "AlterPolicyStmt"); + break; + case T_AlterPublicationStmt: + add_stmt_type_if_needed(summary, "AlterPublicationStmt"); + break; + case T_AlterRoleSetStmt: + add_stmt_type_if_needed(summary, "AlterRoleSetStmt"); + break; + case T_AlterRoleStmt: + add_stmt_type_if_needed(summary, "AlterRoleStmt"); + break; + case T_AlterSeqStmt: + add_stmt_type_if_needed(summary, "AlterSeqStmt"); + break; + case T_AlterStatsStmt: + add_stmt_type_if_needed(summary, "AlterStatsStmt"); + break; + case T_AlterSubscriptionStmt: + add_stmt_type_if_needed(summary, "AlterSubscriptionStmt"); + break; + case T_AlterSystemStmt: + add_stmt_type_if_needed(summary, "AlterSystemStmt"); + break; + case T_AlterTableCmd: + add_stmt_type_if_needed(summary, "AlterTableCmd"); + break; + case T_AlterTableMoveAllStmt: + add_stmt_type_if_needed(summary, "AlterTableMoveAllStmt"); + break; + case T_AlterTableSpaceOptionsStmt: + add_stmt_type_if_needed(summary, "AlterTableSpaceOptionsStmt"); + break; + case T_AlterTableStmt: + add_stmt_type_if_needed(summary, "AlterTableStmt"); + break; + case T_AlterTSConfigurationStmt: + add_stmt_type_if_needed(summary, "AlterTSConfigurationStmt"); + break; + case T_AlterTSDictionaryStmt: + add_stmt_type_if_needed(summary, "AlterTSDictionaryStmt"); + break; + case T_AlterTypeStmt: + add_stmt_type_if_needed(summary, "AlterTypeStmt"); + break; + case T_AlterUserMappingStmt: + add_stmt_type_if_needed(summary, "AlterUserMappingStmt"); + break; + case T_CallStmt: + add_stmt_type_if_needed(summary, "CallStmt"); + break; + case T_CheckPointStmt: + add_stmt_type_if_needed(summary, "CheckPointStmt"); + break; + case T_ClosePortalStmt: + add_stmt_type_if_needed(summary, "ClosePortalStmt"); + break; + case T_ClusterStmt: + add_stmt_type_if_needed(summary, "ClusterStmt"); + break; + case T_CommentStmt: + add_stmt_type_if_needed(summary, "CommentStmt"); + break; + case T_CompositeTypeStmt: + add_stmt_type_if_needed(summary, "CompositeTypeStmt"); + break; + case T_ConstraintsSetStmt: + add_stmt_type_if_needed(summary, "ConstraintsSetStmt"); + break; + case T_CopyStmt: + add_stmt_type_if_needed(summary, "CopyStmt"); + break; + case T_CreateAmStmt: + add_stmt_type_if_needed(summary, "CreateAmStmt"); + break; + case T_CreateCastStmt: + add_stmt_type_if_needed(summary, "CreateCastStmt"); + break; + case T_CreateConversionStmt: + add_stmt_type_if_needed(summary, "CreateConversionStmt"); + break; + case T_CreateDomainStmt: + add_stmt_type_if_needed(summary, "CreateDomainStmt"); + break; + case T_CreateEnumStmt: + add_stmt_type_if_needed(summary, "CreateEnumStmt"); + break; + case T_CreateEventTrigStmt: + add_stmt_type_if_needed(summary, "CreateEventTrigStmt"); + break; + case T_CreateExtensionStmt: + add_stmt_type_if_needed(summary, "CreateExtensionStmt"); + break; + case T_CreateFdwStmt: + add_stmt_type_if_needed(summary, "CreateFdwStmt"); + break; + case T_CreateForeignServerStmt: + add_stmt_type_if_needed(summary, "CreateForeignServerStmt"); + break; + case T_CreateForeignTableStmt: + add_stmt_type_if_needed(summary, "CreateForeignTableStmt"); + break; + case T_CreateFunctionStmt: + add_stmt_type_if_needed(summary, "CreateFunctionStmt"); + break; + case T_CreateOpClassStmt: + add_stmt_type_if_needed(summary, "CreateOpClassStmt"); + break; + case T_CreateOpFamilyStmt: + add_stmt_type_if_needed(summary, "CreateOpFamilyStmt"); + break; + case T_CreatePLangStmt: + add_stmt_type_if_needed(summary, "CreatePLangStmt"); + break; + case T_CreatePolicyStmt: + add_stmt_type_if_needed(summary, "CreatePolicyStmt"); + break; + case T_CreatePublicationStmt: + add_stmt_type_if_needed(summary, "CreatePublicationStmt"); + break; + case T_CreateRangeStmt: + add_stmt_type_if_needed(summary, "CreateRangeStmt"); + break; + case T_CreateRoleStmt: + add_stmt_type_if_needed(summary, "CreateRoleStmt"); + break; + case T_CreateSchemaStmt: + add_stmt_type_if_needed(summary, "CreateSchemaStmt"); + break; + case T_CreateSeqStmt: + add_stmt_type_if_needed(summary, "CreateSeqStmt"); + break; + case T_CreateStatsStmt: + add_stmt_type_if_needed(summary, "CreateStatsStmt"); + break; + case T_CreateStmt: + add_stmt_type_if_needed(summary, "CreateStmt"); + break; + case T_CreateSubscriptionStmt: + add_stmt_type_if_needed(summary, "CreateSubscriptionStmt"); + break; + case T_CreateTableAsStmt: + { + add_stmt_type_if_needed(summary, "CreateTableAsStmt"); + CreateTableAsStmt *stmt = (CreateTableAsStmt *) node; + + if (stmt->query) + pg_query_summary_stmt_walk_impl(stmt->query, summary); + break; + } + case T_CreateTableSpaceStmt: + add_stmt_type_if_needed(summary, "CreateTableSpaceStmt"); + break; + case T_CreateTransformStmt: + add_stmt_type_if_needed(summary, "CreateTransformStmt"); + break; + case T_CreateTrigStmt: + add_stmt_type_if_needed(summary, "CreateTrigStmt"); + break; + case T_CreateUserMappingStmt: + add_stmt_type_if_needed(summary, "CreateUserMappingStmt"); + break; + case T_CreatedbStmt: + add_stmt_type_if_needed(summary, "CreatedbStmt"); + break; + case T_DeallocateStmt: + add_stmt_type_if_needed(summary, "DeallocateStmt"); + break; + case T_DeclareCursorStmt: + add_stmt_type_if_needed(summary, "DeclareCursorStmt"); + break; + case T_DefineStmt: + add_stmt_type_if_needed(summary, "DefineStmt"); + break; + case T_DeleteStmt: + add_stmt_type_if_needed(summary, "DeleteStmt"); + break; + case T_DiscardStmt: + add_stmt_type_if_needed(summary, "DiscardStmt"); + break; + case T_DoStmt: + add_stmt_type_if_needed(summary, "DoStmt"); + break; + case T_DropOwnedStmt: + add_stmt_type_if_needed(summary, "DropOwnedStmt"); + break; + case T_DropRoleStmt: + add_stmt_type_if_needed(summary, "DropRoleStmt"); + break; + case T_DropStmt: + add_stmt_type_if_needed(summary, "DropStmt"); + break; + case T_DropSubscriptionStmt: + add_stmt_type_if_needed(summary, "DropSubscriptionStmt"); + break; + case T_DropTableSpaceStmt: + add_stmt_type_if_needed(summary, "DropTableSpaceStmt"); + break; + case T_DropUserMappingStmt: + add_stmt_type_if_needed(summary, "DropUserMappingStmt"); + break; + case T_DropdbStmt: + add_stmt_type_if_needed(summary, "DropdbStmt"); + break; + case T_ExecuteStmt: + add_stmt_type_if_needed(summary, "ExecuteStmt"); + break; + case T_ExplainStmt: + { + add_stmt_type_if_needed(summary, "ExplainStmt"); + ExplainStmt *stmt = (ExplainStmt *) node; + + if (stmt->query) + pg_query_summary_stmt_walk_impl(stmt->query, summary); + break; + } + case T_FetchStmt: + add_stmt_type_if_needed(summary, "FetchStmt"); + break; + case T_GrantRoleStmt: + add_stmt_type_if_needed(summary, "GrantRoleStmt"); + break; + case T_GrantStmt: + add_stmt_type_if_needed(summary, "GrantStmt"); + break; + case T_ImportForeignSchemaStmt: + add_stmt_type_if_needed(summary, "ImportForeignSchemaStmt"); + break; + case T_IndexStmt: + add_stmt_type_if_needed(summary, "IndexStmt"); + break; + case T_InsertStmt: + add_stmt_type_if_needed(summary, "InsertStmt"); + break; + case T_ListenStmt: + add_stmt_type_if_needed(summary, "ListenStmt"); + break; + case T_LoadStmt: + add_stmt_type_if_needed(summary, "LoadStmt"); + break; + case T_LockStmt: + add_stmt_type_if_needed(summary, "LockStmt"); + break; + case T_MergeStmt: + add_stmt_type_if_needed(summary, "MergeStmt"); + break; + case T_NotifyStmt: + add_stmt_type_if_needed(summary, "NotifyStmt"); + break; + case T_PrepareStmt: + { + add_stmt_type_if_needed(summary, "PrepareStmt"); + PrepareStmt *stmt = (PrepareStmt *) node; + + if (stmt->query) + pg_query_summary_stmt_walk_impl(stmt->query, summary); + break; + } + case T_ReassignOwnedStmt: + add_stmt_type_if_needed(summary, "ReassignOwnedStmt"); + break; + case T_RefreshMatViewStmt: + add_stmt_type_if_needed(summary, "RefreshMatViewStmt"); + break; + case T_ReindexStmt: + add_stmt_type_if_needed(summary, "ReindexStmt"); + break; + case T_RenameStmt: + add_stmt_type_if_needed(summary, "RenameStmt"); + break; + case T_ReplicaIdentityStmt: + add_stmt_type_if_needed(summary, "ReplicaIdentityStmt"); + break; + case T_RuleStmt: + add_stmt_type_if_needed(summary, "RuleStmt"); + break; + case T_SecLabelStmt: + add_stmt_type_if_needed(summary, "SecLabelStmt"); + break; + case T_SelectStmt: + add_stmt_type_if_needed(summary, "SelectStmt"); + break; + case T_SetOperationStmt: + add_stmt_type_if_needed(summary, "SetOperationStmt"); + break; + case T_TransactionStmt: + add_stmt_type_if_needed(summary, "TransactionStmt"); + break; + case T_TruncateStmt: + add_stmt_type_if_needed(summary, "TruncateStmt"); + break; + case T_UnlistenStmt: + add_stmt_type_if_needed(summary, "UnlistenStmt"); + break; + case T_UpdateStmt: + add_stmt_type_if_needed(summary, "UpdateStmt"); + break; + case T_VacuumStmt: + add_stmt_type_if_needed(summary, "VacuumStmt"); + break; + case T_VariableSetStmt: + add_stmt_type_if_needed(summary, "VariableSetStmt"); + break; + case T_VariableShowStmt: + add_stmt_type_if_needed(summary, "VariableShowStmt"); + break; + case T_ViewStmt: + { + add_stmt_type_if_needed(summary, "ViewStmt"); + ViewStmt *stmt = (ViewStmt *) node; + + if (stmt->query) + pg_query_summary_stmt_walk_impl(stmt->query, summary); + break; + } + case T_RawStmt: + return pg_query_summary_stmt_walk_impl(((RawStmt *) node)->stmt, summary); + + /* + * All the cases below here are not handled in the Rust version. + * They're added here so, if a new statement type (like MergeStmt) + * is added, the C compiler will generate a warning. + */ + case T_Invalid: + case T_List: + case T_Alias: + case T_RangeVar: + case T_TableFunc: + case T_IntoClause: + case T_Var: + case T_Const: + case T_Param: + case T_Aggref: + case T_GroupingFunc: + case T_WindowFunc: + case T_WindowFuncRunCondition: + case T_MergeSupportFunc: + case T_SubscriptingRef: + case T_FuncExpr: + case T_NamedArgExpr: + case T_OpExpr: + case T_DistinctExpr: + case T_NullIfExpr: + case T_ScalarArrayOpExpr: + case T_BoolExpr: + case T_SubLink: + case T_SubPlan: + case T_AlternativeSubPlan: + case T_FieldSelect: + case T_FieldStore: + case T_RelabelType: + case T_CoerceViaIO: + case T_ArrayCoerceExpr: + case T_ConvertRowtypeExpr: + case T_CollateExpr: + case T_CaseExpr: + case T_CaseWhen: + case T_CaseTestExpr: + case T_ArrayExpr: + case T_RowExpr: + case T_RowCompareExpr: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_SQLValueFunction: + case T_XmlExpr: + case T_JsonFormat: + case T_JsonReturning: + case T_JsonValueExpr: + case T_JsonConstructorExpr: + case T_JsonIsPredicate: + case T_JsonBehavior: + case T_JsonExpr: + case T_JsonTablePath: + case T_JsonTablePathScan: + case T_JsonTableSiblingJoin: + case T_NullTest: + case T_BooleanTest: + case T_MergeAction: + case T_CoerceToDomain: + case T_CoerceToDomainValue: + case T_SetToDefault: + case T_CurrentOfExpr: + case T_NextValueExpr: + case T_InferenceElem: + case T_TargetEntry: + case T_RangeTblRef: + case T_JoinExpr: + case T_FromExpr: + case T_OnConflictExpr: + case T_Query: + case T_TypeName: + case T_ColumnRef: + case T_ParamRef: + case T_A_Expr: + case T_A_Const: + case T_TypeCast: + case T_CollateClause: + case T_RoleSpec: + case T_FuncCall: + case T_A_Star: + case T_A_Indices: + case T_A_Indirection: + case T_A_ArrayExpr: + case T_ResTarget: + case T_MultiAssignRef: + case T_SortBy: + case T_WindowDef: + case T_RangeSubselect: + case T_RangeFunction: + case T_RangeTableFunc: + case T_RangeTableFuncCol: + case T_RangeTableSample: + case T_ColumnDef: + case T_TableLikeClause: + case T_IndexElem: + case T_DefElem: + case T_LockingClause: + case T_XmlSerialize: + case T_PartitionElem: + case T_PartitionSpec: + case T_PartitionBoundSpec: + case T_PartitionRangeDatum: + case T_SinglePartitionSpec: + case T_PartitionCmd: + case T_RangeTblEntry: + case T_RTEPermissionInfo: + case T_RangeTblFunction: + case T_TableSampleClause: + case T_WithCheckOption: + case T_SortGroupClause: + case T_GroupingSet: + case T_WindowClause: + case T_RowMarkClause: + case T_WithClause: + case T_InferClause: + case T_OnConflictClause: + case T_CTESearchClause: + case T_CTECycleClause: + case T_CommonTableExpr: + case T_MergeWhenClause: + case T_TriggerTransition: + case T_JsonOutput: + case T_JsonArgument: + case T_JsonFuncExpr: + case T_JsonTablePathSpec: + case T_JsonTable: + case T_JsonTableColumn: + case T_JsonKeyValue: + case T_JsonParseExpr: + case T_JsonScalarExpr: + case T_JsonSerializeExpr: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + case T_JsonAggConstructor: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_ReturnStmt: + case T_PLAssignStmt: + case T_ObjectWithArgs: + case T_AccessPriv: + case T_Constraint: + case T_CreateOpClassItem: + case T_StatsElem: + case T_FunctionParameter: + case T_InlineCodeBlock: + case T_CallContext: + case T_AlterDatabaseRefreshCollStmt: + case T_VacuumRelation: + case T_PublicationTable: + case T_PublicationObjSpec: + case T_PlannerGlobal: + case T_PlannerInfo: + case T_RelOptInfo: + case T_IndexOptInfo: + case T_ForeignKeyOptInfo: + case T_StatisticExtInfo: + case T_JoinDomain: + case T_EquivalenceClass: + case T_EquivalenceMember: + case T_PathKey: + case T_GroupByOrdering: + case T_PathTarget: + case T_ParamPathInfo: + case T_Path: + case T_IndexPath: + case T_IndexClause: + case T_BitmapHeapPath: + case T_BitmapAndPath: + case T_BitmapOrPath: + case T_TidPath: + case T_TidRangePath: + case T_SubqueryScanPath: + case T_ForeignPath: + case T_CustomPath: + case T_AppendPath: + case T_MergeAppendPath: + case T_GroupResultPath: + case T_MaterialPath: + case T_MemoizePath: + case T_UniquePath: + case T_GatherPath: + case T_GatherMergePath: + case T_NestPath: + case T_MergePath: + case T_HashPath: + case T_ProjectionPath: + case T_ProjectSetPath: + case T_SortPath: + case T_IncrementalSortPath: + case T_GroupPath: + case T_UpperUniquePath: + case T_AggPath: + case T_GroupingSetData: + case T_RollupData: + case T_GroupingSetsPath: + case T_MinMaxAggPath: + case T_WindowAggPath: + case T_SetOpPath: + case T_RecursiveUnionPath: + case T_LockRowsPath: + case T_ModifyTablePath: + case T_LimitPath: + case T_RestrictInfo: + case T_PlaceHolderVar: + case T_SpecialJoinInfo: + case T_OuterJoinClauseInfo: + case T_AppendRelInfo: + case T_RowIdentityVarInfo: + case T_PlaceHolderInfo: + case T_MinMaxAggInfo: + case T_PlannerParamItem: + case T_AggInfo: + case T_AggTransInfo: + case T_PlannedStmt: + case T_Result: + case T_ProjectSet: + case T_ModifyTable: + case T_Append: + case T_MergeAppend: + case T_RecursiveUnion: + case T_BitmapAnd: + case T_BitmapOr: + case T_SeqScan: + case T_SampleScan: + case T_IndexScan: + case T_IndexOnlyScan: + case T_BitmapIndexScan: + case T_BitmapHeapScan: + case T_TidScan: + case T_TidRangeScan: + case T_SubqueryScan: + case T_FunctionScan: + case T_ValuesScan: + case T_TableFuncScan: + case T_CteScan: + case T_NamedTuplestoreScan: + case T_WorkTableScan: + case T_ForeignScan: + case T_CustomScan: + case T_NestLoop: + case T_NestLoopParam: + case T_MergeJoin: + case T_HashJoin: + case T_Material: + case T_Memoize: + case T_Sort: + case T_IncrementalSort: + case T_Group: + case T_Agg: + case T_WindowAgg: + case T_Unique: + case T_Gather: + case T_GatherMerge: + case T_Hash: + case T_SetOp: + case T_LockRows: + case T_Limit: + case T_PlanRowMark: + case T_PartitionPruneInfo: + case T_PartitionedRelPruneInfo: + case T_PartitionPruneStepOp: + case T_PartitionPruneStepCombine: + case T_PlanInvalItem: + case T_ExprState: + case T_IndexInfo: + case T_ExprContext: + case T_ReturnSetInfo: + case T_ProjectionInfo: + case T_JunkFilter: + case T_OnConflictSetState: + case T_MergeActionState: + case T_ResultRelInfo: + case T_EState: + case T_WindowFuncExprState: + case T_SetExprState: + case T_SubPlanState: + case T_DomainConstraintState: + case T_ResultState: + case T_ProjectSetState: + case T_ModifyTableState: + case T_AppendState: + case T_MergeAppendState: + case T_RecursiveUnionState: + case T_BitmapAndState: + case T_BitmapOrState: + case T_ScanState: + case T_SeqScanState: + case T_SampleScanState: + case T_IndexScanState: + case T_IndexOnlyScanState: + case T_BitmapIndexScanState: + case T_BitmapHeapScanState: + case T_TidScanState: + case T_TidRangeScanState: + case T_SubqueryScanState: + case T_FunctionScanState: + case T_ValuesScanState: + case T_TableFuncScanState: + case T_CteScanState: + case T_NamedTuplestoreScanState: + case T_WorkTableScanState: + case T_ForeignScanState: + case T_CustomScanState: + case T_JoinState: + case T_NestLoopState: + case T_MergeJoinState: + case T_HashJoinState: + case T_MaterialState: + case T_MemoizeState: + case T_SortState: + case T_IncrementalSortState: + case T_GroupState: + case T_AggState: + case T_WindowAggState: + case T_UniqueState: + case T_GatherState: + case T_GatherMergeState: + case T_HashState: + case T_SetOpState: + case T_LockRowsState: + case T_LimitState: + case T_IndexAmRoutine: + case T_TableAmRoutine: + case T_TsmRoutine: + case T_EventTriggerData: + case T_TriggerData: + case T_TupleTableSlot: + case T_FdwRoutine: + case T_Bitmapset: + case T_ExtensibleNode: + case T_ErrorSaveContext: + case T_IdentifySystemCmd: + case T_BaseBackupCmd: + case T_CreateReplicationSlotCmd: + case T_DropReplicationSlotCmd: + case T_AlterReplicationSlotCmd: + case T_StartReplicationCmd: + case T_ReadReplicationSlotCmd: + case T_TimeLineHistoryCmd: + case T_UploadManifestCmd: + case T_SupportRequestSimplify: + case T_SupportRequestSelectivity: + case T_SupportRequestCost: + case T_SupportRequestRows: + case T_SupportRequestIndexCondition: + case T_SupportRequestWFuncMonotonic: + case T_SupportRequestOptimizeWindowClause: + case T_Integer: + case T_Float: + case T_Boolean: + case T_String: + case T_BitString: + case T_ForeignKeyCacheInfo: + case T_IntList: + case T_OidList: + case T_XidList: + case T_AllocSetContext: + case T_GenerationContext: + case T_SlabContext: + case T_BumpContext: + case T_TIDBitmap: + case T_WindowObjectData: + break; + } + + if (!pg_query_raw_tree_walker_supports(node)) + return false; + + return raw_expression_tree_walker(node, pg_query_summary_stmt_walk_impl, (void *) summary); +} diff --git a/c_src/libpg_query/src/pg_query_summary_truncate.c b/c_src/libpg_query/src/pg_query_summary_truncate.c new file mode 100644 index 00000000..4d67a91e --- /dev/null +++ b/c_src/libpg_query/src/pg_query_summary_truncate.c @@ -0,0 +1,530 @@ +#include "pg_query.h" +#include "pg_query_internal.h" +#include "pg_query_summary.h" + +#include "nodes/pg_list.h" +#include "nodes/nodeFuncs.h" + +#include "mb/pg_wchar.h" + +enum TruncationAttr +{ + TRUNCATION_TARGET_LIST, + TRUNCATION_WHERE_CLAUSE, + TRUNCATION_VALUES_LISTS, + TRUNCATION_COLS, + TRUNCATION_CTE_QUERY, +}; + +typedef struct +{ + List *truncations; + int32_t depth; +} TruncationState; + +typedef struct +{ + enum TruncationAttr attr; + Node *node; + int32_t depth; + int32_t length; +} PossibleTruncation; + +static bool generate_possible_truncations(Node *tree, TruncationState * state); +static void apply_truncations(Summary * summary, Node *tree, TruncationState * state, int truncate_limit); +static int cmp_possible_truncations(const ListCell *a, const ListCell *b); + +static int32_t select_target_list_len(List *nodes); +static int32_t select_values_lists_len(List *nodes); +static int32_t update_target_list_len(List *nodes); +static int32_t where_clause_len(Node *node); +static int32_t cols_len(List *nodes); + +static ColumnRef *dummy_column(void); +static ResTarget *dummy_target(void); +static Node *dummy_select(List *targetList, Node *whereClause, List *valuesLists); +static Node *dummy_insert(List *cols); +static Node *dummy_update(List *targetList); + +static size_t deparse_stmt_len(Node *node); +static StringInfo deparse_raw_stmt_list(List *stmts); + +/* Given a walked parse tree and summary, store the truncated version in `summary`. */ +void +pg_query_summary_truncate(Summary * summary, Node *tree, int truncate_limit) +{ + TruncationState state = {NULL, 0}; + + StringInfo output = deparse_raw_stmt_list((List *) tree); + + if (output->len <= truncate_limit) + { + summary->truncated_query = output->data; + return; + } + + destroyStringInfo(output); + + generate_possible_truncations(tree, &state); + + list_sort(state.truncations, cmp_possible_truncations); + apply_truncations(summary, tree, &state, truncate_limit); +} + +static void +truncate_mbstr(char *mbstr, size_t max_chars) +{ + /* Determine the number of characters in mbstr. */ + int n_chars = pg_mbstrlen(mbstr); + + /* If we don't need to truncate the string, return immediately. */ + if (n_chars <= max_chars) + return; + + /* Determine how many bytes hold `max_chars - 3`. */ + int n_bytes = pg_mbcharcliplen(mbstr, n_chars, max_chars - 3); + + /* Actually truncate it. */ + strncpy(mbstr + n_bytes, "...", 4); + mbstr[n_bytes + 3] = '\0'; +} + +static void +add_truncation(TruncationState * state, enum TruncationAttr attr, + Node *node, int32_t length) +{ + /* Don't bother truncating if it won't become shorter. */ + if (length <= 3) + return; + + PossibleTruncation *truncation = palloc(sizeof(PossibleTruncation)); + + truncation->attr = attr; + truncation->node = node; + truncation->depth = state->depth; + truncation->length = length; + + state->truncations = lappend(state->truncations, truncation); +} + +static void +add_truncation_where_clause(TruncationState * state, Node *node, Node *whereClause) +{ + if (whereClause == NULL) + return; + + add_truncation(state, + TRUNCATION_WHERE_CLAUSE, + node, + where_clause_len(whereClause)); +} + +static bool +generate_possible_truncations(Node *node, TruncationState * state) +{ + if (node == NULL) + return false; + + switch (nodeTag(node)) + { + case T_RawStmt: + return generate_possible_truncations(castNode(RawStmt, node)->stmt, state); + + case T_SelectStmt: + { + SelectStmt *stmt = castNode(SelectStmt, node); + + if (stmt->targetList != NULL) + add_truncation(state, + TRUNCATION_TARGET_LIST, + node, + select_target_list_len(stmt->targetList)); + + add_truncation_where_clause(state, node, stmt->whereClause); + + if (stmt->valuesLists != NULL) + add_truncation(state, + TRUNCATION_VALUES_LISTS, + node, + select_values_lists_len(stmt->valuesLists)); + + break; + } + + case T_InsertStmt: + { + InsertStmt *stmt = castNode(InsertStmt, node); + + if (stmt->cols != NULL) + add_truncation(state, TRUNCATION_COLS, node, cols_len(stmt->cols)); + + break; + } + + case T_UpdateStmt: + { + UpdateStmt *stmt = castNode(UpdateStmt, node); + + if (stmt->targetList != NULL) + add_truncation(state, + TRUNCATION_TARGET_LIST, + node, + update_target_list_len(stmt->targetList)); + + add_truncation_where_clause(state, node, stmt->whereClause); + + break; + } + + case T_DeleteStmt: + { + DeleteStmt *stmt = castNode(DeleteStmt, node); + + add_truncation_where_clause(state, node, stmt->whereClause); + break; + } + + case T_CopyStmt: + { + CopyStmt *stmt = castNode(CopyStmt, node); + + add_truncation_where_clause(state, node, stmt->whereClause); + break; + } + + case T_IndexStmt: + { + IndexStmt *stmt = castNode(IndexStmt, node); + + add_truncation_where_clause(state, node, stmt->whereClause); + break; + } + + case T_RuleStmt: + { + RuleStmt *stmt = castNode(RuleStmt, node); + + add_truncation_where_clause(state, node, stmt->whereClause); + break; + } + + case T_CommonTableExpr: + { + CommonTableExpr *stmt = castNode(CommonTableExpr, node); + + if (stmt->ctequery != NULL) + { + size_t query_len = deparse_stmt_len((Node *) stmt->ctequery); + + add_truncation(state, + TRUNCATION_CTE_QUERY, + node, + query_len); + } + + break; + } + + case T_InferClause: + { + InferClause *stmt = castNode(InferClause, node); + + add_truncation_where_clause(state, node, stmt->whereClause); + break; + } + + case T_OnConflictClause: + { + OnConflictClause *stmt = castNode(OnConflictClause, node); + + if (stmt->targetList != NULL) + add_truncation(state, + TRUNCATION_TARGET_LIST, + node, + update_target_list_len(stmt->targetList)); + + add_truncation_where_clause(state, node, stmt->whereClause); + + break; + } + + default: + break; + } + + if (!pg_query_raw_tree_walker_supports(node)) + return false; + + int old_depth = state->depth; + + state->depth++; + + bool result = raw_expression_tree_walker(node, generate_possible_truncations, (void *) state); + + /* Restore old depth value, since the current node (or its parents) may */ + /* have sibling elements. */ + state->depth = old_depth; + + return result; +} + +static int +cmp_possible_truncations(const ListCell *a, const ListCell *b) +{ + const PossibleTruncation *pt_a = lfirst(a); + const PossibleTruncation *pt_b = lfirst(b); + + int depth_cmp = pt_b->depth - pt_a->depth; + + if (depth_cmp != 0) + return depth_cmp; + + return pt_b->length - pt_a->length; +} + +static void +global_replace(char *str, char *pattern, char *replacement) +{ + size_t plen = strlen(pattern); + size_t rlen = strlen(replacement); + char *s = str; + + Assert(plen >= rlen); + + while ((s = strstr(s, pattern)) != NULL) + { + memcpy(s, replacement, rlen); + + /* Shift remainder of the string if needed */ + if (plen > rlen) + memmove(s + rlen, s + plen, strlen(s + plen) + 1); + + s += rlen; + } +} + +static void +apply_truncations(Summary * summary, Node *tree, TruncationState * state, int truncation_limit) +{ + List *truncations = state->truncations; + StringInfo output = NULL; + ListCell *lc; + + foreach(lc, state->truncations) + { + PossibleTruncation *truncation = lfirst(lc); + + Node *node = truncation->node; + enum TruncationAttr attr = truncation->attr; + + if (IsA(node, SelectStmt) && attr == TRUNCATION_TARGET_LIST) + castNode(SelectStmt, node)->targetList = list_make1(dummy_target()); + else if (IsA(node, SelectStmt) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(SelectStmt, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, SelectStmt) && attr == TRUNCATION_VALUES_LISTS) + castNode(SelectStmt, node)->valuesLists = list_make1(list_make1(dummy_column())); + else if (IsA(node, UpdateStmt) && attr == TRUNCATION_TARGET_LIST) + castNode(UpdateStmt, node)->targetList = list_make1(dummy_target()); + else if (IsA(node, InsertStmt) && attr == TRUNCATION_COLS) + castNode(InsertStmt, node)->cols = list_make1(dummy_target()); + else if (IsA(node, UpdateStmt) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(UpdateStmt, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, DeleteStmt) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(DeleteStmt, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, CopyStmt) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(CopyStmt, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, IndexStmt) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(IndexStmt, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, RuleStmt) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(RuleStmt, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, CommonTableExpr) && attr == TRUNCATION_CTE_QUERY) + castNode(CommonTableExpr, node)->ctequery = dummy_select(NULL, (Node *) dummy_column(), NULL); + else if (IsA(node, InferClause) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(InferClause, node)->whereClause = (Node *) dummy_column(); + else if (IsA(node, OnConflictClause) && attr == TRUNCATION_TARGET_LIST) + castNode(OnConflictClause, node)->targetList = list_make1(dummy_target()); + else if (IsA(node, OnConflictClause) && attr == TRUNCATION_WHERE_CLAUSE) + castNode(OnConflictClause, node)->whereClause = (Node *) dummy_column(); + else + elog(ERROR, "apply_truncations() got unknown truncation type"); + + if (output) + destroyStringInfo(output); + output = deparse_raw_stmt_list((List *) tree); + + global_replace(output->data, "SELECT \"…\" AS \"…\"", "SELECT \"…\""); + global_replace(output->data, "SELECT WHERE \"…\"", "\"…\""); + global_replace(output->data, "\"…\"", "..."); + + if (strlen(output->data) <= truncation_limit) + { + summary->truncated_query = output->data; + return; + } + } + + if (!output) + output = deparse_raw_stmt_list((List *) tree); + + truncate_mbstr(output->data, truncation_limit); + summary->truncated_query = output->data; +} + +static ColumnRef * +dummy_column(void) +{ + ColumnRef *colref = makeNode(ColumnRef); + + colref->fields = list_make1(makeString(pstrdup("…"))); + colref->location = 0; + + return colref; +} + +static ResTarget * +dummy_target(void) +{ + ResTarget *target = makeNode(ResTarget); + + target->name = pstrdup("…"); + target->val = (Node *) dummy_column(); + + /* + * TODO:docs for ResTarget say "-1 if unknown"-- would that be more + * correct ? (see also, dummy_column()) + */ + target->location = 0; + + return target; +} + +static Node * +dummy_select(List *targetList, Node *whereClause, List *valuesLists) +{ + SelectStmt *stmt = makeNode(SelectStmt); + + stmt->targetList = targetList; + stmt->whereClause = whereClause; + stmt->valuesLists = valuesLists; + + return (Node *) stmt; +} + +static Node * +dummy_insert(List *cols) +{ + RangeVar *rv = makeNode(RangeVar); + + rv->relname = pstrdup("x"); + rv->inh = true; + rv->relpersistence = 'p'; + rv->location = 0; + + InsertStmt *stmt = makeNode(InsertStmt); + + stmt->relation = rv; + stmt->cols = cols; + stmt->override = 1; + + return (Node *) stmt; +} + +static Node * +dummy_update(List *targetList) +{ + RangeVar *rv = makeNode(RangeVar); + + rv->relname = pstrdup("x"); + rv->inh = true; + rv->relpersistence = 'p'; + rv->location = 0; + + UpdateStmt *stmt = makeNode(UpdateStmt); + + stmt->relation = rv; + stmt->targetList = targetList; + + return (Node *) stmt; +} + +static int32_t +select_target_list_len(List *nodes) +{ + size_t result_len = deparse_stmt_len(dummy_select(nodes, NULL, NULL)); + size_t dummy_len = 7; /* "SELECT " */ + + return (int32_t) result_len - dummy_len; +} + +static int32_t +select_values_lists_len(List *nodes) +{ + size_t result_len = deparse_stmt_len(dummy_select(NULL, NULL, nodes)); + size_t dummy_len = 9; /* "VALUES ()" */ + + return (int32_t) result_len - dummy_len; +} + +static int32_t +update_target_list_len(List *nodes) +{ + size_t result_len = deparse_stmt_len(dummy_update(nodes)); + size_t dummy_len = 13; /* "UPDATE x SET " */ + + return (int32_t) result_len - dummy_len; +} + +static int32_t +where_clause_len(Node *node) +{ + size_t result_len = deparse_stmt_len(dummy_select(NULL, node, NULL)); + size_t dummy_len = 13; /* "SELECT WHERE " */ + + return (int32_t) result_len - dummy_len; +} + +static int32_t +cols_len(List *nodes) +{ + size_t result_len = deparse_stmt_len(dummy_insert(nodes)); + size_t dummy_len = 31; /* "INSERT INTO x () DEFAULT VALUES" */ + + return (int32_t) result_len - dummy_len; +} + +static size_t +deparse_stmt_len(Node *node) +{ + if (!IsA(node, RawStmt)) + { + RawStmt *raw = makeNode(RawStmt); + + raw->stmt = node; + raw->stmt_location = -1; + raw->stmt_len = 0; + node = (Node *) raw; + } + + StringInfo str = deparse_raw_stmt_list(list_make1(node)); + size_t len = str->len; + + destroyStringInfo(str); + return len; +} + +static StringInfo +deparse_raw_stmt_list(List *stmts) +{ + PostgresDeparseOpts opts = {0}; + StringInfo str = makeStringInfo(); + ListCell *lc; + + foreach(lc, stmts) + { + deparseRawStmtOpts(str, castNode(RawStmt, lfirst(lc)), opts); + if (lnext(stmts, lc)) + appendStringInfoString(str, "; "); + } + + return str; +} diff --git a/c_src/libpg_query/src/postgres/COPYRIGHT b/c_src/libpg_query/src/postgres/COPYRIGHT index be2d694b..3b79b1b4 100644 --- a/c_src/libpg_query/src/postgres/COPYRIGHT +++ b/c_src/libpg_query/src/postgres/COPYRIGHT @@ -1,5 +1,5 @@ PostgreSQL Database Management System -(formerly known as Postgres, then as Postgres95) +(also known as Postgres, formerly known as Postgres95) Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group diff --git a/c_src/libpg_query/src/postgres/include/access/amapi.h b/c_src/libpg_query/src/postgres/include/access/amapi.h index d3e5e5d5..09801450 100644 --- a/c_src/libpg_query/src/postgres/include/access/amapi.h +++ b/c_src/libpg_query/src/postgres/include/access/amapi.h @@ -271,7 +271,7 @@ typedef struct IndexAmRoutine ambuild_function ambuild; ambuildempty_function ambuildempty; aminsert_function aminsert; - aminsertcleanup_function aminsertcleanup; + aminsertcleanup_function aminsertcleanup; /* can be NULL */ ambulkdelete_function ambulkdelete; amvacuumcleanup_function amvacuumcleanup; amcanreturn_function amcanreturn; /* can be NULL */ diff --git a/c_src/libpg_query/src/postgres/include/access/slru.h b/c_src/libpg_query/src/postgres/include/access/slru.h index 02fcb3bc..9409f680 100644 --- a/c_src/libpg_query/src/postgres/include/access/slru.h +++ b/c_src/libpg_query/src/postgres/include/access/slru.h @@ -55,7 +55,7 @@ typedef enum /* * Shared-memory state * - * ControlLock is used to protect access to the other fields, except + * SLRU bank locks are used to protect access to the other fields, except * latest_page_number, which uses atomics; see comment in slru.c. */ typedef struct SlruSharedData diff --git a/c_src/libpg_query/src/postgres/include/access/tableam.h b/c_src/libpg_query/src/postgres/include/access/tableam.h index 7be7887b..a1c137d2 100644 --- a/c_src/libpg_query/src/postgres/include/access/tableam.h +++ b/c_src/libpg_query/src/postgres/include/access/tableam.h @@ -129,7 +129,9 @@ typedef enum TU_UpdateIndexes /* * When table_tuple_update, table_tuple_delete, or table_tuple_lock fail * because the target tuple is already outdated, they fill in this struct to - * provide information to the caller about what happened. + * provide information to the caller about what happened. When those functions + * succeed, the contents of this struct should not be relied upon, except for + * `traversed`, which may be set in both success and failure cases. * * ctid is the target's ctid link: it is the same as the target's TID if the * target was deleted, or the location of the replacement tuple if the target @@ -145,6 +147,9 @@ typedef enum TU_UpdateIndexes * tuple); otherwise cmax is zero. (We make this restriction because * HeapTupleHeaderGetCmax doesn't work for tuples outdated in other * transactions.) + * + * traversed indicates if an update chain was followed in order to try to lock + * the target tuple. (This may be set in both success and failure cases.) */ typedef struct TM_FailureData { @@ -1549,7 +1554,7 @@ table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, * * Input parameters: * relation: relation containing tuple (caller must hold suitable lock) - * tid: TID of tuple to lock + * tid: TID of tuple to lock (updated if an update chain was followed) * snapshot: snapshot to use for visibility determinations * cid: current command ID (used for visibility test, and stored into * tuple's cmax if lock is successful) @@ -1574,8 +1579,10 @@ table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, * TM_WouldBlock: lock couldn't be acquired and wait_policy is skip * * In the failure cases other than TM_Invisible and TM_Deleted, the routine - * fills *tmfd with the tuple's t_ctid, t_xmax, and, if possible, t_cmax. See - * comments for struct TM_FailureData for additional info. + * fills *tmfd with the tuple's t_ctid, t_xmax, and, if possible, t_cmax. + * Additionally, in both success and failure cases, tmfd->traversed is set if + * an update chain was followed. See comments for struct TM_FailureData for + * additional info. */ static inline TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, diff --git a/c_src/libpg_query/src/postgres/include/access/xlog.h b/c_src/libpg_query/src/postgres/include/access/xlog.h index 2c507ea6..9c2d101c 100644 --- a/c_src/libpg_query/src/postgres/include/access/xlog.h +++ b/c_src/libpg_query/src/postgres/include/access/xlog.h @@ -265,6 +265,7 @@ extern void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI extern void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli); extern void SetInstallXLogFileSegmentActive(void); extern bool IsInstallXLogFileSegmentActive(void); +extern void ResetInstallXLogFileSegmentActive(void); extern void XLogShutdownWalRcv(void); /* diff --git a/c_src/libpg_query/src/postgres/include/access/xlogdefs.h b/c_src/libpg_query/src/postgres/include/access/xlogdefs.h index 30097989..c55e2f57 100644 --- a/c_src/libpg_query/src/postgres/include/access/xlogdefs.h +++ b/c_src/libpg_query/src/postgres/include/access/xlogdefs.h @@ -25,7 +25,8 @@ typedef uint64 XLogRecPtr; * WAL segment, initializing the first WAL page at WAL segment size, so no XLOG * record can begin at zero. */ -#define InvalidXLogRecPtr 0 +#define InvalidXLogRecPtr 0 +#define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr) #define XLogRecPtrIsInvalid(r) ((r) == InvalidXLogRecPtr) /* diff --git a/c_src/libpg_query/src/postgres/include/commands/defrem.h b/c_src/libpg_query/src/postgres/include/commands/defrem.h index 29c511e3..74ca50ac 100644 --- a/c_src/libpg_query/src/postgres/include/commands/defrem.h +++ b/c_src/libpg_query/src/postgres/include/commands/defrem.h @@ -81,7 +81,7 @@ extern void RemoveOperatorById(Oid operOid); extern ObjectAddress AlterOperator(AlterOperatorStmt *stmt); /* commands/statscmds.c */ -extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt); +extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt, bool check_rights); extern ObjectAddress AlterStatistics(AlterStatsStmt *stmt); extern void RemoveStatisticsById(Oid statsOid); extern void RemoveStatisticsDataById(Oid statsOid, bool inh); diff --git a/c_src/libpg_query/src/postgres/include/commands/trigger.h b/c_src/libpg_query/src/postgres/include/commands/trigger.h index 8a5a9fe6..f9e4dc4f 100644 --- a/c_src/libpg_query/src/postgres/include/commands/trigger.h +++ b/c_src/libpg_query/src/postgres/include/commands/trigger.h @@ -206,6 +206,15 @@ extern void ExecBSDeleteTriggers(EState *estate, extern void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture); +extern bool ExecBRDeleteTriggersNew(EState *estate, + EPQState *epqstate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot **epqslot, + TM_Result *tmresult, + TM_FailureData *tmfd, + bool is_merge_delete); extern bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, @@ -228,6 +237,15 @@ extern void ExecBSUpdateTriggers(EState *estate, extern void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture); +extern bool ExecBRUpdateTriggersNew(EState *estate, + EPQState *epqstate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot *newslot, + TM_Result *tmresult, + TM_FailureData *tmfd, + bool is_merge_update); extern bool ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, diff --git a/c_src/libpg_query/src/postgres/include/executor/executor.h b/c_src/libpg_query/src/postgres/include/executor/executor.h index 9770752e..6cecfbcb 100644 --- a/c_src/libpg_query/src/postgres/include/executor/executor.h +++ b/c_src/libpg_query/src/postgres/include/executor/executor.h @@ -210,6 +210,10 @@ extern void standard_ExecutorEnd(QueryDesc *queryDesc); extern void ExecutorRewind(QueryDesc *queryDesc); extern bool ExecCheckPermissions(List *rangeTable, List *rteperminfos, bool ereport_on_violation); +extern bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo); +extern void CheckValidResultRelNew(ResultRelInfo *resultRelInfo, CmdType operation, + OnConflictAction onConflictAction, + List *mergeActions); extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, List *mergeActions); extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, diff --git a/c_src/libpg_query/src/postgres/include/mb/pg_wchar.h b/c_src/libpg_query/src/postgres/include/mb/pg_wchar.h index 08f6fa6e..e5babf3e 100644 --- a/c_src/libpg_query/src/postgres/include/mb/pg_wchar.h +++ b/c_src/libpg_query/src/postgres/include/mb/pg_wchar.h @@ -664,6 +664,8 @@ extern int pg_valid_server_encoding_id(int encoding); */ extern void pg_encoding_set_invalid(int encoding, char *dst); extern int pg_encoding_mblen(int encoding, const char *mbstr); +extern int pg_encoding_mblen_or_incomplete(int encoding, const char *mbstr, + size_t remaining); extern int pg_encoding_mblen_bounded(int encoding, const char *mbstr); extern int pg_encoding_dsplen(int encoding, const char *mbstr); extern int pg_encoding_verifymbchar(int encoding, const char *mbstr, int len); diff --git a/c_src/libpg_query/src/postgres/include/miscadmin.h b/c_src/libpg_query/src/postgres/include/miscadmin.h index e6a65d9c..131f780d 100644 --- a/c_src/libpg_query/src/postgres/include/miscadmin.h +++ b/c_src/libpg_query/src/postgres/include/miscadmin.h @@ -114,7 +114,8 @@ extern void ProcessInterrupts(void); (unlikely(InterruptPending)) #else #define INTERRUPTS_PENDING_CONDITION() \ - (unlikely(UNBLOCKED_SIGNAL_QUEUE()) ? pgwin32_dispatch_queued_signals() : 0, \ + (unlikely(UNBLOCKED_SIGNAL_QUEUE()) ? \ + pgwin32_dispatch_queued_signals() : (void) 0, \ unlikely(InterruptPending)) #endif diff --git a/c_src/libpg_query/src/postgres/include/nodes/execnodes.h b/c_src/libpg_query/src/postgres/include/nodes/execnodes.h index 17b0ec51..ef492b9d 100644 --- a/c_src/libpg_query/src/postgres/include/nodes/execnodes.h +++ b/c_src/libpg_query/src/postgres/include/nodes/execnodes.h @@ -164,7 +164,7 @@ typedef struct ExprState * UniqueProcs * UniqueStrats * Unique is it a unique index? - * OpclassOptions opclass-specific options, or NULL if none + * NullsNotDistinct is NULLS NOT DISTINCT? * ReadyForInserts is it valid for inserts? * CheckedUnchanged IndexUnchanged status determined yet? * IndexUnchanged aminsert hint, cached for retail inserts @@ -574,15 +574,13 @@ typedef struct ResultRelInfo bool ri_RootToChildMapValid; /* - * Information needed by tuple routing target relations + * Other information needed by child result relations * - * RootResultRelInfo gives the target relation mentioned in the query, if - * it's a partitioned table. It is not set if the target relation - * mentioned in the query is an inherited table, nor when tuple routing is - * not needed. + * ri_RootResultRelInfo gives the target relation mentioned in the query. + * Used as the root for tuple routing and/or transition capture. * - * PartitionTupleSlot is non-NULL if RootToChild conversion is needed and - * the relation is a partition. + * ri_PartitionTupleSlot is non-NULL if the relation is a partition to + * route tuples into and ri_RootToChildMap conversion is needed. */ struct ResultRelInfo *ri_RootResultRelInfo; TupleTableSlot *ri_PartitionTupleSlot; diff --git a/c_src/libpg_query/src/postgres/include/nodes/pathnodes.h b/c_src/libpg_query/src/postgres/include/nodes/pathnodes.h index 50b09781..576f1c7e 100644 --- a/c_src/libpg_query/src/postgres/include/nodes/pathnodes.h +++ b/c_src/libpg_query/src/postgres/include/nodes/pathnodes.h @@ -1101,8 +1101,7 @@ typedef struct IndexOptInfo IndexOptInfo; #define HAVE_INDEXOPTINFO_TYPEDEF 1 #endif -struct IndexPath; /* avoid including pathnodes.h here */ -struct PlannerInfo; /* avoid including pathnodes.h here */ +struct IndexPath; /* forward declaration */ struct IndexOptInfo { diff --git a/c_src/libpg_query/src/postgres/include/pg_config.h b/c_src/libpg_query/src/postgres/include/pg_config.h index a361c9e0..aab1919c 100644 --- a/c_src/libpg_query/src/postgres/include/pg_config.h +++ b/c_src/libpg_query/src/postgres/include/pg_config.h @@ -104,6 +104,10 @@ `LLVMCreatePerfJITEventListener', and to 0 if you don't. */ /* #undef HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER */ +/* Define to 1 if you have the declaration of `memset_s', and to 0 if you + don't. */ +#define HAVE_DECL_MEMSET_S 1 + /* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you don't. */ #define HAVE_DECL_POSIX_FADVISE 0 @@ -302,9 +306,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 -/* Define to 1 if you have the `memset_s' function. */ -#define HAVE_MEMSET_S 1 - /* Define to 1 if you have the `mkdtemp' function. */ #define HAVE_MKDTEMP 1 @@ -592,7 +593,7 @@ #define PACKAGE_NAME "PostgreSQL" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PostgreSQL 17.4" +#define PACKAGE_STRING "PostgreSQL 17.7" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "postgresql" @@ -601,7 +602,7 @@ #define PACKAGE_URL "https://www.postgresql.org/" /* Define to the version of this package. */ -#define PACKAGE_VERSION "17.4" +#define PACKAGE_VERSION "17.7" /* Define to the name of a signed 128-bit integer type. */ #define PG_INT128_TYPE __int128 @@ -620,7 +621,7 @@ #define PG_MAJORVERSION_NUM 17 /* PostgreSQL minor version number */ -#define PG_MINORVERSION_NUM 4 +#define PG_MINORVERSION_NUM 7 /* Define to best printf format archetype, usually gnu_printf if available. */ #define PG_PRINTF_ATTRIBUTE printf @@ -629,13 +630,13 @@ #define PG_USE_STDBOOL 1 /* PostgreSQL version as a string */ -#define PG_VERSION "17.4" +#define PG_VERSION "17.7" /* PostgreSQL version as a number */ -#define PG_VERSION_NUM 170004 +#define PG_VERSION_NUM 170007 /* A string containing the version number, platform, and C compiler */ -#define PG_VERSION_STR "PostgreSQL 17.4 (libpg_query)" +#define PG_VERSION_STR "PostgreSQL 17.7 (libpg_query)" /* Define to 1 to allow profiling output to be saved separately for each process. */ diff --git a/c_src/libpg_query/src/postgres/include/pg_config_manual.h b/c_src/libpg_query/src/postgres/include/pg_config_manual.h index f941ee2f..e74d3149 100644 --- a/c_src/libpg_query/src/postgres/include/pg_config_manual.h +++ b/c_src/libpg_query/src/postgres/include/pg_config_manual.h @@ -26,7 +26,9 @@ * * Changing this requires an initdb. */ +#ifndef NAMEDATALEN #define NAMEDATALEN 64 +#endif /* * Maximum number of arguments to a function. diff --git a/c_src/libpg_query/src/postgres/include/port/atomics/generic-gcc.h b/c_src/libpg_query/src/postgres/include/port/atomics/generic-gcc.h index 872d2f02..afdb8f67 100644 --- a/c_src/libpg_query/src/postgres/include/port/atomics/generic-gcc.h +++ b/c_src/libpg_query/src/postgres/include/port/atomics/generic-gcc.h @@ -44,12 +44,20 @@ #if !defined(pg_read_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS) /* acquire semantics include read barrier semantics */ -# define pg_read_barrier_impl() __atomic_thread_fence(__ATOMIC_ACQUIRE) +# define pg_read_barrier_impl() do \ +{ \ + pg_compiler_barrier_impl(); \ + __atomic_thread_fence(__ATOMIC_ACQUIRE); \ +} while (0) #endif #if !defined(pg_write_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS) /* release semantics include write barrier semantics */ -# define pg_write_barrier_impl() __atomic_thread_fence(__ATOMIC_RELEASE) +# define pg_write_barrier_impl() do \ +{ \ + pg_compiler_barrier_impl(); \ + __atomic_thread_fence(__ATOMIC_RELEASE); \ +} while (0) #endif diff --git a/c_src/libpg_query/src/postgres/include/port/pg_iovec.h b/c_src/libpg_query/src/postgres/include/port/pg_iovec.h index e5fe677b..10fecdd4 100644 --- a/c_src/libpg_query/src/postgres/include/port/pg_iovec.h +++ b/c_src/libpg_query/src/postgres/include/port/pg_iovec.h @@ -21,9 +21,6 @@ #else -/* POSIX requires at least 16 as a maximum iovcnt. */ -#define IOV_MAX 16 - /* Define our own POSIX-compatible iovec struct. */ struct iovec { @@ -33,6 +30,15 @@ struct iovec #endif +/* + * If didn't define IOV_MAX, define our own. X/Open requires at + * least 16. (GNU Hurd apparently feel that they're not bound by X/Open, + * because they don't define this symbol at all.) + */ +#ifndef IOV_MAX +#define IOV_MAX 16 +#endif + /* Define a reasonable maximum that is safe to use on the stack. */ #define PG_IOV_MAX Min(IOV_MAX, 32) diff --git a/c_src/libpg_query/src/postgres/include/replication/reorderbuffer.h b/c_src/libpg_query/src/postgres/include/replication/reorderbuffer.h index 7de50462..0cfa9005 100644 --- a/c_src/libpg_query/src/postgres/include/replication/reorderbuffer.h +++ b/c_src/libpg_query/src/postgres/include/replication/reorderbuffer.h @@ -159,15 +159,16 @@ typedef struct ReorderBufferChange } ReorderBufferChange; /* ReorderBufferTXN txn_flags */ -#define RBTXN_HAS_CATALOG_CHANGES 0x0001 -#define RBTXN_IS_SUBXACT 0x0002 -#define RBTXN_IS_SERIALIZED 0x0004 -#define RBTXN_IS_SERIALIZED_CLEAR 0x0008 -#define RBTXN_IS_STREAMED 0x0010 -#define RBTXN_HAS_PARTIAL_CHANGE 0x0020 -#define RBTXN_PREPARE 0x0040 -#define RBTXN_SKIPPED_PREPARE 0x0080 -#define RBTXN_HAS_STREAMABLE_CHANGE 0x0100 +#define RBTXN_HAS_CATALOG_CHANGES 0x0001 +#define RBTXN_IS_SUBXACT 0x0002 +#define RBTXN_IS_SERIALIZED 0x0004 +#define RBTXN_IS_SERIALIZED_CLEAR 0x0008 +#define RBTXN_IS_STREAMED 0x0010 +#define RBTXN_HAS_PARTIAL_CHANGE 0x0020 +#define RBTXN_PREPARE 0x0040 +#define RBTXN_SKIPPED_PREPARE 0x0080 +#define RBTXN_HAS_STREAMABLE_CHANGE 0x0100 +#define RBTXN_DISTR_INVAL_OVERFLOWED 0x0200 /* Does the transaction have catalog changes? */ #define rbtxn_has_catalog_changes(txn) \ @@ -231,6 +232,12 @@ typedef struct ReorderBufferChange ((txn)->txn_flags & RBTXN_SKIPPED_PREPARE) != 0 \ ) +/* Is the array of distributed inval messages overflowed? */ +#define rbtxn_distr_inval_overflowed(txn) \ +( \ + ((txn)->txn_flags & RBTXN_DISTR_INVAL_OVERFLOWED) != 0 \ +) + /* Is this a top-level transaction? */ #define rbtxn_is_toptxn(txn) \ ( \ @@ -422,6 +429,12 @@ typedef struct ReorderBufferTXN * Private data pointer of the output plugin. */ void *output_plugin_private; + + /* + * Stores cache invalidation messages distributed by other transactions. + */ + uint32 ninvalidations_distributed; + SharedInvalidationMessage *invalidations_distributed; } ReorderBufferTXN; /* so we can define the callbacks used inside struct ReorderBuffer itself */ @@ -709,6 +722,9 @@ extern void ReorderBufferAddNewTupleCids(ReorderBuffer *rb, TransactionId xid, CommandId cmin, CommandId cmax, CommandId combocid); extern void ReorderBufferAddInvalidations(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn, Size nmsgs, SharedInvalidationMessage *msgs); +extern void ReorderBufferAddDistributedInvalidations(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr lsn, Size nmsgs, + SharedInvalidationMessage *msgs); extern void ReorderBufferImmediateInvalidation(ReorderBuffer *rb, uint32 ninvalidations, SharedInvalidationMessage *invalidations); extern void ReorderBufferProcessXid(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn); @@ -729,6 +745,10 @@ extern TransactionId *ReorderBufferGetCatalogChangesXacts(ReorderBuffer *rb); extern void ReorderBufferSetRestartPoint(ReorderBuffer *rb, XLogRecPtr ptr); +extern uint32 ReorderBufferGetInvalidations(ReorderBuffer *rb, + TransactionId xid, + SharedInvalidationMessage **msgs); + extern void StartupReorderBuffer(void); #endif diff --git a/c_src/libpg_query/src/postgres/include/replication/slot.h b/c_src/libpg_query/src/postgres/include/replication/slot.h index 07561bc4..43594bb9 100644 --- a/c_src/libpg_query/src/postgres/include/replication/slot.h +++ b/c_src/libpg_query/src/postgres/include/replication/slot.h @@ -258,6 +258,8 @@ extern void ReplicationSlotMarkDirty(void); /* misc stuff */ extern void ReplicationSlotInitialize(void); extern bool ReplicationSlotValidateName(const char *name, int elevel); +extern bool ReplicationSlotValidateNameInternal(const char *name, + int *err_code, char **err_msg, char **err_hint); extern void ReplicationSlotReserveWal(void); extern void ReplicationSlotsComputeRequiredXmin(bool already_locked); extern void ReplicationSlotsComputeRequiredLSN(void); diff --git a/c_src/libpg_query/src/postgres/include/utils/elog.h b/c_src/libpg_query/src/postgres/include/utils/elog.h index 60dca028..8c4b0f8f 100644 --- a/c_src/libpg_query/src/postgres/include/utils/elog.h +++ b/c_src/libpg_query/src/postgres/include/utils/elog.h @@ -536,5 +536,6 @@ extern void write_jsonlog(ErrorData *edata); * safely (memory context, GUC load etc) */ extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2); +extern void vwrite_stderr(const char *fmt, va_list ap) pg_attribute_printf(1, 0); #endif /* ELOG_H */ diff --git a/c_src/libpg_query/src/postgres/include/utils/guc.h b/c_src/libpg_query/src/postgres/include/utils/guc.h index fd4d8c69..464bd759 100644 --- a/c_src/libpg_query/src/postgres/include/utils/guc.h +++ b/c_src/libpg_query/src/postgres/include/utils/guc.h @@ -102,7 +102,7 @@ typedef enum * will show as "default" in pg_settings. If there is a specific reason not * to want that, use source == PGC_S_OVERRIDE. * - * NB: see GucSource_Names in guc.c if you change this. + * NB: see GucSource_Names in guc_tables.c if you change this. */ typedef enum { diff --git a/c_src/libpg_query/src/postgres/include/utils/guc_hooks.h b/c_src/libpg_query/src/postgres/include/utils/guc_hooks.h index 8fd91af3..1babff78 100644 --- a/c_src/libpg_query/src/postgres/include/utils/guc_hooks.h +++ b/c_src/libpg_query/src/postgres/include/utils/guc_hooks.h @@ -86,8 +86,6 @@ extern bool check_maintenance_io_concurrency(int *newval, void **extra, extern void assign_maintenance_io_concurrency(int newval, void *extra); extern bool check_max_connections(int *newval, void **extra, GucSource source); extern bool check_max_wal_senders(int *newval, void **extra, GucSource source); -extern bool check_max_slot_wal_keep_size(int *newval, void **extra, - GucSource source); extern void assign_max_wal_size(int newval, void *extra); extern bool check_max_worker_processes(int *newval, void **extra, GucSource source); diff --git a/c_src/libpg_query/src/postgres/include/utils/pg_locale.h b/c_src/libpg_query/src/postgres/include/utils/pg_locale.h index 040968d6..0bc93142 100644 --- a/c_src/libpg_query/src/postgres/include/utils/pg_locale.h +++ b/c_src/libpg_query/src/postgres/include/utils/pg_locale.h @@ -16,6 +16,11 @@ #include #endif #ifdef USE_ICU +/* only include the C APIs, to avoid errors in cpluspluscheck */ +#undef U_SHOW_CPLUSPLUS_API +#define U_SHOW_CPLUSPLUS_API 0 +#undef U_SHOW_CPLUSPLUS_HEADER_API +#define U_SHOW_CPLUSPLUS_HEADER_API 0 #include #endif diff --git a/c_src/libpg_query/src/postgres/src_backend_catalog_namespace.c b/c_src/libpg_query/src/postgres/src_backend_catalog_namespace.c index d83eed52..38e11d6b 100644 --- a/c_src/libpg_query/src/postgres/src_backend_catalog_namespace.c +++ b/c_src/libpg_query/src/postgres/src_backend_catalog_namespace.c @@ -2,6 +2,7 @@ * Symbols referenced in this file: * - NameListToString * - get_collation_oid + * - makeRangeVarFromNameList *-------------------------------------------------------------------- */ @@ -900,7 +901,35 @@ static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, * makeRangeVarFromNameList * Utility routine to convert a qualified-name list into RangeVar form. */ +RangeVar * +makeRangeVarFromNameList(const List *names) +{ + RangeVar *rel = makeRangeVar(NULL, NULL, -1); + switch (list_length(names)) + { + case 1: + rel->relname = strVal(linitial(names)); + break; + case 2: + rel->schemaname = strVal(linitial(names)); + rel->relname = strVal(lsecond(names)); + break; + case 3: + rel->catalogname = strVal(linitial(names)); + rel->schemaname = strVal(lsecond(names)); + rel->relname = strVal(lthird(names)); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper relation name (too many dotted names): %s", + NameListToString(names)))); + break; + } + + return rel; +} /* * NameListToString diff --git a/c_src/libpg_query/src/postgres/src_backend_nodes_bitmapset.c b/c_src/libpg_query/src/postgres/src_backend_nodes_bitmapset.c index 13c951ae..0b49baa5 100644 --- a/c_src/libpg_query/src/postgres/src_backend_nodes_bitmapset.c +++ b/c_src/libpg_query/src/postgres/src_backend_nodes_bitmapset.c @@ -6,6 +6,9 @@ * - bms_free * - bms_next_member * - bms_num_members + * - bms_add_member + * - bms_make_singleton + * - bms_is_member *-------------------------------------------------------------------- */ @@ -195,7 +198,23 @@ bms_equal(const Bitmapset *a, const Bitmapset *b) /* * bms_make_singleton - build a bitmapset containing a single member */ - +Bitmapset * +bms_make_singleton(int x) +{ + Bitmapset *result; + int wordnum, + bitnum; + + if (x < 0) + elog(ERROR, "negative bitmapset member not allowed"); + wordnum = WORDNUM(x); + bitnum = BITNUM(x); + result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1)); + result->type = T_Bitmapset; + result->nwords = wordnum + 1; + result->words[wordnum] = ((bitmapword) 1 << bitnum); + return result; +} /* * bms_free - free a bitmapset @@ -243,7 +262,28 @@ bms_free(Bitmapset *a) /* * bms_is_member - is X a member of A? */ +bool +bms_is_member(int x, const Bitmapset *a) +{ + int wordnum, + bitnum; + Assert(bms_is_valid_set(a)); + + /* XXX better to just return false for x<0 ? */ + if (x < 0) + elog(ERROR, "negative bitmapset member not allowed"); + if (a == NULL) + return false; + + wordnum = WORDNUM(x); + bitnum = BITNUM(x); + if (wordnum >= a->nwords) + return false; + if ((a->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0) + return true; + return false; +} /* * bms_member_index @@ -331,9 +371,52 @@ bms_num_members(const Bitmapset *a) * * 'a' is recycled when possible. */ +Bitmapset * +bms_add_member(Bitmapset *a, int x) +{ + int wordnum, + bitnum; + + Assert(bms_is_valid_set(a)); + + if (x < 0) + elog(ERROR, "negative bitmapset member not allowed"); + if (a == NULL) + return bms_make_singleton(x); + + wordnum = WORDNUM(x); + bitnum = BITNUM(x); + + /* enlarge the set if necessary */ + if (wordnum >= a->nwords) + { + int oldnwords = a->nwords; + int i; + + a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(wordnum + 1)); + a->nwords = wordnum + 1; + /* zero out the enlarged portion */ + i = oldnwords; + do + { + a->words[i] = 0; + } while (++i < a->nwords); + } + + a->words[wordnum] |= ((bitmapword) 1 << bitnum); + #ifdef REALLOCATE_BITMAPSETS + + /* + * There's no guarantee that the repalloc returned a new pointer, so copy + * and free unconditionally here. + */ + a = bms_copy_and_free(a); #endif + return a; +} + /* * bms_del_member - remove a specified member from set * diff --git a/c_src/libpg_query/src/postgres/src_backend_nodes_list.c b/c_src/libpg_query/src/postgres/src_backend_nodes_list.c index 70f89f57..f9a93780 100644 --- a/c_src/libpg_query/src/postgres/src_backend_nodes_list.c +++ b/c_src/libpg_query/src/postgres/src_backend_nodes_list.c @@ -19,6 +19,10 @@ * - list_copy_deep * - list_copy_tail * - list_truncate + * - list_delete_last + * - list_insert_nth + * - insert_new_cell + * - list_sort *-------------------------------------------------------------------- */ @@ -383,7 +387,22 @@ lappend(List *list, void *datum) * list position, ie, 0 <= pos <= list's length. * Returns address of the new cell. */ +static ListCell * +insert_new_cell(List *list, int pos) +{ + Assert(pos >= 0 && pos <= list->length); + /* Enlarge array if necessary */ + if (list->length >= list->max_length) + enlarge_list(list, list->length + 1); + /* Now shove the existing data over */ + if (pos < list->length) + memmove(&list->elements[pos + 1], &list->elements[pos], + (list->length - pos) * sizeof(ListCell)); + list->length++; + + return &list->elements[pos]; +} /* * Insert the given datum at position 'pos' (measured from 0) in the list. @@ -392,7 +411,19 @@ lappend(List *list, void *datum) * Note that this takes time proportional to the distance to the end of the * list, since the following entries must be moved. */ - +List * +list_insert_nth(List *list, int pos, void *datum) +{ + if (list == NIL) + { + Assert(pos == 0); + return list_make1(datum); + } + Assert(IsPointerList(list)); + lfirst(insert_new_cell(list, pos)) = datum; + check_list_invariants(list); + return list; +} @@ -674,7 +705,23 @@ list_delete_nth_cell(List *list, int n) /* * Delete the last element of the list. */ +List * +list_delete_last(List *list) +{ + check_list_invariants(list); + if (list == NIL) + return NIL; /* would an error be better? */ + + /* list_truncate won't free list if it goes to empty, but this should */ + if (list_length(list) <= 1) + { + list_free(list); + return NIL; + } + + return list_truncate(list, list_length(list) - 1); +} /* * Delete the first N cells of the list. @@ -992,7 +1039,19 @@ list_copy_deep(const List *oldlist) * * This is based on qsort(), so it likewise has O(N log N) runtime. */ +void +list_sort(List *list, list_sort_comparator cmp) +{ + typedef int (*qsort_comparator) (const void *a, const void *b); + int len; + + check_list_invariants(list); + /* Nothing to do if there's less than two elements */ + len = list_length(list); + if (len > 1) + qsort(list->elements, len, sizeof(ListCell), (qsort_comparator) cmp); +} /* * list_sort comparator for sorting a list into ascending int order. diff --git a/c_src/libpg_query/src/postgres/src_backend_parser_gram.c b/c_src/libpg_query/src/postgres/src_backend_parser_gram.c index 926e8d7c..8188645c 100644 --- a/c_src/libpg_query/src/postgres/src_backend_parser_gram.c +++ b/c_src/libpg_query/src/postgres/src_backend_parser_gram.c @@ -3549,160 +3549,160 @@ static const yytype_uint16 yyrline[] = 13827, 13834, 13845, 13846, 13859, 13863, 13871, 13885, 13899, 13900, 13915, 13926, 13939, 13944, 13945, 13948, 13949, 13952, 13953, 13958, 13959, 13964, 13965, 13974, 13979, 13980, 13984, 13988, 13994, 14019, - 14030, 14044, 14045, 14049, 14063, 14120, 14134, 14136, 14141, 14143, - 14145, 14147, 14149, 14154, 14156, 14161, 14169, 14180, 14208, 14209, - 14213, 14215, 14220, 14229, 14249, 14269, 14287, 14299, 14314, 14315, - 14319, 14322, 14335, 14340, 14347, 14352, 14358, 14363, 14372, 14374, - 14377, 14381, 14382, 14383, 14384, 14385, 14386, 14391, 14397, 14412, - 14413, 14414, 14415, 14416, 14427, 14433, 14441, 14442, 14448, 14453, - 14458, 14463, 14468, 14473, 14478, 14483, 14489, 14495, 14501, 14508, - 14530, 14539, 14543, 14551, 14555, 14563, 14575, 14596, 14600, 14606, - 14610, 14623, 14631, 14641, 14643, 14645, 14647, 14649, 14651, 14656, - 14657, 14664, 14673, 14681, 14690, 14701, 14709, 14710, 14711, 14715, - 14717, 14719, 14721, 14723, 14725, 14727, 14732, 14737, 14743, 14751, - 14756, 14763, 14770, 14774, 14778, 14786, 14821, 14822, 14824, 14833, - 14840, 14856, 14858, 14860, 14862, 14864, 14866, 14868, 14870, 14872, - 14874, 14876, 14878, 14880, 14882, 14885, 14887, 14890, 14892, 14894, - 14896, 14899, 14904, 14913, 14918, 14927, 14932, 14941, 14946, 14956, - 14965, 14974, 14983, 15002, 15011, 15020, 15029, 15038, 15055, 15064, - 15073, 15082, 15091, 15100, 15109, 15113, 15117, 15125, 15133, 15141, - 15149, 15170, 15193, 15205, 15212, 15228, 15233, 15239, 15246, 15253, - 15261, 15269, 15286, 15305, 15331, 15333, 15335, 15337, 15339, 15341, - 15343, 15345, 15347, 15349, 15351, 15353, 15355, 15357, 15359, 15361, - 15363, 15365, 15367, 15371, 15375, 15380, 15396, 15397, 15398, 15415, - 15428, 15430, 15432, 15444, 15469, 15481, 15493, 15501, 15512, 15523, - 15533, 15539, 15548, 15558, 15568, 15581, 15591, 15622, 15658, 15668, - 15679, 15680, 15681, 15688, 15695, 15699, 15703, 15707, 15711, 15715, - 15719, 15723, 15727, 15731, 15735, 15739, 15743, 15750, 15754, 15758, - 15762, 15764, 15771, 15778, 15785, 15792, 15803, 15817, 15827, 15838, - 15854, 15864, 15871, 15878, 15885, 15889, 15897, 15906, 15915, 15919, - 15923, 15927, 15931, 15935, 15944, 15948, 15958, 15962, 15966, 15971, - 15982, 15988, 16002, 16013, 16027, 16043, 16055, 16065, 16074, 16083, - 16091, 16113, 16129, 16153, 16155, 16159, 16161, 16163, 16166, 16169, - 16172, 16173, 16176, 16184, 16194, 16195, 16198, 16199, 16200, 16203, - 16204, 16205, 16210, 16214, 16218, 16222, 16229, 16230, 16238, 16239, - 16243, 16244, 16252, 16253, 16257, 16258, 16263, 16272, 16274, 16289, - 16292, 16320, 16321, 16324, 16325, 16333, 16341, 16349, 16358, 16368, - 16386, 16432, 16441, 16450, 16459, 16468, 16480, 16481, 16482, 16483, - 16484, 16498, 16499, 16500, 16503, 16504, 16507, 16510, 16511, 16512, - 16515, 16516, 16519, 16520, 16521, 16522, 16523, 16524, 16525, 16526, - 16527, 16528, 16529, 16530, 16533, 16535, 16540, 16542, 16547, 16549, - 16551, 16553, 16555, 16557, 16569, 16573, 16580, 16584, 16590, 16594, - 16604, 16616, 16617, 16620, 16621, 16624, 16628, 16632, 16638, 16639, - 16644, 16648, 16658, 16659, 16660, 16661, 16662, 16663, 16664, 16665, - 16669, 16670, 16671, 16672, 16677, 16682, 16691, 16712, 16716, 16721, - 16732, 16749, 16755, 16756, 16757, 16760, 16768, 16778, 16793, 16794, - 16798, 16810, 16811, 16814, 16815, 16818, 16822, 16829, 16833, 16837, - 16846, 16858, 16859, 16863, 16864, 16868, 16869, 16872, 16873, 16878, - 16879, 16883, 16884, 16888, 16900, 16901, 16902, 16903, 16904, 16905, - 16906, 16907, 16908, 16912, 16914, 16919, 16920, 16921, 16922, 16923, - 16924, 16925, 16927, 16931, 16933, 16935, 16938, 16942, 16945, 16949, - 16958, 16975, 16982, 16987, 16993, 16994, 16995, 16996, 16997, 17001, - 17010, 17024, 17025, 17026, 17027, 17028, 17037, 17038, 17039, 17040, - 17041, 17045, 17047, 17057, 17060, 17066, 17067, 17068, 17072, 17073, - 17074, 17078, 17079, 17083, 17101, 17121, 17122, 17131, 17132, 17136, - 17137, 17140, 17148, 17156, 17164, 17187, 17188, 17199, 17203, 17209, - 17211, 17216, 17218, 17220, 17230, 17232, 17243, 17247, 17251, 17255, - 17259, 17268, 17276, 17308, 17315, 17347, 17351, 17358, 17366, 17370, - 17376, 17383, 17387, 17391, 17397, 17398, 17400, 17401, 17402, 17406, - 17447, 17475, 17479, 17483, 17489, 17491, 17505, 17541, 17554, 17555, - 17558, 17559, 17576, 17577, 17578, 17583, 17584, 17585, 17590, 17591, - 17592, 17593, 17599, 17600, 17601, 17602, 17603, 17609, 17610, 17630, - 17631, 17632, 17633, 17634, 17635, 17636, 17637, 17638, 17639, 17640, - 17641, 17642, 17643, 17644, 17645, 17646, 17647, 17648, 17649, 17650, - 17651, 17652, 17653, 17654, 17655, 17656, 17657, 17658, 17659, 17660, - 17661, 17662, 17663, 17664, 17665, 17666, 17667, 17668, 17669, 17670, - 17671, 17672, 17673, 17674, 17675, 17676, 17677, 17678, 17679, 17680, - 17681, 17682, 17683, 17684, 17685, 17686, 17687, 17688, 17689, 17690, - 17691, 17692, 17693, 17694, 17695, 17696, 17697, 17698, 17699, 17700, - 17701, 17702, 17703, 17704, 17705, 17706, 17707, 17708, 17709, 17710, - 17711, 17712, 17713, 17714, 17715, 17716, 17717, 17718, 17719, 17720, - 17721, 17722, 17723, 17724, 17725, 17726, 17727, 17728, 17729, 17730, - 17731, 17732, 17733, 17734, 17735, 17736, 17737, 17738, 17739, 17740, - 17741, 17742, 17743, 17744, 17745, 17746, 17747, 17748, 17749, 17750, - 17751, 17752, 17753, 17754, 17755, 17756, 17757, 17758, 17759, 17760, - 17761, 17762, 17763, 17764, 17765, 17766, 17767, 17768, 17769, 17770, - 17771, 17772, 17773, 17774, 17775, 17776, 17777, 17778, 17779, 17780, - 17781, 17782, 17783, 17784, 17785, 17786, 17787, 17788, 17789, 17790, - 17791, 17792, 17793, 17794, 17795, 17796, 17797, 17798, 17799, 17800, - 17801, 17802, 17803, 17804, 17805, 17806, 17807, 17808, 17809, 17810, - 17811, 17812, 17813, 17814, 17815, 17816, 17817, 17818, 17819, 17820, - 17821, 17822, 17823, 17824, 17825, 17826, 17827, 17828, 17829, 17830, - 17831, 17832, 17833, 17834, 17835, 17836, 17837, 17838, 17839, 17840, - 17841, 17842, 17843, 17844, 17845, 17846, 17847, 17848, 17849, 17850, - 17851, 17852, 17853, 17854, 17855, 17856, 17857, 17858, 17859, 17860, - 17861, 17862, 17863, 17864, 17865, 17866, 17867, 17868, 17869, 17870, - 17871, 17872, 17873, 17874, 17875, 17876, 17877, 17878, 17879, 17880, - 17881, 17882, 17883, 17884, 17885, 17886, 17887, 17888, 17889, 17890, - 17891, 17892, 17893, 17894, 17895, 17896, 17897, 17898, 17899, 17900, - 17901, 17902, 17903, 17904, 17905, 17906, 17907, 17908, 17909, 17910, - 17911, 17912, 17913, 17914, 17915, 17916, 17917, 17918, 17919, 17920, - 17921, 17922, 17923, 17924, 17925, 17926, 17927, 17928, 17929, 17930, - 17931, 17932, 17933, 17934, 17935, 17936, 17937, 17938, 17939, 17940, - 17941, 17942, 17943, 17944, 17945, 17946, 17947, 17948, 17949, 17950, - 17951, 17952, 17953, 17954, 17955, 17956, 17970, 17971, 17972, 17973, - 17974, 17975, 17976, 17977, 17978, 17979, 17980, 17981, 17982, 17983, - 17984, 17985, 17986, 17987, 17988, 17989, 17990, 17991, 17992, 17993, - 17994, 17995, 17996, 17997, 17998, 17999, 18000, 18001, 18002, 18003, - 18004, 18005, 18006, 18007, 18008, 18009, 18010, 18011, 18012, 18013, - 18014, 18015, 18016, 18017, 18018, 18019, 18020, 18021, 18022, 18023, - 18024, 18025, 18026, 18027, 18028, 18029, 18030, 18031, 18032, 18046, - 18047, 18048, 18049, 18050, 18051, 18052, 18053, 18054, 18055, 18056, - 18057, 18058, 18059, 18060, 18061, 18062, 18063, 18064, 18065, 18066, - 18067, 18068, 18078, 18079, 18080, 18081, 18082, 18083, 18084, 18085, - 18086, 18087, 18088, 18089, 18090, 18091, 18092, 18093, 18094, 18095, - 18096, 18097, 18098, 18099, 18100, 18101, 18102, 18103, 18104, 18105, - 18106, 18107, 18108, 18109, 18110, 18111, 18112, 18113, 18114, 18115, - 18116, 18117, 18118, 18119, 18120, 18121, 18122, 18123, 18124, 18125, - 18126, 18127, 18128, 18129, 18130, 18131, 18132, 18133, 18134, 18135, - 18136, 18137, 18138, 18139, 18140, 18141, 18142, 18143, 18144, 18145, - 18146, 18147, 18148, 18149, 18150, 18151, 18152, 18153, 18154, 18155, - 18168, 18169, 18170, 18171, 18172, 18173, 18174, 18175, 18176, 18177, - 18178, 18179, 18180, 18181, 18182, 18183, 18184, 18185, 18186, 18187, - 18188, 18189, 18190, 18191, 18192, 18193, 18194, 18195, 18196, 18197, - 18198, 18199, 18200, 18201, 18202, 18203, 18204, 18205, 18206, 18207, - 18208, 18209, 18210, 18211, 18212, 18213, 18214, 18215, 18216, 18217, - 18218, 18219, 18220, 18221, 18222, 18223, 18224, 18225, 18226, 18227, - 18228, 18229, 18230, 18231, 18232, 18233, 18234, 18235, 18236, 18237, - 18238, 18239, 18240, 18241, 18242, 18243, 18244, 18245, 18246, 18247, - 18248, 18249, 18250, 18251, 18252, 18253, 18254, 18255, 18256, 18257, - 18258, 18259, 18260, 18261, 18262, 18263, 18264, 18265, 18266, 18267, - 18268, 18269, 18270, 18271, 18272, 18273, 18274, 18275, 18276, 18277, - 18278, 18279, 18280, 18281, 18282, 18283, 18284, 18285, 18286, 18287, - 18288, 18289, 18290, 18291, 18292, 18293, 18294, 18295, 18296, 18297, - 18298, 18299, 18300, 18301, 18302, 18303, 18304, 18305, 18306, 18307, - 18308, 18309, 18310, 18311, 18312, 18313, 18314, 18315, 18316, 18317, - 18318, 18319, 18320, 18321, 18322, 18323, 18324, 18325, 18326, 18327, - 18328, 18329, 18330, 18331, 18332, 18333, 18334, 18335, 18336, 18337, - 18338, 18339, 18340, 18341, 18342, 18343, 18344, 18345, 18346, 18347, - 18348, 18349, 18350, 18351, 18352, 18353, 18354, 18355, 18356, 18357, - 18358, 18359, 18360, 18361, 18362, 18363, 18364, 18365, 18366, 18367, - 18368, 18369, 18370, 18371, 18372, 18373, 18374, 18375, 18376, 18377, - 18378, 18379, 18380, 18381, 18382, 18383, 18384, 18385, 18386, 18387, - 18388, 18389, 18390, 18391, 18392, 18393, 18394, 18395, 18396, 18397, - 18398, 18399, 18400, 18401, 18402, 18403, 18404, 18405, 18406, 18407, - 18408, 18409, 18410, 18411, 18412, 18413, 18414, 18415, 18416, 18417, - 18418, 18419, 18420, 18421, 18422, 18423, 18424, 18425, 18426, 18427, - 18428, 18429, 18430, 18431, 18432, 18433, 18434, 18435, 18436, 18437, - 18438, 18439, 18440, 18441, 18442, 18443, 18444, 18445, 18446, 18447, - 18448, 18449, 18450, 18451, 18452, 18453, 18454, 18455, 18456, 18457, - 18458, 18459, 18460, 18461, 18462, 18463, 18464, 18465, 18466, 18467, - 18468, 18469, 18470, 18471, 18472, 18473, 18474, 18475, 18476, 18477, - 18478, 18479, 18480, 18481, 18482, 18483, 18484, 18485, 18486, 18487, - 18488, 18489, 18490, 18491, 18492, 18493, 18494, 18495, 18496, 18497, - 18498, 18499, 18500, 18501, 18502, 18503, 18504, 18505, 18506, 18507, - 18508, 18509, 18510, 18511, 18512, 18513, 18514, 18515, 18516, 18517, - 18518, 18519, 18520, 18521, 18522, 18523, 18524, 18525, 18526, 18527, - 18528, 18529, 18530, 18531, 18532, 18533, 18534, 18535, 18536, 18537, - 18538, 18539, 18540, 18541, 18542, 18543, 18544, 18545, 18546, 18547, - 18548, 18549, 18550, 18551, 18552, 18553, 18554, 18555, 18556, 18557, - 18558, 18559, 18560, 18561, 18562, 18563, 18564, 18565, 18566, 18567, - 18568, 18569, 18570, 18571, 18572, 18573, 18574, 18575, 18576, 18577, - 18578, 18579, 18580, 18581, 18582, 18583, 18584, 18585, 18586, 18587, - 18588, 18589, 18590, 18591, 18592, 18593, 18594, 18595, 18596, 18597, - 18598, 18599, 18600, 18601, 18602, 18603, 18604, 18605, 18606, 18607, - 18608, 18609, 18610, 18611, 18612, 18613, 18614, 18615, 18616, 18617, - 18618, 18619 + 14030, 14044, 14045, 14049, 14063, 14120, 14134, 14136, 14141, 14150, + 14152, 14154, 14156, 14161, 14163, 14168, 14176, 14187, 14215, 14216, + 14220, 14222, 14227, 14236, 14256, 14276, 14294, 14306, 14321, 14322, + 14326, 14329, 14342, 14347, 14354, 14359, 14365, 14370, 14379, 14381, + 14384, 14388, 14389, 14390, 14391, 14392, 14393, 14398, 14404, 14419, + 14420, 14421, 14422, 14423, 14434, 14440, 14448, 14449, 14455, 14460, + 14465, 14470, 14475, 14480, 14485, 14490, 14496, 14502, 14508, 14515, + 14537, 14546, 14550, 14558, 14562, 14570, 14582, 14603, 14607, 14613, + 14617, 14630, 14638, 14648, 14650, 14652, 14654, 14656, 14658, 14663, + 14664, 14671, 14680, 14688, 14697, 14708, 14716, 14717, 14718, 14722, + 14724, 14726, 14728, 14730, 14732, 14734, 14739, 14744, 14750, 14758, + 14763, 14770, 14777, 14781, 14785, 14793, 14828, 14829, 14831, 14840, + 14847, 14863, 14865, 14867, 14869, 14871, 14873, 14875, 14877, 14879, + 14881, 14883, 14885, 14887, 14889, 14892, 14894, 14897, 14899, 14901, + 14903, 14906, 14911, 14920, 14925, 14934, 14939, 14948, 14953, 14963, + 14972, 14981, 14990, 15009, 15018, 15027, 15036, 15045, 15062, 15071, + 15080, 15089, 15098, 15107, 15116, 15120, 15124, 15132, 15140, 15148, + 15156, 15177, 15200, 15212, 15219, 15235, 15240, 15246, 15253, 15260, + 15268, 15276, 15293, 15312, 15338, 15340, 15342, 15344, 15346, 15348, + 15350, 15352, 15354, 15356, 15358, 15360, 15362, 15364, 15366, 15368, + 15370, 15372, 15374, 15378, 15382, 15387, 15403, 15404, 15405, 15422, + 15435, 15437, 15439, 15451, 15476, 15488, 15500, 15508, 15519, 15530, + 15540, 15546, 15555, 15565, 15575, 15588, 15598, 15629, 15665, 15675, + 15686, 15687, 15688, 15695, 15702, 15706, 15710, 15714, 15718, 15722, + 15726, 15730, 15734, 15738, 15742, 15746, 15750, 15757, 15761, 15765, + 15769, 15771, 15778, 15785, 15792, 15799, 15810, 15824, 15834, 15845, + 15861, 15871, 15878, 15885, 15892, 15896, 15904, 15913, 15922, 15926, + 15930, 15934, 15938, 15942, 15951, 15955, 15965, 15969, 15973, 15978, + 15989, 15995, 16009, 16020, 16034, 16050, 16062, 16072, 16081, 16090, + 16098, 16120, 16136, 16160, 16162, 16166, 16168, 16170, 16173, 16176, + 16179, 16180, 16183, 16191, 16201, 16202, 16205, 16206, 16207, 16210, + 16211, 16212, 16217, 16221, 16225, 16229, 16236, 16237, 16245, 16246, + 16250, 16251, 16259, 16260, 16264, 16265, 16270, 16279, 16281, 16296, + 16299, 16327, 16328, 16331, 16332, 16340, 16348, 16356, 16365, 16375, + 16393, 16439, 16448, 16457, 16466, 16475, 16487, 16488, 16489, 16490, + 16491, 16505, 16506, 16507, 16510, 16511, 16514, 16517, 16518, 16519, + 16522, 16523, 16526, 16527, 16528, 16529, 16530, 16531, 16532, 16533, + 16534, 16535, 16536, 16537, 16540, 16542, 16547, 16549, 16554, 16556, + 16558, 16560, 16562, 16564, 16576, 16580, 16587, 16591, 16597, 16601, + 16611, 16623, 16624, 16627, 16628, 16631, 16635, 16639, 16645, 16646, + 16651, 16655, 16665, 16666, 16667, 16668, 16669, 16670, 16671, 16672, + 16676, 16677, 16678, 16679, 16684, 16689, 16698, 16719, 16723, 16728, + 16739, 16756, 16762, 16763, 16764, 16767, 16775, 16785, 16800, 16801, + 16805, 16817, 16818, 16821, 16822, 16825, 16829, 16836, 16840, 16844, + 16853, 16865, 16866, 16870, 16871, 16875, 16876, 16879, 16880, 16885, + 16886, 16890, 16891, 16895, 16907, 16908, 16909, 16910, 16911, 16912, + 16913, 16914, 16915, 16919, 16921, 16926, 16927, 16928, 16929, 16930, + 16931, 16932, 16934, 16938, 16940, 16942, 16945, 16949, 16952, 16956, + 16965, 16982, 16989, 16994, 17000, 17001, 17002, 17003, 17004, 17008, + 17017, 17031, 17032, 17033, 17034, 17035, 17044, 17045, 17046, 17047, + 17048, 17052, 17054, 17064, 17067, 17073, 17074, 17075, 17079, 17080, + 17081, 17085, 17086, 17090, 17108, 17128, 17129, 17138, 17139, 17143, + 17144, 17147, 17155, 17163, 17171, 17194, 17195, 17206, 17210, 17216, + 17218, 17223, 17225, 17227, 17237, 17239, 17250, 17254, 17258, 17262, + 17266, 17275, 17283, 17315, 17322, 17354, 17358, 17365, 17373, 17377, + 17383, 17390, 17394, 17398, 17404, 17405, 17407, 17408, 17409, 17413, + 17454, 17482, 17486, 17490, 17496, 17498, 17512, 17548, 17561, 17562, + 17565, 17566, 17583, 17584, 17585, 17590, 17591, 17592, 17597, 17598, + 17599, 17600, 17606, 17607, 17608, 17609, 17610, 17616, 17617, 17637, + 17638, 17639, 17640, 17641, 17642, 17643, 17644, 17645, 17646, 17647, + 17648, 17649, 17650, 17651, 17652, 17653, 17654, 17655, 17656, 17657, + 17658, 17659, 17660, 17661, 17662, 17663, 17664, 17665, 17666, 17667, + 17668, 17669, 17670, 17671, 17672, 17673, 17674, 17675, 17676, 17677, + 17678, 17679, 17680, 17681, 17682, 17683, 17684, 17685, 17686, 17687, + 17688, 17689, 17690, 17691, 17692, 17693, 17694, 17695, 17696, 17697, + 17698, 17699, 17700, 17701, 17702, 17703, 17704, 17705, 17706, 17707, + 17708, 17709, 17710, 17711, 17712, 17713, 17714, 17715, 17716, 17717, + 17718, 17719, 17720, 17721, 17722, 17723, 17724, 17725, 17726, 17727, + 17728, 17729, 17730, 17731, 17732, 17733, 17734, 17735, 17736, 17737, + 17738, 17739, 17740, 17741, 17742, 17743, 17744, 17745, 17746, 17747, + 17748, 17749, 17750, 17751, 17752, 17753, 17754, 17755, 17756, 17757, + 17758, 17759, 17760, 17761, 17762, 17763, 17764, 17765, 17766, 17767, + 17768, 17769, 17770, 17771, 17772, 17773, 17774, 17775, 17776, 17777, + 17778, 17779, 17780, 17781, 17782, 17783, 17784, 17785, 17786, 17787, + 17788, 17789, 17790, 17791, 17792, 17793, 17794, 17795, 17796, 17797, + 17798, 17799, 17800, 17801, 17802, 17803, 17804, 17805, 17806, 17807, + 17808, 17809, 17810, 17811, 17812, 17813, 17814, 17815, 17816, 17817, + 17818, 17819, 17820, 17821, 17822, 17823, 17824, 17825, 17826, 17827, + 17828, 17829, 17830, 17831, 17832, 17833, 17834, 17835, 17836, 17837, + 17838, 17839, 17840, 17841, 17842, 17843, 17844, 17845, 17846, 17847, + 17848, 17849, 17850, 17851, 17852, 17853, 17854, 17855, 17856, 17857, + 17858, 17859, 17860, 17861, 17862, 17863, 17864, 17865, 17866, 17867, + 17868, 17869, 17870, 17871, 17872, 17873, 17874, 17875, 17876, 17877, + 17878, 17879, 17880, 17881, 17882, 17883, 17884, 17885, 17886, 17887, + 17888, 17889, 17890, 17891, 17892, 17893, 17894, 17895, 17896, 17897, + 17898, 17899, 17900, 17901, 17902, 17903, 17904, 17905, 17906, 17907, + 17908, 17909, 17910, 17911, 17912, 17913, 17914, 17915, 17916, 17917, + 17918, 17919, 17920, 17921, 17922, 17923, 17924, 17925, 17926, 17927, + 17928, 17929, 17930, 17931, 17932, 17933, 17934, 17935, 17936, 17937, + 17938, 17939, 17940, 17941, 17942, 17943, 17944, 17945, 17946, 17947, + 17948, 17949, 17950, 17951, 17952, 17953, 17954, 17955, 17956, 17957, + 17958, 17959, 17960, 17961, 17962, 17963, 17977, 17978, 17979, 17980, + 17981, 17982, 17983, 17984, 17985, 17986, 17987, 17988, 17989, 17990, + 17991, 17992, 17993, 17994, 17995, 17996, 17997, 17998, 17999, 18000, + 18001, 18002, 18003, 18004, 18005, 18006, 18007, 18008, 18009, 18010, + 18011, 18012, 18013, 18014, 18015, 18016, 18017, 18018, 18019, 18020, + 18021, 18022, 18023, 18024, 18025, 18026, 18027, 18028, 18029, 18030, + 18031, 18032, 18033, 18034, 18035, 18036, 18037, 18038, 18039, 18053, + 18054, 18055, 18056, 18057, 18058, 18059, 18060, 18061, 18062, 18063, + 18064, 18065, 18066, 18067, 18068, 18069, 18070, 18071, 18072, 18073, + 18074, 18075, 18085, 18086, 18087, 18088, 18089, 18090, 18091, 18092, + 18093, 18094, 18095, 18096, 18097, 18098, 18099, 18100, 18101, 18102, + 18103, 18104, 18105, 18106, 18107, 18108, 18109, 18110, 18111, 18112, + 18113, 18114, 18115, 18116, 18117, 18118, 18119, 18120, 18121, 18122, + 18123, 18124, 18125, 18126, 18127, 18128, 18129, 18130, 18131, 18132, + 18133, 18134, 18135, 18136, 18137, 18138, 18139, 18140, 18141, 18142, + 18143, 18144, 18145, 18146, 18147, 18148, 18149, 18150, 18151, 18152, + 18153, 18154, 18155, 18156, 18157, 18158, 18159, 18160, 18161, 18162, + 18175, 18176, 18177, 18178, 18179, 18180, 18181, 18182, 18183, 18184, + 18185, 18186, 18187, 18188, 18189, 18190, 18191, 18192, 18193, 18194, + 18195, 18196, 18197, 18198, 18199, 18200, 18201, 18202, 18203, 18204, + 18205, 18206, 18207, 18208, 18209, 18210, 18211, 18212, 18213, 18214, + 18215, 18216, 18217, 18218, 18219, 18220, 18221, 18222, 18223, 18224, + 18225, 18226, 18227, 18228, 18229, 18230, 18231, 18232, 18233, 18234, + 18235, 18236, 18237, 18238, 18239, 18240, 18241, 18242, 18243, 18244, + 18245, 18246, 18247, 18248, 18249, 18250, 18251, 18252, 18253, 18254, + 18255, 18256, 18257, 18258, 18259, 18260, 18261, 18262, 18263, 18264, + 18265, 18266, 18267, 18268, 18269, 18270, 18271, 18272, 18273, 18274, + 18275, 18276, 18277, 18278, 18279, 18280, 18281, 18282, 18283, 18284, + 18285, 18286, 18287, 18288, 18289, 18290, 18291, 18292, 18293, 18294, + 18295, 18296, 18297, 18298, 18299, 18300, 18301, 18302, 18303, 18304, + 18305, 18306, 18307, 18308, 18309, 18310, 18311, 18312, 18313, 18314, + 18315, 18316, 18317, 18318, 18319, 18320, 18321, 18322, 18323, 18324, + 18325, 18326, 18327, 18328, 18329, 18330, 18331, 18332, 18333, 18334, + 18335, 18336, 18337, 18338, 18339, 18340, 18341, 18342, 18343, 18344, + 18345, 18346, 18347, 18348, 18349, 18350, 18351, 18352, 18353, 18354, + 18355, 18356, 18357, 18358, 18359, 18360, 18361, 18362, 18363, 18364, + 18365, 18366, 18367, 18368, 18369, 18370, 18371, 18372, 18373, 18374, + 18375, 18376, 18377, 18378, 18379, 18380, 18381, 18382, 18383, 18384, + 18385, 18386, 18387, 18388, 18389, 18390, 18391, 18392, 18393, 18394, + 18395, 18396, 18397, 18398, 18399, 18400, 18401, 18402, 18403, 18404, + 18405, 18406, 18407, 18408, 18409, 18410, 18411, 18412, 18413, 18414, + 18415, 18416, 18417, 18418, 18419, 18420, 18421, 18422, 18423, 18424, + 18425, 18426, 18427, 18428, 18429, 18430, 18431, 18432, 18433, 18434, + 18435, 18436, 18437, 18438, 18439, 18440, 18441, 18442, 18443, 18444, + 18445, 18446, 18447, 18448, 18449, 18450, 18451, 18452, 18453, 18454, + 18455, 18456, 18457, 18458, 18459, 18460, 18461, 18462, 18463, 18464, + 18465, 18466, 18467, 18468, 18469, 18470, 18471, 18472, 18473, 18474, + 18475, 18476, 18477, 18478, 18479, 18480, 18481, 18482, 18483, 18484, + 18485, 18486, 18487, 18488, 18489, 18490, 18491, 18492, 18493, 18494, + 18495, 18496, 18497, 18498, 18499, 18500, 18501, 18502, 18503, 18504, + 18505, 18506, 18507, 18508, 18509, 18510, 18511, 18512, 18513, 18514, + 18515, 18516, 18517, 18518, 18519, 18520, 18521, 18522, 18523, 18524, + 18525, 18526, 18527, 18528, 18529, 18530, 18531, 18532, 18533, 18534, + 18535, 18536, 18537, 18538, 18539, 18540, 18541, 18542, 18543, 18544, + 18545, 18546, 18547, 18548, 18549, 18550, 18551, 18552, 18553, 18554, + 18555, 18556, 18557, 18558, 18559, 18560, 18561, 18562, 18563, 18564, + 18565, 18566, 18567, 18568, 18569, 18570, 18571, 18572, 18573, 18574, + 18575, 18576, 18577, 18578, 18579, 18580, 18581, 18582, 18583, 18584, + 18585, 18586, 18587, 18588, 18589, 18590, 18591, 18592, 18593, 18594, + 18595, 18596, 18597, 18598, 18599, 18600, 18601, 18602, 18603, 18604, + 18605, 18606, 18607, 18608, 18609, 18610, 18611, 18612, 18613, 18614, + 18615, 18616, 18617, 18618, 18619, 18620, 18621, 18622, 18623, 18624, + 18625, 18626 }; #endif @@ -47930,7 +47930,7 @@ YYLTYPE yylloc; parser_errposition(defel->location))); fc->colexpr = defel->arg; } - else if (strcmp(defel->defname, "is_not_null") == 0) + else if (strcmp(defel->defname, "__pg__is_not_null") == 0) { if (nullability_seen) ereport(ERROR, @@ -47979,41 +47979,48 @@ YYLTYPE yylloc; case 1898: #line 14142 "gram.y" - { (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} + { + if (strcmp((yyvsp[(1) - (2)].str), "__pg__is_not_null") == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("option name \"%s\" cannot be used in XMLTABLE", (yyvsp[(1) - (2)].str)), + parser_errposition((yylsp[(1) - (2)])))); + (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); + ;} break; case 1899: -#line 14144 "gram.y" +#line 14151 "gram.y" { (yyval.defelt) = makeDefElem("default", (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 1900: -#line 14146 "gram.y" - { (yyval.defelt) = makeDefElem("is_not_null", (Node *) makeBoolean(true), (yylsp[(1) - (2)])); ;} +#line 14153 "gram.y" + { (yyval.defelt) = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(true), (yylsp[(1) - (2)])); ;} break; case 1901: -#line 14148 "gram.y" - { (yyval.defelt) = makeDefElem("is_not_null", (Node *) makeBoolean(false), (yylsp[(1) - (1)])); ;} +#line 14155 "gram.y" + { (yyval.defelt) = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(false), (yylsp[(1) - (1)])); ;} break; case 1902: -#line 14150 "gram.y" +#line 14157 "gram.y" { (yyval.defelt) = makeDefElem("path", (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 1903: -#line 14155 "gram.y" +#line 14162 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].target)); ;} break; case 1904: -#line 14157 "gram.y" +#line 14164 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].target)); ;} break; case 1905: -#line 14162 "gram.y" +#line 14169 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = (yyvsp[(3) - (3)].str); @@ -48024,7 +48031,7 @@ YYLTYPE yylloc; break; case 1906: -#line 14170 "gram.y" +#line 14177 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = NULL; @@ -48035,7 +48042,7 @@ YYLTYPE yylloc; break; case 1907: -#line 14186 "gram.y" +#line 14193 "gram.y" { JsonTable *n = makeNode(JsonTable); char *pathstring; @@ -48058,27 +48065,27 @@ YYLTYPE yylloc; break; case 1908: -#line 14208 "gram.y" +#line 14215 "gram.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; case 1909: -#line 14209 "gram.y" +#line 14216 "gram.y" { (yyval.str) = NULL; ;} break; case 1910: -#line 14214 "gram.y" +#line 14221 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 1911: -#line 14216 "gram.y" +#line 14223 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 1912: -#line 14221 "gram.y" +#line 14228 "gram.y" { JsonTableColumn *n = makeNode(JsonTableColumn); @@ -48090,7 +48097,7 @@ YYLTYPE yylloc; break; case 1913: -#line 14234 "gram.y" +#line 14241 "gram.y" { JsonTableColumn *n = makeNode(JsonTableColumn); @@ -48109,7 +48116,7 @@ YYLTYPE yylloc; break; case 1914: -#line 14254 "gram.y" +#line 14261 "gram.y" { JsonTableColumn *n = makeNode(JsonTableColumn); @@ -48128,7 +48135,7 @@ YYLTYPE yylloc; break; case 1915: -#line 14272 "gram.y" +#line 14279 "gram.y" { JsonTableColumn *n = makeNode(JsonTableColumn); @@ -48147,7 +48154,7 @@ YYLTYPE yylloc; break; case 1916: -#line 14289 "gram.y" +#line 14296 "gram.y" { JsonTableColumn *n = makeNode(JsonTableColumn); @@ -48161,7 +48168,7 @@ YYLTYPE yylloc; break; case 1917: -#line 14301 "gram.y" +#line 14308 "gram.y" { JsonTableColumn *n = makeNode(JsonTableColumn); @@ -48175,17 +48182,17 @@ YYLTYPE yylloc; break; case 1920: -#line 14320 "gram.y" +#line 14327 "gram.y" { (yyval.node) = (Node *) makeJsonTablePathSpec((yyvsp[(2) - (2)].str), NULL, (yylsp[(2) - (2)]), -1); ;} break; case 1921: -#line 14322 "gram.y" +#line 14329 "gram.y" { (yyval.node) = NULL; ;} break; case 1922: -#line 14336 "gram.y" +#line 14343 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = (yyvsp[(2) - (2)].list); @@ -48193,7 +48200,7 @@ YYLTYPE yylloc; break; case 1923: -#line 14341 "gram.y" +#line 14348 "gram.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = (yyvsp[(3) - (3)].list); @@ -48202,7 +48209,7 @@ YYLTYPE yylloc; break; case 1924: -#line 14348 "gram.y" +#line 14355 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (5)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(4) - (5)].ival))); @@ -48210,7 +48217,7 @@ YYLTYPE yylloc; break; case 1925: -#line 14353 "gram.y" +#line 14360 "gram.y" { (yyval.typnam) = (yyvsp[(2) - (6)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(5) - (6)].ival))); @@ -48219,7 +48226,7 @@ YYLTYPE yylloc; break; case 1926: -#line 14359 "gram.y" +#line 14366 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); @@ -48227,7 +48234,7 @@ YYLTYPE yylloc; break; case 1927: -#line 14364 "gram.y" +#line 14371 "gram.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); @@ -48236,47 +48243,47 @@ YYLTYPE yylloc; break; case 1928: -#line 14373 "gram.y" +#line 14380 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeInteger(-1)); ;} break; case 1929: -#line 14375 "gram.y" +#line 14382 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (4)].list), makeInteger((yyvsp[(3) - (4)].ival))); ;} break; case 1930: -#line 14377 "gram.y" +#line 14384 "gram.y" { (yyval.list) = NIL; ;} break; case 1931: -#line 14381 "gram.y" +#line 14388 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1932: -#line 14382 "gram.y" +#line 14389 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1933: -#line 14383 "gram.y" +#line 14390 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1934: -#line 14384 "gram.y" +#line 14391 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1935: -#line 14385 "gram.y" +#line 14392 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1936: -#line 14387 "gram.y" +#line 14394 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -48284,7 +48291,7 @@ YYLTYPE yylloc; break; case 1937: -#line 14392 "gram.y" +#line 14399 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (4)].typnam); (yyval.typnam)->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), @@ -48293,37 +48300,37 @@ YYLTYPE yylloc; break; case 1938: -#line 14397 "gram.y" +#line 14404 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1939: -#line 14412 "gram.y" +#line 14419 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1940: -#line 14413 "gram.y" +#line 14420 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1941: -#line 14414 "gram.y" +#line 14421 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1942: -#line 14415 "gram.y" +#line 14422 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1943: -#line 14416 "gram.y" +#line 14423 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1944: -#line 14428 "gram.y" +#line 14435 "gram.y" { (yyval.typnam) = makeTypeName((yyvsp[(1) - (2)].str)); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -48332,7 +48339,7 @@ YYLTYPE yylloc; break; case 1945: -#line 14434 "gram.y" +#line 14441 "gram.y" { (yyval.typnam) = makeTypeNameFromNameList(lcons(makeString((yyvsp[(1) - (3)].str)), (yyvsp[(2) - (3)].list))); (yyval.typnam)->typmods = (yyvsp[(3) - (3)].list); @@ -48341,17 +48348,17 @@ YYLTYPE yylloc; break; case 1946: -#line 14441 "gram.y" +#line 14448 "gram.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; case 1947: -#line 14442 "gram.y" +#line 14449 "gram.y" { (yyval.list) = NIL; ;} break; case 1948: -#line 14449 "gram.y" +#line 14456 "gram.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48359,7 +48366,7 @@ YYLTYPE yylloc; break; case 1949: -#line 14454 "gram.y" +#line 14461 "gram.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48367,7 +48374,7 @@ YYLTYPE yylloc; break; case 1950: -#line 14459 "gram.y" +#line 14466 "gram.y" { (yyval.typnam) = SystemTypeName("int2"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48375,7 +48382,7 @@ YYLTYPE yylloc; break; case 1951: -#line 14464 "gram.y" +#line 14471 "gram.y" { (yyval.typnam) = SystemTypeName("int8"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48383,7 +48390,7 @@ YYLTYPE yylloc; break; case 1952: -#line 14469 "gram.y" +#line 14476 "gram.y" { (yyval.typnam) = SystemTypeName("float4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48391,7 +48398,7 @@ YYLTYPE yylloc; break; case 1953: -#line 14474 "gram.y" +#line 14481 "gram.y" { (yyval.typnam) = (yyvsp[(2) - (2)].typnam); (yyval.typnam)->location = (yylsp[(1) - (2)]); @@ -48399,7 +48406,7 @@ YYLTYPE yylloc; break; case 1954: -#line 14479 "gram.y" +#line 14486 "gram.y" { (yyval.typnam) = SystemTypeName("float8"); (yyval.typnam)->location = (yylsp[(1) - (2)]); @@ -48407,7 +48414,7 @@ YYLTYPE yylloc; break; case 1955: -#line 14484 "gram.y" +#line 14491 "gram.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -48416,7 +48423,7 @@ YYLTYPE yylloc; break; case 1956: -#line 14490 "gram.y" +#line 14497 "gram.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -48425,7 +48432,7 @@ YYLTYPE yylloc; break; case 1957: -#line 14496 "gram.y" +#line 14503 "gram.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -48434,7 +48441,7 @@ YYLTYPE yylloc; break; case 1958: -#line 14502 "gram.y" +#line 14509 "gram.y" { (yyval.typnam) = SystemTypeName("bool"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48442,7 +48449,7 @@ YYLTYPE yylloc; break; case 1959: -#line 14509 "gram.y" +#line 14516 "gram.y" { /* * Check FLOAT() precision limits assuming IEEE floating @@ -48466,35 +48473,35 @@ YYLTYPE yylloc; break; case 1960: -#line 14530 "gram.y" +#line 14537 "gram.y" { (yyval.typnam) = SystemTypeName("float8"); ;} break; case 1961: -#line 14540 "gram.y" +#line 14547 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1962: -#line 14544 "gram.y" +#line 14551 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1963: -#line 14552 "gram.y" +#line 14559 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1964: -#line 14556 "gram.y" +#line 14563 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); (yyval.typnam)->typmods = NIL; @@ -48502,7 +48509,7 @@ YYLTYPE yylloc; break; case 1965: -#line 14564 "gram.y" +#line 14571 "gram.y" { char *typname; @@ -48514,7 +48521,7 @@ YYLTYPE yylloc; break; case 1966: -#line 14576 "gram.y" +#line 14583 "gram.y" { /* bit defaults to bit(1), varbit to no limit */ if ((yyvsp[(2) - (2)].boolean)) @@ -48531,28 +48538,28 @@ YYLTYPE yylloc; break; case 1967: -#line 14597 "gram.y" +#line 14604 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1968: -#line 14601 "gram.y" +#line 14608 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1969: -#line 14607 "gram.y" +#line 14614 "gram.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; case 1970: -#line 14611 "gram.y" +#line 14618 "gram.y" { /* Length was not specified so allow to be unrestricted. * This handles problems with fixed-length (bpchar) strings @@ -48566,7 +48573,7 @@ YYLTYPE yylloc; break; case 1971: -#line 14624 "gram.y" +#line 14631 "gram.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (4)].str)); (yyval.typnam)->typmods = list_make1(makeIntConst((yyvsp[(3) - (4)].ival), (yylsp[(3) - (4)]))); @@ -48575,7 +48582,7 @@ YYLTYPE yylloc; break; case 1972: -#line 14632 "gram.y" +#line 14639 "gram.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (1)].str)); /* char defaults to char(1), varchar to no limit */ @@ -48586,47 +48593,47 @@ YYLTYPE yylloc; break; case 1973: -#line 14642 "gram.y" +#line 14649 "gram.y" { (yyval.str) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; case 1974: -#line 14644 "gram.y" +#line 14651 "gram.y" { (yyval.str) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; case 1975: -#line 14646 "gram.y" +#line 14653 "gram.y" { (yyval.str) = "varchar"; ;} break; case 1976: -#line 14648 "gram.y" +#line 14655 "gram.y" { (yyval.str) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; case 1977: -#line 14650 "gram.y" +#line 14657 "gram.y" { (yyval.str) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; case 1978: -#line 14652 "gram.y" +#line 14659 "gram.y" { (yyval.str) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; case 1979: -#line 14656 "gram.y" +#line 14663 "gram.y" { (yyval.boolean) = true; ;} break; case 1980: -#line 14657 "gram.y" +#line 14664 "gram.y" { (yyval.boolean) = false; ;} break; case 1981: -#line 14665 "gram.y" +#line 14672 "gram.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -48638,7 +48645,7 @@ YYLTYPE yylloc; break; case 1982: -#line 14674 "gram.y" +#line 14681 "gram.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -48649,7 +48656,7 @@ YYLTYPE yylloc; break; case 1983: -#line 14682 "gram.y" +#line 14689 "gram.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -48661,7 +48668,7 @@ YYLTYPE yylloc; break; case 1984: -#line 14691 "gram.y" +#line 14698 "gram.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -48672,7 +48679,7 @@ YYLTYPE yylloc; break; case 1985: -#line 14702 "gram.y" +#line 14709 "gram.y" { (yyval.typnam) = SystemTypeName("interval"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48680,52 +48687,52 @@ YYLTYPE yylloc; break; case 1986: -#line 14709 "gram.y" +#line 14716 "gram.y" { (yyval.boolean) = true; ;} break; case 1987: -#line 14710 "gram.y" +#line 14717 "gram.y" { (yyval.boolean) = false; ;} break; case 1988: -#line 14711 "gram.y" +#line 14718 "gram.y" { (yyval.boolean) = false; ;} break; case 1989: -#line 14716 "gram.y" +#line 14723 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR), (yylsp[(1) - (1)]))); ;} break; case 1990: -#line 14718 "gram.y" +#line 14725 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MONTH), (yylsp[(1) - (1)]))); ;} break; case 1991: -#line 14720 "gram.y" +#line 14727 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY), (yylsp[(1) - (1)]))); ;} break; case 1992: -#line 14722 "gram.y" +#line 14729 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR), (yylsp[(1) - (1)]))); ;} break; case 1993: -#line 14724 "gram.y" +#line 14731 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), (yylsp[(1) - (1)]))); ;} break; case 1994: -#line 14726 "gram.y" +#line 14733 "gram.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 1995: -#line 14728 "gram.y" +#line 14735 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH), (yylsp[(1) - (3)]))); @@ -48733,7 +48740,7 @@ YYLTYPE yylloc; break; case 1996: -#line 14733 "gram.y" +#line 14740 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR), (yylsp[(1) - (3)]))); @@ -48741,7 +48748,7 @@ YYLTYPE yylloc; break; case 1997: -#line 14738 "gram.y" +#line 14745 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -48750,7 +48757,7 @@ YYLTYPE yylloc; break; case 1998: -#line 14744 "gram.y" +#line 14751 "gram.y" { (yyval.list) = (yyvsp[(3) - (3)].list); linitial((yyval.list)) = makeIntConst(INTERVAL_MASK(DAY) | @@ -48761,7 +48768,7 @@ YYLTYPE yylloc; break; case 1999: -#line 14752 "gram.y" +#line 14759 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE), (yylsp[(1) - (3)]))); @@ -48769,7 +48776,7 @@ YYLTYPE yylloc; break; case 2000: -#line 14757 "gram.y" +#line 14764 "gram.y" { (yyval.list) = (yyvsp[(3) - (3)].list); linitial((yyval.list)) = makeIntConst(INTERVAL_MASK(HOUR) | @@ -48779,7 +48786,7 @@ YYLTYPE yylloc; break; case 2001: -#line 14764 "gram.y" +#line 14771 "gram.y" { (yyval.list) = (yyvsp[(3) - (3)].list); linitial((yyval.list)) = makeIntConst(INTERVAL_MASK(MINUTE) | @@ -48788,19 +48795,19 @@ YYLTYPE yylloc; break; case 2002: -#line 14770 "gram.y" +#line 14777 "gram.y" { (yyval.list) = NIL; ;} break; case 2003: -#line 14775 "gram.y" +#line 14782 "gram.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(SECOND), (yylsp[(1) - (1)]))); ;} break; case 2004: -#line 14779 "gram.y" +#line 14786 "gram.y" { (yyval.list) = list_make2(makeIntConst(INTERVAL_MASK(SECOND), (yylsp[(1) - (4)])), makeIntConst((yyvsp[(3) - (4)].ival), (yylsp[(3) - (4)]))); @@ -48808,7 +48815,7 @@ YYLTYPE yylloc; break; case 2005: -#line 14787 "gram.y" +#line 14794 "gram.y" { (yyval.typnam) = SystemTypeName("json"); (yyval.typnam)->location = (yylsp[(1) - (1)]); @@ -48816,17 +48823,17 @@ YYLTYPE yylloc; break; case 2006: -#line 14821 "gram.y" +#line 14828 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2007: -#line 14823 "gram.y" +#line 14830 "gram.y" { (yyval.node) = makeTypeCast((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].typnam), (yylsp[(2) - (3)])); ;} break; case 2008: -#line 14825 "gram.y" +#line 14832 "gram.y" { CollateClause *n = makeNode(CollateClause); @@ -48838,7 +48845,7 @@ YYLTYPE yylloc; break; case 2009: -#line 14834 "gram.y" +#line 14841 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("timezone"), list_make2((yyvsp[(5) - (5)].node), (yyvsp[(1) - (5)].node)), @@ -48848,7 +48855,7 @@ YYLTYPE yylloc; break; case 2010: -#line 14841 "gram.y" +#line 14848 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("timezone"), list_make1((yyvsp[(1) - (3)].node)), @@ -48858,107 +48865,107 @@ YYLTYPE yylloc; break; case 2011: -#line 14857 "gram.y" +#line 14864 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2012: -#line 14859 "gram.y" +#line 14866 "gram.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2013: -#line 14861 "gram.y" +#line 14868 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2014: -#line 14863 "gram.y" +#line 14870 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2015: -#line 14865 "gram.y" +#line 14872 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2016: -#line 14867 "gram.y" +#line 14874 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2017: -#line 14869 "gram.y" +#line 14876 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2018: -#line 14871 "gram.y" +#line 14878 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2019: -#line 14873 "gram.y" +#line 14880 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2020: -#line 14875 "gram.y" +#line 14882 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2021: -#line 14877 "gram.y" +#line 14884 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2022: -#line 14879 "gram.y" +#line 14886 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2023: -#line 14881 "gram.y" +#line 14888 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2024: -#line 14883 "gram.y" +#line 14890 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2025: -#line 14886 "gram.y" +#line 14893 "gram.y" { (yyval.node) = (Node *) makeA_Expr(AEXPR_OP, (yyvsp[(2) - (3)].list), (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2026: -#line 14888 "gram.y" +#line 14895 "gram.y" { (yyval.node) = (Node *) makeA_Expr(AEXPR_OP, (yyvsp[(1) - (2)].list), NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2027: -#line 14891 "gram.y" +#line 14898 "gram.y" { (yyval.node) = makeAndExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2028: -#line 14893 "gram.y" +#line 14900 "gram.y" { (yyval.node) = makeOrExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2029: -#line 14895 "gram.y" +#line 14902 "gram.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2030: -#line 14897 "gram.y" +#line 14904 "gram.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2031: -#line 14900 "gram.y" +#line 14907 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); @@ -48966,7 +48973,7 @@ YYLTYPE yylloc; break; case 2032: -#line 14905 "gram.y" +#line 14912 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), list_make2((yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)), @@ -48978,7 +48985,7 @@ YYLTYPE yylloc; break; case 2033: -#line 14914 "gram.y" +#line 14921 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~", (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node), (yylsp[(2) - (4)])); @@ -48986,7 +48993,7 @@ YYLTYPE yylloc; break; case 2034: -#line 14919 "gram.y" +#line 14926 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), list_make2((yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -48998,7 +49005,7 @@ YYLTYPE yylloc; break; case 2035: -#line 14928 "gram.y" +#line 14935 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); @@ -49006,7 +49013,7 @@ YYLTYPE yylloc; break; case 2036: -#line 14933 "gram.y" +#line 14940 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), list_make2((yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)), @@ -49018,7 +49025,7 @@ YYLTYPE yylloc; break; case 2037: -#line 14942 "gram.y" +#line 14949 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*", (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node), (yylsp[(2) - (4)])); @@ -49026,7 +49033,7 @@ YYLTYPE yylloc; break; case 2038: -#line 14947 "gram.y" +#line 14954 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), list_make2((yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -49038,7 +49045,7 @@ YYLTYPE yylloc; break; case 2039: -#line 14957 "gram.y" +#line 14964 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), list_make1((yyvsp[(4) - (4)].node)), @@ -49050,7 +49057,7 @@ YYLTYPE yylloc; break; case 2040: -#line 14966 "gram.y" +#line 14973 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), list_make2((yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -49062,7 +49069,7 @@ YYLTYPE yylloc; break; case 2041: -#line 14975 "gram.y" +#line 14982 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), list_make1((yyvsp[(5) - (5)].node)), @@ -49074,7 +49081,7 @@ YYLTYPE yylloc; break; case 2042: -#line 14984 "gram.y" +#line 14991 "gram.y" { FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), list_make2((yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)), @@ -49086,7 +49093,7 @@ YYLTYPE yylloc; break; case 2043: -#line 15003 "gram.y" +#line 15010 "gram.y" { NullTest *n = makeNode(NullTest); @@ -49098,7 +49105,7 @@ YYLTYPE yylloc; break; case 2044: -#line 15012 "gram.y" +#line 15019 "gram.y" { NullTest *n = makeNode(NullTest); @@ -49110,7 +49117,7 @@ YYLTYPE yylloc; break; case 2045: -#line 15021 "gram.y" +#line 15028 "gram.y" { NullTest *n = makeNode(NullTest); @@ -49122,7 +49129,7 @@ YYLTYPE yylloc; break; case 2046: -#line 15030 "gram.y" +#line 15037 "gram.y" { NullTest *n = makeNode(NullTest); @@ -49134,7 +49141,7 @@ YYLTYPE yylloc; break; case 2047: -#line 15039 "gram.y" +#line 15046 "gram.y" { if (list_length((yyvsp[(1) - (3)].list)) != 2) ereport(ERROR, @@ -49154,7 +49161,7 @@ YYLTYPE yylloc; break; case 2048: -#line 15056 "gram.y" +#line 15063 "gram.y" { BooleanTest *b = makeNode(BooleanTest); @@ -49166,7 +49173,7 @@ YYLTYPE yylloc; break; case 2049: -#line 15065 "gram.y" +#line 15072 "gram.y" { BooleanTest *b = makeNode(BooleanTest); @@ -49178,7 +49185,7 @@ YYLTYPE yylloc; break; case 2050: -#line 15074 "gram.y" +#line 15081 "gram.y" { BooleanTest *b = makeNode(BooleanTest); @@ -49190,7 +49197,7 @@ YYLTYPE yylloc; break; case 2051: -#line 15083 "gram.y" +#line 15090 "gram.y" { BooleanTest *b = makeNode(BooleanTest); @@ -49202,7 +49209,7 @@ YYLTYPE yylloc; break; case 2052: -#line 15092 "gram.y" +#line 15099 "gram.y" { BooleanTest *b = makeNode(BooleanTest); @@ -49214,7 +49221,7 @@ YYLTYPE yylloc; break; case 2053: -#line 15101 "gram.y" +#line 15108 "gram.y" { BooleanTest *b = makeNode(BooleanTest); @@ -49226,21 +49233,21 @@ YYLTYPE yylloc; break; case 2054: -#line 15110 "gram.y" +#line 15117 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yylsp[(2) - (5)])); ;} break; case 2055: -#line 15114 "gram.y" +#line 15121 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", (yyvsp[(1) - (6)].node), (yyvsp[(6) - (6)].node), (yylsp[(2) - (6)])); ;} break; case 2056: -#line 15118 "gram.y" +#line 15125 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN, "BETWEEN", @@ -49251,7 +49258,7 @@ YYLTYPE yylloc; break; case 2057: -#line 15126 "gram.y" +#line 15133 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN, "NOT BETWEEN", @@ -49262,7 +49269,7 @@ YYLTYPE yylloc; break; case 2058: -#line 15134 "gram.y" +#line 15141 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN_SYM, "BETWEEN SYMMETRIC", @@ -49273,7 +49280,7 @@ YYLTYPE yylloc; break; case 2059: -#line 15142 "gram.y" +#line 15149 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN_SYM, "NOT BETWEEN SYMMETRIC", @@ -49284,7 +49291,7 @@ YYLTYPE yylloc; break; case 2060: -#line 15150 "gram.y" +#line 15157 "gram.y" { /* in_expr returns a SubLink or a list of a_exprs */ if (IsA((yyvsp[(3) - (3)].node), SubLink)) @@ -49308,7 +49315,7 @@ YYLTYPE yylloc; break; case 2061: -#line 15171 "gram.y" +#line 15178 "gram.y" { /* in_expr returns a SubLink or a list of a_exprs */ if (IsA((yyvsp[(4) - (4)].node), SubLink)) @@ -49334,7 +49341,7 @@ YYLTYPE yylloc; break; case 2062: -#line 15194 "gram.y" +#line 15201 "gram.y" { SubLink *n = makeNode(SubLink); @@ -49349,7 +49356,7 @@ YYLTYPE yylloc; break; case 2063: -#line 15206 "gram.y" +#line 15213 "gram.y" { if ((yyvsp[(3) - (6)].ival) == ANY_SUBLINK) (yyval.node) = (Node *) makeA_Expr(AEXPR_OP_ANY, (yyvsp[(2) - (6)].list), (yyvsp[(1) - (6)].node), (yyvsp[(5) - (6)].node), (yylsp[(2) - (6)])); @@ -49359,7 +49366,7 @@ YYLTYPE yylloc; break; case 2064: -#line 15213 "gram.y" +#line 15220 "gram.y" { /* Not sure how to get rid of the parentheses * but there are lots of shift/reduce errors without them. @@ -49378,7 +49385,7 @@ YYLTYPE yylloc; break; case 2065: -#line 15229 "gram.y" +#line 15236 "gram.y" { (yyval.node) = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1((yyvsp[(1) - (3)].node)), (yylsp[(2) - (3)])); @@ -49386,7 +49393,7 @@ YYLTYPE yylloc; break; case 2066: -#line 15234 "gram.y" +#line 15241 "gram.y" { (yyval.node) = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1((yyvsp[(1) - (4)].node)), (yylsp[(2) - (4)])), @@ -49395,7 +49402,7 @@ YYLTYPE yylloc; break; case 2067: -#line 15240 "gram.y" +#line 15247 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("is_normalized"), list_make1((yyvsp[(1) - (3)].node)), @@ -49405,7 +49412,7 @@ YYLTYPE yylloc; break; case 2068: -#line 15247 "gram.y" +#line 15254 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("is_normalized"), list_make2((yyvsp[(1) - (4)].node), makeStringConst((yyvsp[(3) - (4)].str), (yylsp[(3) - (4)]))), @@ -49415,7 +49422,7 @@ YYLTYPE yylloc; break; case 2069: -#line 15254 "gram.y" +#line 15261 "gram.y" { (yyval.node) = makeNotExpr((Node *) makeFuncCall(SystemFuncName("is_normalized"), list_make1((yyvsp[(1) - (4)].node)), @@ -49426,7 +49433,7 @@ YYLTYPE yylloc; break; case 2070: -#line 15262 "gram.y" +#line 15269 "gram.y" { (yyval.node) = makeNotExpr((Node *) makeFuncCall(SystemFuncName("is_normalized"), list_make2((yyvsp[(1) - (5)].node), makeStringConst((yyvsp[(4) - (5)].str), (yylsp[(4) - (5)]))), @@ -49437,7 +49444,7 @@ YYLTYPE yylloc; break; case 2071: -#line 15271 "gram.y" +#line 15278 "gram.y" { JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); @@ -49446,7 +49453,7 @@ YYLTYPE yylloc; break; case 2072: -#line 15289 "gram.y" +#line 15296 "gram.y" { JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); @@ -49455,7 +49462,7 @@ YYLTYPE yylloc; break; case 2073: -#line 15306 "gram.y" +#line 15313 "gram.y" { /* * The SQL spec only allows DEFAULT in "contextually typed @@ -49473,111 +49480,111 @@ YYLTYPE yylloc; break; case 2074: -#line 15332 "gram.y" +#line 15339 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2075: -#line 15334 "gram.y" +#line 15341 "gram.y" { (yyval.node) = makeTypeCast((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].typnam), (yylsp[(2) - (3)])); ;} break; case 2076: -#line 15336 "gram.y" +#line 15343 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2077: -#line 15338 "gram.y" +#line 15345 "gram.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2078: -#line 15340 "gram.y" +#line 15347 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2079: -#line 15342 "gram.y" +#line 15349 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2080: -#line 15344 "gram.y" +#line 15351 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2081: -#line 15346 "gram.y" +#line 15353 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2082: -#line 15348 "gram.y" +#line 15355 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2083: -#line 15350 "gram.y" +#line 15357 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2084: -#line 15352 "gram.y" +#line 15359 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2085: -#line 15354 "gram.y" +#line 15361 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2086: -#line 15356 "gram.y" +#line 15363 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2087: -#line 15358 "gram.y" +#line 15365 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2088: -#line 15360 "gram.y" +#line 15367 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2089: -#line 15362 "gram.y" +#line 15369 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2090: -#line 15364 "gram.y" +#line 15371 "gram.y" { (yyval.node) = (Node *) makeA_Expr(AEXPR_OP, (yyvsp[(2) - (3)].list), (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; case 2091: -#line 15366 "gram.y" +#line 15373 "gram.y" { (yyval.node) = (Node *) makeA_Expr(AEXPR_OP, (yyvsp[(1) - (2)].list), NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2092: -#line 15368 "gram.y" +#line 15375 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yylsp[(2) - (5)])); ;} break; case 2093: -#line 15372 "gram.y" +#line 15379 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", (yyvsp[(1) - (6)].node), (yyvsp[(6) - (6)].node), (yylsp[(2) - (6)])); ;} break; case 2094: -#line 15376 "gram.y" +#line 15383 "gram.y" { (yyval.node) = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1((yyvsp[(1) - (3)].node)), (yylsp[(2) - (3)])); @@ -49585,7 +49592,7 @@ YYLTYPE yylloc; break; case 2095: -#line 15381 "gram.y" +#line 15388 "gram.y" { (yyval.node) = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1((yyvsp[(1) - (4)].node)), (yylsp[(2) - (4)])), @@ -49594,17 +49601,17 @@ YYLTYPE yylloc; break; case 2096: -#line 15396 "gram.y" +#line 15403 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2097: -#line 15397 "gram.y" +#line 15404 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2098: -#line 15399 "gram.y" +#line 15406 "gram.y" { ParamRef *p = makeNode(ParamRef); @@ -49624,7 +49631,7 @@ YYLTYPE yylloc; break; case 2099: -#line 15416 "gram.y" +#line 15423 "gram.y" { if ((yyvsp[(4) - (4)].list)) { @@ -49640,17 +49647,17 @@ YYLTYPE yylloc; break; case 2100: -#line 15429 "gram.y" +#line 15436 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2101: -#line 15431 "gram.y" +#line 15438 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2102: -#line 15433 "gram.y" +#line 15440 "gram.y" { SubLink *n = makeNode(SubLink); @@ -49665,7 +49672,7 @@ YYLTYPE yylloc; break; case 2103: -#line 15445 "gram.y" +#line 15452 "gram.y" { /* * Because the select_with_parens nonterminal is designed @@ -49693,7 +49700,7 @@ YYLTYPE yylloc; break; case 2104: -#line 15470 "gram.y" +#line 15477 "gram.y" { SubLink *n = makeNode(SubLink); @@ -49708,7 +49715,7 @@ YYLTYPE yylloc; break; case 2105: -#line 15482 "gram.y" +#line 15489 "gram.y" { SubLink *n = makeNode(SubLink); @@ -49723,7 +49730,7 @@ YYLTYPE yylloc; break; case 2106: -#line 15494 "gram.y" +#line 15501 "gram.y" { A_ArrayExpr *n = castNode(A_ArrayExpr, (yyvsp[(2) - (2)].node)); @@ -49734,7 +49741,7 @@ YYLTYPE yylloc; break; case 2107: -#line 15502 "gram.y" +#line 15509 "gram.y" { RowExpr *r = makeNode(RowExpr); @@ -49748,7 +49755,7 @@ YYLTYPE yylloc; break; case 2108: -#line 15513 "gram.y" +#line 15520 "gram.y" { RowExpr *r = makeNode(RowExpr); @@ -49762,7 +49769,7 @@ YYLTYPE yylloc; break; case 2109: -#line 15524 "gram.y" +#line 15531 "gram.y" { GroupingFunc *g = makeNode(GroupingFunc); @@ -49773,7 +49780,7 @@ YYLTYPE yylloc; break; case 2110: -#line 15534 "gram.y" +#line 15541 "gram.y" { (yyval.node) = (Node *) makeFuncCall((yyvsp[(1) - (3)].list), NIL, COERCE_EXPLICIT_CALL, @@ -49782,7 +49789,7 @@ YYLTYPE yylloc; break; case 2111: -#line 15540 "gram.y" +#line 15547 "gram.y" { FuncCall *n = makeFuncCall((yyvsp[(1) - (5)].list), (yyvsp[(3) - (5)].list), COERCE_EXPLICIT_CALL, @@ -49794,7 +49801,7 @@ YYLTYPE yylloc; break; case 2112: -#line 15549 "gram.y" +#line 15556 "gram.y" { FuncCall *n = makeFuncCall((yyvsp[(1) - (6)].list), list_make1((yyvsp[(4) - (6)].node)), COERCE_EXPLICIT_CALL, @@ -49807,7 +49814,7 @@ YYLTYPE yylloc; break; case 2113: -#line 15559 "gram.y" +#line 15566 "gram.y" { FuncCall *n = makeFuncCall((yyvsp[(1) - (8)].list), lappend((yyvsp[(3) - (8)].list), (yyvsp[(6) - (8)].node)), COERCE_EXPLICIT_CALL, @@ -49820,7 +49827,7 @@ YYLTYPE yylloc; break; case 2114: -#line 15569 "gram.y" +#line 15576 "gram.y" { FuncCall *n = makeFuncCall((yyvsp[(1) - (6)].list), (yyvsp[(4) - (6)].list), COERCE_EXPLICIT_CALL, @@ -49836,7 +49843,7 @@ YYLTYPE yylloc; break; case 2115: -#line 15582 "gram.y" +#line 15589 "gram.y" { FuncCall *n = makeFuncCall((yyvsp[(1) - (6)].list), (yyvsp[(4) - (6)].list), COERCE_EXPLICIT_CALL, @@ -49849,7 +49856,7 @@ YYLTYPE yylloc; break; case 2116: -#line 15592 "gram.y" +#line 15599 "gram.y" { /* * We consider AGGREGATE(*) to invoke a parameterless @@ -49871,7 +49878,7 @@ YYLTYPE yylloc; break; case 2117: -#line 15623 "gram.y" +#line 15630 "gram.y" { FuncCall *n = (FuncCall *) (yyvsp[(1) - (4)].node); @@ -49910,7 +49917,7 @@ YYLTYPE yylloc; break; case 2118: -#line 15659 "gram.y" +#line 15666 "gram.y" { JsonAggConstructor *n = IsA((yyvsp[(1) - (3)].node), JsonObjectAgg) ? ((JsonObjectAgg *) (yyvsp[(1) - (3)].node))->constructor : @@ -49923,27 +49930,27 @@ YYLTYPE yylloc; break; case 2119: -#line 15669 "gram.y" +#line 15676 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2120: -#line 15679 "gram.y" +#line 15686 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2121: -#line 15680 "gram.y" +#line 15687 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2122: -#line 15681 "gram.y" +#line 15688 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2123: -#line 15689 "gram.y" +#line 15696 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("pg_collation_for"), list_make1((yyvsp[(4) - (5)].node)), @@ -49953,91 +49960,91 @@ YYLTYPE yylloc; break; case 2124: -#line 15696 "gram.y" +#line 15703 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, (yylsp[(1) - (1)])); ;} break; case 2125: -#line 15700 "gram.y" +#line 15707 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, (yylsp[(1) - (1)])); ;} break; case 2126: -#line 15704 "gram.y" +#line 15711 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, (yyvsp[(3) - (4)].ival), (yylsp[(1) - (4)])); ;} break; case 2127: -#line 15708 "gram.y" +#line 15715 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, (yylsp[(1) - (1)])); ;} break; case 2128: -#line 15712 "gram.y" +#line 15719 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, (yyvsp[(3) - (4)].ival), (yylsp[(1) - (4)])); ;} break; case 2129: -#line 15716 "gram.y" +#line 15723 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_LOCALTIME, -1, (yylsp[(1) - (1)])); ;} break; case 2130: -#line 15720 "gram.y" +#line 15727 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_LOCALTIME_N, (yyvsp[(3) - (4)].ival), (yylsp[(1) - (4)])); ;} break; case 2131: -#line 15724 "gram.y" +#line 15731 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, (yylsp[(1) - (1)])); ;} break; case 2132: -#line 15728 "gram.y" +#line 15735 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, (yyvsp[(3) - (4)].ival), (yylsp[(1) - (4)])); ;} break; case 2133: -#line 15732 "gram.y" +#line 15739 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, (yylsp[(1) - (1)])); ;} break; case 2134: -#line 15736 "gram.y" +#line 15743 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, (yylsp[(1) - (1)])); ;} break; case 2135: -#line 15740 "gram.y" +#line 15747 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_SESSION_USER, -1, (yylsp[(1) - (1)])); ;} break; case 2136: -#line 15744 "gram.y" +#line 15751 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("system_user"), NIL, @@ -50047,33 +50054,33 @@ YYLTYPE yylloc; break; case 2137: -#line 15751 "gram.y" +#line 15758 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_USER, -1, (yylsp[(1) - (1)])); ;} break; case 2138: -#line 15755 "gram.y" +#line 15762 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, (yylsp[(1) - (1)])); ;} break; case 2139: -#line 15759 "gram.y" +#line 15766 "gram.y" { (yyval.node) = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, (yylsp[(1) - (1)])); ;} break; case 2140: -#line 15763 "gram.y" +#line 15770 "gram.y" { (yyval.node) = makeTypeCast((yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].typnam), (yylsp[(1) - (6)])); ;} break; case 2141: -#line 15765 "gram.y" +#line 15772 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("extract"), (yyvsp[(3) - (4)].list), @@ -50083,7 +50090,7 @@ YYLTYPE yylloc; break; case 2142: -#line 15772 "gram.y" +#line 15779 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("normalize"), list_make1((yyvsp[(3) - (4)].node)), @@ -50093,7 +50100,7 @@ YYLTYPE yylloc; break; case 2143: -#line 15779 "gram.y" +#line 15786 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("normalize"), list_make2((yyvsp[(3) - (6)].node), makeStringConst((yyvsp[(5) - (6)].str), (yylsp[(5) - (6)]))), @@ -50103,7 +50110,7 @@ YYLTYPE yylloc; break; case 2144: -#line 15786 "gram.y" +#line 15793 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("overlay"), (yyvsp[(3) - (4)].list), @@ -50113,7 +50120,7 @@ YYLTYPE yylloc; break; case 2145: -#line 15793 "gram.y" +#line 15800 "gram.y" { /* * allow functions named overlay() to be called without @@ -50127,7 +50134,7 @@ YYLTYPE yylloc; break; case 2146: -#line 15804 "gram.y" +#line 15811 "gram.y" { /* * position(A in B) is converted to position(B, A) @@ -50144,7 +50151,7 @@ YYLTYPE yylloc; break; case 2147: -#line 15818 "gram.y" +#line 15825 "gram.y" { /* substring(A from B for C) is converted to * substring(A, B, C) - thomas 2000-11-28 @@ -50157,7 +50164,7 @@ YYLTYPE yylloc; break; case 2148: -#line 15828 "gram.y" +#line 15835 "gram.y" { /* * allow functions named substring() to be called without @@ -50171,7 +50178,7 @@ YYLTYPE yylloc; break; case 2149: -#line 15839 "gram.y" +#line 15846 "gram.y" { /* TREAT(expr AS target) converts expr of a particular type to target, * which is defined to be a subtype of the original expression. @@ -50190,7 +50197,7 @@ YYLTYPE yylloc; break; case 2150: -#line 15855 "gram.y" +#line 15862 "gram.y" { /* various trim expressions are defined in SQL * - thomas 1997-07-19 @@ -50203,7 +50210,7 @@ YYLTYPE yylloc; break; case 2151: -#line 15865 "gram.y" +#line 15872 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("ltrim"), (yyvsp[(4) - (5)].list), @@ -50213,7 +50220,7 @@ YYLTYPE yylloc; break; case 2152: -#line 15872 "gram.y" +#line 15879 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("rtrim"), (yyvsp[(4) - (5)].list), @@ -50223,7 +50230,7 @@ YYLTYPE yylloc; break; case 2153: -#line 15879 "gram.y" +#line 15886 "gram.y" { (yyval.node) = (Node *) makeFuncCall(SystemFuncName("btrim"), (yyvsp[(3) - (4)].list), @@ -50233,14 +50240,14 @@ YYLTYPE yylloc; break; case 2154: -#line 15886 "gram.y" +#line 15893 "gram.y" { (yyval.node) = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node), (yylsp[(1) - (6)])); ;} break; case 2155: -#line 15890 "gram.y" +#line 15897 "gram.y" { CoalesceExpr *c = makeNode(CoalesceExpr); @@ -50251,7 +50258,7 @@ YYLTYPE yylloc; break; case 2156: -#line 15898 "gram.y" +#line 15905 "gram.y" { MinMaxExpr *v = makeNode(MinMaxExpr); @@ -50263,7 +50270,7 @@ YYLTYPE yylloc; break; case 2157: -#line 15907 "gram.y" +#line 15914 "gram.y" { MinMaxExpr *v = makeNode(MinMaxExpr); @@ -50275,42 +50282,42 @@ YYLTYPE yylloc; break; case 2158: -#line 15916 "gram.y" +#line 15923 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; case 2159: -#line 15920 "gram.y" +#line 15927 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLELEMENT, (yyvsp[(4) - (5)].str), NIL, NIL, (yylsp[(1) - (5)])); ;} break; case 2160: -#line 15924 "gram.y" +#line 15931 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLELEMENT, (yyvsp[(4) - (7)].str), (yyvsp[(6) - (7)].list), NIL, (yylsp[(1) - (7)])); ;} break; case 2161: -#line 15928 "gram.y" +#line 15935 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLELEMENT, (yyvsp[(4) - (7)].str), NIL, (yyvsp[(6) - (7)].list), (yylsp[(1) - (7)])); ;} break; case 2162: -#line 15932 "gram.y" +#line 15939 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLELEMENT, (yyvsp[(4) - (9)].str), (yyvsp[(6) - (9)].list), (yyvsp[(8) - (9)].list), (yylsp[(1) - (9)])); ;} break; case 2163: -#line 15936 "gram.y" +#line 15943 "gram.y" { /* xmlexists(A PASSING [BY REF] B [BY REF]) is * converted to xmlexists(A, B)*/ @@ -50322,14 +50329,14 @@ YYLTYPE yylloc; break; case 2164: -#line 15945 "gram.y" +#line 15952 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLFOREST, NULL, (yyvsp[(3) - (4)].list), NIL, (yylsp[(1) - (4)])); ;} break; case 2165: -#line 15949 "gram.y" +#line 15956 "gram.y" { XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL, @@ -50342,21 +50349,21 @@ YYLTYPE yylloc; break; case 2166: -#line 15959 "gram.y" +#line 15966 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLPI, (yyvsp[(4) - (5)].str), NULL, NIL, (yylsp[(1) - (5)])); ;} break; case 2167: -#line 15963 "gram.y" +#line 15970 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLPI, (yyvsp[(4) - (7)].str), NULL, list_make1((yyvsp[(6) - (7)].node)), (yylsp[(1) - (7)])); ;} break; case 2168: -#line 15967 "gram.y" +#line 15974 "gram.y" { (yyval.node) = makeXmlExpr(IS_XMLROOT, NULL, NIL, list_make3((yyvsp[(3) - (7)].node), (yyvsp[(5) - (7)].node), (yyvsp[(6) - (7)].node)), (yylsp[(1) - (7)])); @@ -50364,7 +50371,7 @@ YYLTYPE yylloc; break; case 2169: -#line 15972 "gram.y" +#line 15979 "gram.y" { XmlSerialize *n = makeNode(XmlSerialize); @@ -50378,7 +50385,7 @@ YYLTYPE yylloc; break; case 2170: -#line 15983 "gram.y" +#line 15990 "gram.y" { /* Support for legacy (non-standard) json_object() */ (yyval.node) = (Node *) makeFuncCall(SystemFuncName("json_object"), @@ -50387,7 +50394,7 @@ YYLTYPE yylloc; break; case 2171: -#line 15992 "gram.y" +#line 15999 "gram.y" { JsonObjectConstructor *n = makeNode(JsonObjectConstructor); @@ -50401,7 +50408,7 @@ YYLTYPE yylloc; break; case 2172: -#line 16003 "gram.y" +#line 16010 "gram.y" { JsonObjectConstructor *n = makeNode(JsonObjectConstructor); @@ -50415,7 +50422,7 @@ YYLTYPE yylloc; break; case 2173: -#line 16018 "gram.y" +#line 16025 "gram.y" { JsonArrayConstructor *n = makeNode(JsonArrayConstructor); @@ -50428,7 +50435,7 @@ YYLTYPE yylloc; break; case 2174: -#line 16033 "gram.y" +#line 16040 "gram.y" { JsonArrayQueryConstructor *n = makeNode(JsonArrayQueryConstructor); @@ -50442,7 +50449,7 @@ YYLTYPE yylloc; break; case 2175: -#line 16046 "gram.y" +#line 16053 "gram.y" { JsonArrayConstructor *n = makeNode(JsonArrayConstructor); @@ -50455,7 +50462,7 @@ YYLTYPE yylloc; break; case 2176: -#line 16056 "gram.y" +#line 16063 "gram.y" { JsonParseExpr *n = makeNode(JsonParseExpr); @@ -50468,7 +50475,7 @@ YYLTYPE yylloc; break; case 2177: -#line 16066 "gram.y" +#line 16073 "gram.y" { JsonScalarExpr *n = makeNode(JsonScalarExpr); @@ -50480,7 +50487,7 @@ YYLTYPE yylloc; break; case 2178: -#line 16075 "gram.y" +#line 16082 "gram.y" { JsonSerializeExpr *n = makeNode(JsonSerializeExpr); @@ -50492,7 +50499,7 @@ YYLTYPE yylloc; break; case 2179: -#line 16084 "gram.y" +#line 16091 "gram.y" { MergeSupportFunc *m = makeNode(MergeSupportFunc); @@ -50503,7 +50510,7 @@ YYLTYPE yylloc; break; case 2180: -#line 16098 "gram.y" +#line 16105 "gram.y" { JsonFuncExpr *n = makeNode(JsonFuncExpr); @@ -50522,7 +50529,7 @@ YYLTYPE yylloc; break; case 2181: -#line 16117 "gram.y" +#line 16124 "gram.y" { JsonFuncExpr *n = makeNode(JsonFuncExpr); @@ -50538,7 +50545,7 @@ YYLTYPE yylloc; break; case 2182: -#line 16134 "gram.y" +#line 16141 "gram.y" { JsonFuncExpr *n = makeNode(JsonFuncExpr); @@ -50555,52 +50562,52 @@ YYLTYPE yylloc; break; case 2183: -#line 16154 "gram.y" +#line 16161 "gram.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 2184: -#line 16156 "gram.y" +#line 16163 "gram.y" { (yyval.node) = makeNullAConst(-1); ;} break; case 2185: -#line 16160 "gram.y" +#line 16167 "gram.y" { (yyval.node) = makeIntConst(XML_STANDALONE_YES, -1); ;} break; case 2186: -#line 16162 "gram.y" +#line 16169 "gram.y" { (yyval.node) = makeIntConst(XML_STANDALONE_NO, -1); ;} break; case 2187: -#line 16164 "gram.y" +#line 16171 "gram.y" { (yyval.node) = makeIntConst(XML_STANDALONE_NO_VALUE, -1); ;} break; case 2188: -#line 16166 "gram.y" +#line 16173 "gram.y" { (yyval.node) = makeIntConst(XML_STANDALONE_OMITTED, -1); ;} break; case 2189: -#line 16169 "gram.y" +#line 16176 "gram.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; case 2190: -#line 16172 "gram.y" +#line 16179 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].target)); ;} break; case 2191: -#line 16173 "gram.y" +#line 16180 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].target)); ;} break; case 2192: -#line 16177 "gram.y" +#line 16184 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = (yyvsp[(3) - (3)].str); @@ -50611,7 +50618,7 @@ YYLTYPE yylloc; break; case 2193: -#line 16185 "gram.y" +#line 16192 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = NULL; @@ -50622,115 +50629,115 @@ YYLTYPE yylloc; break; case 2194: -#line 16194 "gram.y" +#line 16201 "gram.y" { (yyval.ival) = XMLOPTION_DOCUMENT; ;} break; case 2195: -#line 16195 "gram.y" +#line 16202 "gram.y" { (yyval.ival) = XMLOPTION_CONTENT; ;} break; case 2196: -#line 16198 "gram.y" +#line 16205 "gram.y" { (yyval.boolean) = true; ;} break; case 2197: -#line 16199 "gram.y" +#line 16206 "gram.y" { (yyval.boolean) = false; ;} break; case 2198: -#line 16200 "gram.y" +#line 16207 "gram.y" { (yyval.boolean) = false; ;} break; case 2199: -#line 16203 "gram.y" +#line 16210 "gram.y" { (yyval.boolean) = true; ;} break; case 2200: -#line 16204 "gram.y" +#line 16211 "gram.y" { (yyval.boolean) = false; ;} break; case 2201: -#line 16205 "gram.y" +#line 16212 "gram.y" { (yyval.boolean) = false; ;} break; case 2202: -#line 16211 "gram.y" +#line 16218 "gram.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 2203: -#line 16215 "gram.y" +#line 16222 "gram.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; case 2204: -#line 16219 "gram.y" +#line 16226 "gram.y" { (yyval.node) = (yyvsp[(3) - (3)].node); ;} break; case 2205: -#line 16223 "gram.y" +#line 16230 "gram.y" { (yyval.node) = (yyvsp[(3) - (4)].node); ;} break; case 2208: -#line 16238 "gram.y" +#line 16245 "gram.y" { (yyval.list) = (yyvsp[(4) - (5)].list); ;} break; case 2209: -#line 16239 "gram.y" +#line 16246 "gram.y" { (yyval.list) = NIL; ;} break; case 2210: -#line 16243 "gram.y" +#line 16250 "gram.y" { (yyval.node) = (yyvsp[(4) - (5)].node); ;} break; case 2211: -#line 16244 "gram.y" +#line 16251 "gram.y" { (yyval.node) = NULL; ;} break; case 2212: -#line 16252 "gram.y" +#line 16259 "gram.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; case 2213: -#line 16253 "gram.y" +#line 16260 "gram.y" { (yyval.list) = NIL; ;} break; case 2214: -#line 16257 "gram.y" +#line 16264 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].windef)); ;} break; case 2215: -#line 16259 "gram.y" +#line 16266 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].windef)); ;} break; case 2216: -#line 16264 "gram.y" +#line 16271 "gram.y" { WindowDef *n = (yyvsp[(3) - (3)].windef); @@ -50740,12 +50747,12 @@ YYLTYPE yylloc; break; case 2217: -#line 16273 "gram.y" +#line 16280 "gram.y" { (yyval.windef) = (yyvsp[(2) - (2)].windef); ;} break; case 2218: -#line 16275 "gram.y" +#line 16282 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50762,12 +50769,12 @@ YYLTYPE yylloc; break; case 2219: -#line 16289 "gram.y" +#line 16296 "gram.y" { (yyval.windef) = NULL; ;} break; case 2220: -#line 16294 "gram.y" +#line 16301 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50785,27 +50792,27 @@ YYLTYPE yylloc; break; case 2221: -#line 16320 "gram.y" +#line 16327 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2222: -#line 16321 "gram.y" +#line 16328 "gram.y" { (yyval.str) = NULL; ;} break; case 2223: -#line 16324 "gram.y" +#line 16331 "gram.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; case 2224: -#line 16325 "gram.y" +#line 16332 "gram.y" { (yyval.list) = NIL; ;} break; case 2225: -#line 16334 "gram.y" +#line 16341 "gram.y" { WindowDef *n = (yyvsp[(2) - (3)].windef); @@ -50816,7 +50823,7 @@ YYLTYPE yylloc; break; case 2226: -#line 16342 "gram.y" +#line 16349 "gram.y" { WindowDef *n = (yyvsp[(2) - (3)].windef); @@ -50827,7 +50834,7 @@ YYLTYPE yylloc; break; case 2227: -#line 16350 "gram.y" +#line 16357 "gram.y" { WindowDef *n = (yyvsp[(2) - (3)].windef); @@ -50838,7 +50845,7 @@ YYLTYPE yylloc; break; case 2228: -#line 16358 "gram.y" +#line 16365 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50850,7 +50857,7 @@ YYLTYPE yylloc; break; case 2229: -#line 16369 "gram.y" +#line 16376 "gram.y" { WindowDef *n = (yyvsp[(1) - (1)].windef); @@ -50871,7 +50878,7 @@ YYLTYPE yylloc; break; case 2230: -#line 16387 "gram.y" +#line 16394 "gram.y" { WindowDef *n1 = (yyvsp[(2) - (4)].windef); WindowDef *n2 = (yyvsp[(4) - (4)].windef); @@ -50912,7 +50919,7 @@ YYLTYPE yylloc; break; case 2231: -#line 16433 "gram.y" +#line 16440 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50924,7 +50931,7 @@ YYLTYPE yylloc; break; case 2232: -#line 16442 "gram.y" +#line 16449 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50936,7 +50943,7 @@ YYLTYPE yylloc; break; case 2233: -#line 16451 "gram.y" +#line 16458 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50948,7 +50955,7 @@ YYLTYPE yylloc; break; case 2234: -#line 16460 "gram.y" +#line 16467 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50960,7 +50967,7 @@ YYLTYPE yylloc; break; case 2235: -#line 16469 "gram.y" +#line 16476 "gram.y" { WindowDef *n = makeNode(WindowDef); @@ -50972,232 +50979,232 @@ YYLTYPE yylloc; break; case 2236: -#line 16480 "gram.y" +#line 16487 "gram.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_CURRENT_ROW; ;} break; case 2237: -#line 16481 "gram.y" +#line 16488 "gram.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_GROUP; ;} break; case 2238: -#line 16482 "gram.y" +#line 16489 "gram.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_TIES; ;} break; case 2239: -#line 16483 "gram.y" +#line 16490 "gram.y" { (yyval.ival) = 0; ;} break; case 2240: -#line 16484 "gram.y" +#line 16491 "gram.y" { (yyval.ival) = 0; ;} break; case 2241: -#line 16498 "gram.y" +#line 16505 "gram.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; case 2242: -#line 16499 "gram.y" +#line 16506 "gram.y" { (yyval.list) = NIL; ;} break; case 2243: -#line 16500 "gram.y" +#line 16507 "gram.y" { (yyval.list) = lappend((yyvsp[(2) - (5)].list), (yyvsp[(4) - (5)].node)); ;} break; case 2244: -#line 16503 "gram.y" +#line 16510 "gram.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; case 2245: -#line 16504 "gram.y" +#line 16511 "gram.y" { (yyval.list) = NIL; ;} break; case 2246: -#line 16507 "gram.y" +#line 16514 "gram.y" { (yyval.list) = lappend((yyvsp[(2) - (5)].list), (yyvsp[(4) - (5)].node)); ;} break; case 2247: -#line 16510 "gram.y" +#line 16517 "gram.y" { (yyval.ival) = ANY_SUBLINK; ;} break; case 2248: -#line 16511 "gram.y" +#line 16518 "gram.y" { (yyval.ival) = ANY_SUBLINK; ;} break; case 2249: -#line 16512 "gram.y" +#line 16519 "gram.y" { (yyval.ival) = ALL_SUBLINK; ;} break; case 2250: -#line 16515 "gram.y" +#line 16522 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2251: -#line 16516 "gram.y" +#line 16523 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2252: -#line 16519 "gram.y" +#line 16526 "gram.y" { (yyval.str) = "+"; ;} break; case 2253: -#line 16520 "gram.y" +#line 16527 "gram.y" { (yyval.str) = "-"; ;} break; case 2254: -#line 16521 "gram.y" +#line 16528 "gram.y" { (yyval.str) = "*"; ;} break; case 2255: -#line 16522 "gram.y" +#line 16529 "gram.y" { (yyval.str) = "/"; ;} break; case 2256: -#line 16523 "gram.y" +#line 16530 "gram.y" { (yyval.str) = "%"; ;} break; case 2257: -#line 16524 "gram.y" +#line 16531 "gram.y" { (yyval.str) = "^"; ;} break; case 2258: -#line 16525 "gram.y" +#line 16532 "gram.y" { (yyval.str) = "<"; ;} break; case 2259: -#line 16526 "gram.y" +#line 16533 "gram.y" { (yyval.str) = ">"; ;} break; case 2260: -#line 16527 "gram.y" +#line 16534 "gram.y" { (yyval.str) = "="; ;} break; case 2261: -#line 16528 "gram.y" +#line 16535 "gram.y" { (yyval.str) = "<="; ;} break; case 2262: -#line 16529 "gram.y" +#line 16536 "gram.y" { (yyval.str) = ">="; ;} break; case 2263: -#line 16530 "gram.y" +#line 16537 "gram.y" { (yyval.str) = "<>"; ;} break; case 2264: -#line 16534 "gram.y" +#line 16541 "gram.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; case 2265: -#line 16536 "gram.y" +#line 16543 "gram.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; case 2266: -#line 16541 "gram.y" +#line 16548 "gram.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; case 2267: -#line 16543 "gram.y" +#line 16550 "gram.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; case 2268: -#line 16548 "gram.y" +#line 16555 "gram.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; case 2269: -#line 16550 "gram.y" +#line 16557 "gram.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; case 2270: -#line 16552 "gram.y" +#line 16559 "gram.y" { (yyval.list) = list_make1(makeString("~~")); ;} break; case 2271: -#line 16554 "gram.y" +#line 16561 "gram.y" { (yyval.list) = list_make1(makeString("!~~")); ;} break; case 2272: -#line 16556 "gram.y" +#line 16563 "gram.y" { (yyval.list) = list_make1(makeString("~~*")); ;} break; case 2273: -#line 16558 "gram.y" +#line 16565 "gram.y" { (yyval.list) = list_make1(makeString("!~~*")); ;} break; case 2274: -#line 16570 "gram.y" +#line 16577 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2275: -#line 16574 "gram.y" +#line 16581 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 2276: -#line 16581 "gram.y" +#line 16588 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2277: -#line 16585 "gram.y" +#line 16592 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 2278: -#line 16591 "gram.y" +#line 16598 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2279: -#line 16595 "gram.y" +#line 16602 "gram.y" { NamedArgExpr *na = makeNode(NamedArgExpr); @@ -51210,7 +51217,7 @@ YYLTYPE yylloc; break; case 2280: -#line 16605 "gram.y" +#line 16612 "gram.y" { NamedArgExpr *na = makeNode(NamedArgExpr); @@ -51223,132 +51230,132 @@ YYLTYPE yylloc; break; case 2281: -#line 16616 "gram.y" +#line 16623 "gram.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 2282: -#line 16617 "gram.y" +#line 16624 "gram.y" { (yyval.list) = NIL; ;} break; case 2283: -#line 16620 "gram.y" +#line 16627 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].typnam)); ;} break; case 2284: -#line 16621 "gram.y" +#line 16628 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].typnam)); ;} break; case 2285: -#line 16625 "gram.y" +#line 16632 "gram.y" { (yyval.node) = makeAArrayExpr((yyvsp[(2) - (3)].list), (yylsp[(1) - (3)])); ;} break; case 2286: -#line 16629 "gram.y" +#line 16636 "gram.y" { (yyval.node) = makeAArrayExpr((yyvsp[(2) - (3)].list), (yylsp[(1) - (3)])); ;} break; case 2287: -#line 16633 "gram.y" +#line 16640 "gram.y" { (yyval.node) = makeAArrayExpr(NIL, (yylsp[(1) - (2)])); ;} break; case 2288: -#line 16638 "gram.y" +#line 16645 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2289: -#line 16639 "gram.y" +#line 16646 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 2290: -#line 16645 "gram.y" +#line 16652 "gram.y" { (yyval.list) = list_make2(makeStringConst((yyvsp[(1) - (3)].str), (yylsp[(1) - (3)])), (yyvsp[(3) - (3)].node)); ;} break; case 2291: -#line 16649 "gram.y" +#line 16656 "gram.y" { (yyval.list) = list_make2(makeParamRef((yyvsp[(1) - (3)].ival), (yylsp[(1) - (3)])), (yyvsp[(3) - (3)].node)); ;} break; case 2292: -#line 16658 "gram.y" +#line 16665 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2293: -#line 16659 "gram.y" +#line 16666 "gram.y" { (yyval.str) = "year"; ;} break; case 2294: -#line 16660 "gram.y" +#line 16667 "gram.y" { (yyval.str) = "month"; ;} break; case 2295: -#line 16661 "gram.y" +#line 16668 "gram.y" { (yyval.str) = "day"; ;} break; case 2296: -#line 16662 "gram.y" +#line 16669 "gram.y" { (yyval.str) = "hour"; ;} break; case 2297: -#line 16663 "gram.y" +#line 16670 "gram.y" { (yyval.str) = "minute"; ;} break; case 2298: -#line 16664 "gram.y" +#line 16671 "gram.y" { (yyval.str) = "second"; ;} break; case 2299: -#line 16665 "gram.y" +#line 16672 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2300: -#line 16669 "gram.y" +#line 16676 "gram.y" { (yyval.str) = "NFC"; ;} break; case 2301: -#line 16670 "gram.y" +#line 16677 "gram.y" { (yyval.str) = "NFD"; ;} break; case 2302: -#line 16671 "gram.y" +#line 16678 "gram.y" { (yyval.str) = "NFKC"; ;} break; case 2303: -#line 16672 "gram.y" +#line 16679 "gram.y" { (yyval.str) = "NFKD"; ;} break; case 2304: -#line 16678 "gram.y" +#line 16685 "gram.y" { /* overlay(A PLACING B FROM C FOR D) is converted to overlay(A, B, C, D) */ (yyval.list) = list_make4((yyvsp[(1) - (7)].node), (yyvsp[(3) - (7)].node), (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)); @@ -51356,7 +51363,7 @@ YYLTYPE yylloc; break; case 2305: -#line 16683 "gram.y" +#line 16690 "gram.y" { /* overlay(A PLACING B FROM C) is converted to overlay(A, B, C) */ (yyval.list) = list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); @@ -51364,19 +51371,19 @@ YYLTYPE yylloc; break; case 2306: -#line 16691 "gram.y" +#line 16698 "gram.y" { (yyval.list) = list_make2((yyvsp[(3) - (3)].node), (yyvsp[(1) - (3)].node)); ;} break; case 2307: -#line 16713 "gram.y" +#line 16720 "gram.y" { (yyval.list) = list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); ;} break; case 2308: -#line 16717 "gram.y" +#line 16724 "gram.y" { /* not legal per SQL, but might as well allow it */ (yyval.list) = list_make3((yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yyvsp[(3) - (5)].node)); @@ -51384,7 +51391,7 @@ YYLTYPE yylloc; break; case 2309: -#line 16722 "gram.y" +#line 16729 "gram.y" { /* * Because we aren't restricting data types here, this @@ -51398,7 +51405,7 @@ YYLTYPE yylloc; break; case 2310: -#line 16733 "gram.y" +#line 16740 "gram.y" { /* not legal per SQL */ @@ -51418,29 +51425,29 @@ YYLTYPE yylloc; break; case 2311: -#line 16750 "gram.y" +#line 16757 "gram.y" { (yyval.list) = list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); ;} break; case 2312: -#line 16755 "gram.y" +#line 16762 "gram.y" { (yyval.list) = lappend((yyvsp[(3) - (3)].list), (yyvsp[(1) - (3)].node)); ;} break; case 2313: -#line 16756 "gram.y" +#line 16763 "gram.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; case 2314: -#line 16757 "gram.y" +#line 16764 "gram.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 2315: -#line 16761 "gram.y" +#line 16768 "gram.y" { SubLink *n = makeNode(SubLink); @@ -51451,12 +51458,12 @@ YYLTYPE yylloc; break; case 2316: -#line 16768 "gram.y" +#line 16775 "gram.y" { (yyval.node) = (Node *) (yyvsp[(2) - (3)].list); ;} break; case 2317: -#line 16779 "gram.y" +#line 16786 "gram.y" { CaseExpr *c = makeNode(CaseExpr); @@ -51470,17 +51477,17 @@ YYLTYPE yylloc; break; case 2318: -#line 16793 "gram.y" +#line 16800 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2319: -#line 16794 "gram.y" +#line 16801 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; case 2320: -#line 16799 "gram.y" +#line 16806 "gram.y" { CaseWhen *w = makeNode(CaseWhen); @@ -51492,55 +51499,55 @@ YYLTYPE yylloc; break; case 2321: -#line 16810 "gram.y" +#line 16817 "gram.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 2322: -#line 16811 "gram.y" +#line 16818 "gram.y" { (yyval.node) = NULL; ;} break; case 2323: -#line 16814 "gram.y" +#line 16821 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2324: -#line 16815 "gram.y" +#line 16822 "gram.y" { (yyval.node) = NULL; ;} break; case 2325: -#line 16819 "gram.y" +#line 16826 "gram.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; case 2326: -#line 16823 "gram.y" +#line 16830 "gram.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].list), (yylsp[(1) - (2)]), yyscanner); ;} break; case 2327: -#line 16830 "gram.y" +#line 16837 "gram.y" { (yyval.node) = (Node *) makeString((yyvsp[(2) - (2)].str)); ;} break; case 2328: -#line 16834 "gram.y" +#line 16841 "gram.y" { (yyval.node) = (Node *) makeNode(A_Star); ;} break; case 2329: -#line 16838 "gram.y" +#line 16845 "gram.y" { A_Indices *ai = makeNode(A_Indices); @@ -51552,7 +51559,7 @@ YYLTYPE yylloc; break; case 2330: -#line 16847 "gram.y" +#line 16854 "gram.y" { A_Indices *ai = makeNode(A_Indices); @@ -51564,57 +51571,57 @@ YYLTYPE yylloc; break; case 2331: -#line 16858 "gram.y" +#line 16865 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2332: -#line 16859 "gram.y" +#line 16866 "gram.y" { (yyval.node) = NULL; ;} break; case 2333: -#line 16863 "gram.y" +#line 16870 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2334: -#line 16864 "gram.y" +#line 16871 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; case 2335: -#line 16868 "gram.y" +#line 16875 "gram.y" { (yyval.list) = NIL; ;} break; case 2336: -#line 16869 "gram.y" +#line 16876 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; case 2339: -#line 16878 "gram.y" +#line 16885 "gram.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; case 2340: -#line 16879 "gram.y" +#line 16886 "gram.y" { (yyval.list) = NIL; ;} break; case 2341: -#line 16883 "gram.y" +#line 16890 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2342: -#line 16884 "gram.y" +#line 16891 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 2343: -#line 16889 "gram.y" +#line 16896 "gram.y" { JsonArgument *n = makeNode(JsonArgument); @@ -51625,132 +51632,132 @@ YYLTYPE yylloc; break; case 2344: -#line 16900 "gram.y" +#line 16907 "gram.y" { (yyval.ival) = JSW_NONE; ;} break; case 2345: -#line 16901 "gram.y" +#line 16908 "gram.y" { (yyval.ival) = JSW_NONE; ;} break; case 2346: -#line 16902 "gram.y" +#line 16909 "gram.y" { (yyval.ival) = JSW_UNCONDITIONAL; ;} break; case 2347: -#line 16903 "gram.y" +#line 16910 "gram.y" { (yyval.ival) = JSW_UNCONDITIONAL; ;} break; case 2348: -#line 16904 "gram.y" +#line 16911 "gram.y" { (yyval.ival) = JSW_CONDITIONAL; ;} break; case 2349: -#line 16905 "gram.y" +#line 16912 "gram.y" { (yyval.ival) = JSW_UNCONDITIONAL; ;} break; case 2350: -#line 16906 "gram.y" +#line 16913 "gram.y" { (yyval.ival) = JSW_CONDITIONAL; ;} break; case 2351: -#line 16907 "gram.y" +#line 16914 "gram.y" { (yyval.ival) = JSW_UNCONDITIONAL; ;} break; case 2352: -#line 16908 "gram.y" +#line 16915 "gram.y" { (yyval.ival) = JSW_UNSPEC; ;} break; case 2353: -#line 16913 "gram.y" +#line 16920 "gram.y" { (yyval.node) = (Node *) makeJsonBehavior(JSON_BEHAVIOR_DEFAULT, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 2354: -#line 16915 "gram.y" +#line 16922 "gram.y" { (yyval.node) = (Node *) makeJsonBehavior((yyvsp[(1) - (1)].ival), NULL, (yylsp[(1) - (1)])); ;} break; case 2355: -#line 16919 "gram.y" +#line 16926 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_ERROR; ;} break; case 2356: -#line 16920 "gram.y" +#line 16927 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_NULL; ;} break; case 2357: -#line 16921 "gram.y" +#line 16928 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_TRUE; ;} break; case 2358: -#line 16922 "gram.y" +#line 16929 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_FALSE; ;} break; case 2359: -#line 16923 "gram.y" +#line 16930 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_UNKNOWN; ;} break; case 2360: -#line 16924 "gram.y" +#line 16931 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_EMPTY_ARRAY; ;} break; case 2361: -#line 16925 "gram.y" +#line 16932 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_EMPTY_OBJECT; ;} break; case 2362: -#line 16927 "gram.y" +#line 16934 "gram.y" { (yyval.ival) = JSON_BEHAVIOR_EMPTY_ARRAY; ;} break; case 2363: -#line 16932 "gram.y" +#line 16939 "gram.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), NULL); ;} break; case 2364: -#line 16934 "gram.y" +#line 16941 "gram.y" { (yyval.list) = list_make2(NULL, (yyvsp[(1) - (3)].node)); ;} break; case 2365: -#line 16936 "gram.y" +#line 16943 "gram.y" { (yyval.list) = list_make2((yyvsp[(1) - (6)].node), (yyvsp[(4) - (6)].node)); ;} break; case 2366: -#line 16938 "gram.y" +#line 16945 "gram.y" { (yyval.list) = list_make2(NULL, NULL); ;} break; case 2367: -#line 16943 "gram.y" +#line 16950 "gram.y" { (yyval.node) = (yyvsp[(1) - (3)].node); ;} break; case 2368: -#line 16945 "gram.y" +#line 16952 "gram.y" { (yyval.node) = NULL; ;} break; case 2369: -#line 16950 "gram.y" +#line 16957 "gram.y" { /* formatted_expr will be set during parse-analysis. */ (yyval.node) = (Node *) makeJsonValueExpr((Expr *) (yyvsp[(1) - (2)].node), NULL, @@ -51759,7 +51766,7 @@ YYLTYPE yylloc; break; case 2370: -#line 16959 "gram.y" +#line 16966 "gram.y" { int encoding; @@ -51779,53 +51786,53 @@ YYLTYPE yylloc; break; case 2371: -#line 16976 "gram.y" +#line 16983 "gram.y" { (yyval.node) = (Node *) makeJsonFormat(JS_FORMAT_JSON, JS_ENC_DEFAULT, (yylsp[(1) - (2)])); ;} break; case 2372: -#line 16983 "gram.y" +#line 16990 "gram.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 2373: -#line 16987 "gram.y" +#line 16994 "gram.y" { (yyval.node) = (Node *) makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); ;} break; case 2374: -#line 16993 "gram.y" +#line 17000 "gram.y" { (yyval.ival) = JS_QUOTES_KEEP; ;} break; case 2375: -#line 16994 "gram.y" +#line 17001 "gram.y" { (yyval.ival) = JS_QUOTES_KEEP; ;} break; case 2376: -#line 16995 "gram.y" +#line 17002 "gram.y" { (yyval.ival) = JS_QUOTES_OMIT; ;} break; case 2377: -#line 16996 "gram.y" +#line 17003 "gram.y" { (yyval.ival) = JS_QUOTES_OMIT; ;} break; case 2378: -#line 16997 "gram.y" +#line 17004 "gram.y" { (yyval.ival) = JS_QUOTES_UNSPEC; ;} break; case 2379: -#line 17002 "gram.y" +#line 17009 "gram.y" { JsonOutput *n = makeNode(JsonOutput); @@ -51837,122 +51844,122 @@ YYLTYPE yylloc; break; case 2380: -#line 17010 "gram.y" +#line 17017 "gram.y" { (yyval.node) = NULL; ;} break; case 2381: -#line 17024 "gram.y" +#line 17031 "gram.y" { (yyval.ival) = JS_TYPE_ANY; ;} break; case 2382: -#line 17025 "gram.y" +#line 17032 "gram.y" { (yyval.ival) = JS_TYPE_ANY; ;} break; case 2383: -#line 17026 "gram.y" +#line 17033 "gram.y" { (yyval.ival) = JS_TYPE_ARRAY; ;} break; case 2384: -#line 17027 "gram.y" +#line 17034 "gram.y" { (yyval.ival) = JS_TYPE_OBJECT; ;} break; case 2385: -#line 17028 "gram.y" +#line 17035 "gram.y" { (yyval.ival) = JS_TYPE_SCALAR; ;} break; case 2386: -#line 17037 "gram.y" +#line 17044 "gram.y" { (yyval.boolean) = true; ;} break; case 2387: -#line 17038 "gram.y" +#line 17045 "gram.y" { (yyval.boolean) = true; ;} break; case 2388: -#line 17039 "gram.y" +#line 17046 "gram.y" { (yyval.boolean) = false; ;} break; case 2389: -#line 17040 "gram.y" +#line 17047 "gram.y" { (yyval.boolean) = false; ;} break; case 2390: -#line 17041 "gram.y" +#line 17048 "gram.y" { (yyval.boolean) = false; ;} break; case 2391: -#line 17046 "gram.y" +#line 17053 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2392: -#line 17048 "gram.y" +#line 17055 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 2393: -#line 17058 "gram.y" +#line 17065 "gram.y" { (yyval.node) = makeJsonKeyValue((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; case 2394: -#line 17061 "gram.y" +#line 17068 "gram.y" { (yyval.node) = makeJsonKeyValue((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; case 2395: -#line 17066 "gram.y" +#line 17073 "gram.y" { (yyval.boolean) = false; ;} break; case 2396: -#line 17067 "gram.y" +#line 17074 "gram.y" { (yyval.boolean) = true; ;} break; case 2397: -#line 17068 "gram.y" +#line 17075 "gram.y" { (yyval.boolean) = false; ;} break; case 2398: -#line 17072 "gram.y" +#line 17079 "gram.y" { (yyval.boolean) = false; ;} break; case 2399: -#line 17073 "gram.y" +#line 17080 "gram.y" { (yyval.boolean) = true; ;} break; case 2400: -#line 17074 "gram.y" +#line 17081 "gram.y" { (yyval.boolean) = true; ;} break; case 2401: -#line 17078 "gram.y" +#line 17085 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 2402: -#line 17079 "gram.y" +#line 17086 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));;} break; case 2403: -#line 17089 "gram.y" +#line 17096 "gram.y" { JsonObjectAgg *n = makeNode(JsonObjectAgg); @@ -51968,7 +51975,7 @@ YYLTYPE yylloc; break; case 2404: -#line 17107 "gram.y" +#line 17114 "gram.y" { JsonArrayAgg *n = makeNode(JsonArrayAgg); @@ -51983,37 +51990,37 @@ YYLTYPE yylloc; break; case 2405: -#line 17121 "gram.y" +#line 17128 "gram.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; case 2406: -#line 17122 "gram.y" +#line 17129 "gram.y" { (yyval.list) = NIL; ;} break; case 2407: -#line 17131 "gram.y" +#line 17138 "gram.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 2408: -#line 17132 "gram.y" +#line 17139 "gram.y" { (yyval.list) = NIL; ;} break; case 2409: -#line 17136 "gram.y" +#line 17143 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].target)); ;} break; case 2410: -#line 17137 "gram.y" +#line 17144 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].target)); ;} break; case 2411: -#line 17141 "gram.y" +#line 17148 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = (yyvsp[(3) - (3)].str); @@ -52024,7 +52031,7 @@ YYLTYPE yylloc; break; case 2412: -#line 17149 "gram.y" +#line 17156 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = (yyvsp[(2) - (2)].str); @@ -52035,7 +52042,7 @@ YYLTYPE yylloc; break; case 2413: -#line 17157 "gram.y" +#line 17164 "gram.y" { (yyval.target) = makeNode(ResTarget); (yyval.target)->name = NULL; @@ -52046,7 +52053,7 @@ YYLTYPE yylloc; break; case 2414: -#line 17165 "gram.y" +#line 17172 "gram.y" { ColumnRef *n = makeNode(ColumnRef); @@ -52062,61 +52069,61 @@ YYLTYPE yylloc; break; case 2415: -#line 17187 "gram.y" +#line 17194 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].range)); ;} break; case 2416: -#line 17188 "gram.y" +#line 17195 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].range)); ;} break; case 2417: -#line 17200 "gram.y" +#line 17207 "gram.y" { (yyval.range) = makeRangeVar(NULL, (yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; case 2418: -#line 17204 "gram.y" +#line 17211 "gram.y" { (yyval.range) = makeRangeVarFromQualifiedName((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].list), (yylsp[(1) - (2)]), yyscanner); ;} break; case 2419: -#line 17210 "gram.y" +#line 17217 "gram.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; case 2420: -#line 17212 "gram.y" +#line 17219 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; case 2421: -#line 17216 "gram.y" +#line 17223 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2422: -#line 17218 "gram.y" +#line 17225 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2423: -#line 17220 "gram.y" +#line 17227 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2424: -#line 17231 "gram.y" +#line 17238 "gram.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; case 2425: -#line 17233 "gram.y" +#line 17240 "gram.y" { (yyval.list) = check_func_name(lcons(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].list)), yyscanner); @@ -52124,35 +52131,35 @@ YYLTYPE yylloc; break; case 2426: -#line 17244 "gram.y" +#line 17251 "gram.y" { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); ;} break; case 2427: -#line 17248 "gram.y" +#line 17255 "gram.y" { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; case 2428: -#line 17252 "gram.y" +#line 17259 "gram.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; case 2429: -#line 17256 "gram.y" +#line 17263 "gram.y" { (yyval.node) = makeBitStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; case 2430: -#line 17260 "gram.y" +#line 17267 "gram.y" { /* This is a bit constant per SQL99: * Without Feature F511, "BIT data type", @@ -52164,7 +52171,7 @@ YYLTYPE yylloc; break; case 2431: -#line 17269 "gram.y" +#line 17276 "gram.y" { /* generic type 'literal' syntax */ TypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); @@ -52175,7 +52182,7 @@ YYLTYPE yylloc; break; case 2432: -#line 17277 "gram.y" +#line 17284 "gram.y" { /* generic syntax with a type modifier */ TypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (6)].list)); @@ -52210,7 +52217,7 @@ YYLTYPE yylloc; break; case 2433: -#line 17309 "gram.y" +#line 17316 "gram.y" { /* generic type 'literal' syntax */ TypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); @@ -52220,7 +52227,7 @@ YYLTYPE yylloc; break; case 2434: -#line 17316 "gram.y" +#line 17323 "gram.y" { /* generic syntax with a type modifier */ TypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (6)].list)); @@ -52255,14 +52262,14 @@ YYLTYPE yylloc; break; case 2435: -#line 17348 "gram.y" +#line 17355 "gram.y" { (yyval.node) = makeStringConstCast((yyvsp[(2) - (2)].str), (yylsp[(2) - (2)]), (yyvsp[(1) - (2)].typnam)); ;} break; case 2436: -#line 17352 "gram.y" +#line 17359 "gram.y" { TypeName *t = (yyvsp[(1) - (3)].typnam); @@ -52272,7 +52279,7 @@ YYLTYPE yylloc; break; case 2437: -#line 17359 "gram.y" +#line 17366 "gram.y" { TypeName *t = (yyvsp[(1) - (5)].typnam); @@ -52283,14 +52290,14 @@ YYLTYPE yylloc; break; case 2438: -#line 17367 "gram.y" +#line 17374 "gram.y" { (yyval.node) = makeParamRefCast((yyvsp[(2) - (2)].ival), (yylsp[(2) - (2)]), (yyvsp[(1) - (2)].typnam)); ;} break; case 2439: -#line 17371 "gram.y" +#line 17378 "gram.y" { TypeName *t = (yyvsp[(1) - (3)].typnam); t->typmods = (yyvsp[(3) - (3)].list); @@ -52299,7 +52306,7 @@ YYLTYPE yylloc; break; case 2440: -#line 17377 "gram.y" +#line 17384 "gram.y" { TypeName *t = (yyvsp[(1) - (5)].typnam); t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), @@ -52309,53 +52316,53 @@ YYLTYPE yylloc; break; case 2441: -#line 17384 "gram.y" +#line 17391 "gram.y" { (yyval.node) = makeBoolAConst(true, (yylsp[(1) - (1)])); ;} break; case 2442: -#line 17388 "gram.y" +#line 17395 "gram.y" { (yyval.node) = makeBoolAConst(false, (yylsp[(1) - (1)])); ;} break; case 2443: -#line 17392 "gram.y" +#line 17399 "gram.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; case 2444: -#line 17397 "gram.y" +#line 17404 "gram.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; case 2445: -#line 17398 "gram.y" +#line 17405 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2446: -#line 17400 "gram.y" +#line 17407 "gram.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; case 2447: -#line 17401 "gram.y" +#line 17408 "gram.y" { (yyval.ival) = + (yyvsp[(2) - (2)].ival); ;} break; case 2448: -#line 17402 "gram.y" +#line 17409 "gram.y" { (yyval.ival) = - (yyvsp[(2) - (2)].ival); ;} break; case 2449: -#line 17407 "gram.y" +#line 17414 "gram.y" { RoleSpec *spc = (RoleSpec *) (yyvsp[(1) - (1)].rolespec); @@ -52397,7 +52404,7 @@ YYLTYPE yylloc; break; case 2450: -#line 17448 "gram.y" +#line 17455 "gram.y" { /* * "public" and "none" are not keywords, but they must @@ -52428,38 +52435,38 @@ YYLTYPE yylloc; break; case 2451: -#line 17476 "gram.y" +#line 17483 "gram.y" { (yyval.rolespec) = makeRoleSpec(ROLESPEC_CURRENT_ROLE, (yylsp[(1) - (1)])); ;} break; case 2452: -#line 17480 "gram.y" +#line 17487 "gram.y" { (yyval.rolespec) = makeRoleSpec(ROLESPEC_CURRENT_USER, (yylsp[(1) - (1)])); ;} break; case 2453: -#line 17484 "gram.y" +#line 17491 "gram.y" { (yyval.rolespec) = makeRoleSpec(ROLESPEC_SESSION_USER, (yylsp[(1) - (1)])); ;} break; case 2454: -#line 17490 "gram.y" +#line 17497 "gram.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].rolespec)); ;} break; case 2455: -#line 17492 "gram.y" +#line 17499 "gram.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].rolespec)); ;} break; case 2456: -#line 17509 "gram.y" +#line 17516 "gram.y" { SelectStmt *n = makeNode(SelectStmt); @@ -52489,7 +52496,7 @@ YYLTYPE yylloc; break; case 2457: -#line 17542 "gram.y" +#line 17549 "gram.y" { PLAssignStmt *n = makeNode(PLAssignStmt); @@ -52503,103 +52510,103 @@ YYLTYPE yylloc; break; case 2458: -#line 17554 "gram.y" +#line 17561 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2459: -#line 17555 "gram.y" +#line 17562 "gram.y" { (yyval.str) = psprintf("$%d", (yyvsp[(1) - (1)].ival)); ;} break; case 2462: -#line 17576 "gram.y" +#line 17583 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2463: -#line 17577 "gram.y" +#line 17584 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2464: -#line 17578 "gram.y" +#line 17585 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2465: -#line 17583 "gram.y" +#line 17590 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2466: -#line 17584 "gram.y" +#line 17591 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2467: -#line 17585 "gram.y" +#line 17592 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2468: -#line 17590 "gram.y" +#line 17597 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2469: -#line 17591 "gram.y" +#line 17598 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2470: -#line 17592 "gram.y" +#line 17599 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2471: -#line 17593 "gram.y" +#line 17600 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2472: -#line 17599 "gram.y" +#line 17606 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2473: -#line 17600 "gram.y" +#line 17607 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2474: -#line 17601 "gram.y" +#line 17608 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2475: -#line 17602 "gram.y" +#line 17609 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2476: -#line 17603 "gram.y" +#line 17610 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; case 2477: -#line 17609 "gram.y" +#line 17616 "gram.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 2478: -#line 17610 "gram.y" +#line 17617 "gram.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; /* Line 1267 of yacc.c. */ -#line 52543 "gram.c" +#line 52550 "gram.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -52819,7 +52826,7 @@ YYLTYPE yylloc; } -#line 18622 "gram.y" +#line 18629 "gram.y" /* diff --git a/c_src/libpg_query/src/postgres/src_backend_utils_activity_pgstat_database.c b/c_src/libpg_query/src/postgres/src_backend_utils_activity_pgstat_database.c index fb5b1aab..315d637e 100644 --- a/c_src/libpg_query/src/postgres/src_backend_utils_activity_pgstat_database.c +++ b/c_src/libpg_query/src/postgres/src_backend_utils_activity_pgstat_database.c @@ -130,8 +130,8 @@ __thread SessionEndType pgStatSessionEndCause = DISCONNECT_NORMAL; /* * Flush out pending stats for the entry * - * If nowait is true, this function returns false if lock could not - * immediately acquired, otherwise true is returned. + * If nowait is true and the lock could not be immediately acquired, returns + * false without flushing the entry. Otherwise returns true. */ #define PGSTAT_ACCUM_DBCOUNT(item) \ (sharedent)->stats.item += (pendingent)->item diff --git a/c_src/libpg_query/src/postgres/src_backend_utils_error_elog.c b/c_src/libpg_query/src/postgres/src_backend_utils_error_elog.c index 58f76a9b..49b7311a 100644 --- a/c_src/libpg_query/src/postgres/src_backend_utils_error_elog.c +++ b/c_src/libpg_query/src/postgres/src_backend_utils_error_elog.c @@ -1939,6 +1939,17 @@ write_stderr(const char *fmt,...) } + + +/* + * Write errors to stderr (or by equal means when stderr is + * not available) - va_list version + */ +#ifdef WIN32 +#endif +#ifndef WIN32 +#else +#endif #ifdef WIN32 __thread volatile int pg_signal_queue; diff --git a/c_src/libpg_query/src/postgres/src_backend_utils_mb_mbutils.c b/c_src/libpg_query/src/postgres/src_backend_utils_mb_mbutils.c index 62f21463..2485cd56 100644 --- a/c_src/libpg_query/src/postgres/src_backend_utils_mb_mbutils.c +++ b/c_src/libpg_query/src/postgres/src_backend_utils_mb_mbutils.c @@ -17,6 +17,8 @@ * - pg_mbstrlen_with_len * - pg_mblen * - SetDatabaseEncoding + * - pg_mbcharcliplen + * - pg_mbstrlen * - GetMessageEncoding * - MessageEncoding *-------------------------------------------------------------------- @@ -386,7 +388,22 @@ pg_mblen(const char *mbstr) /* returns the length (counted in wchars) of a multibyte string */ +int +pg_mbstrlen(const char *mbstr) +{ + int len = 0; + /* optimization for single byte encoding */ + if (pg_database_encoding_max_length() == 1) + return strlen(mbstr); + + while (*mbstr) + { + mbstr += pg_mblen(mbstr); + len++; + } + return len; +} /* returns the length (counted in wchars) of a multibyte string * (not necessarily NULL terminated) @@ -425,7 +442,7 @@ pg_mbcliplen(const char *mbstr, int len, int limit) } /* - * pg_mbcliplen with specified encoding + * pg_mbcliplen with specified encoding; string must be valid in encoding */ int pg_encoding_mbcliplen(int encoding, const char *mbstr, @@ -459,7 +476,29 @@ pg_encoding_mbcliplen(int encoding, const char *mbstr, * Similar to pg_mbcliplen except the limit parameter specifies the * character length, not the byte length. */ +int +pg_mbcharcliplen(const char *mbstr, int len, int limit) +{ + int clen = 0; + int nch = 0; + int l; + /* optimization for single byte encoding */ + if (pg_database_encoding_max_length() == 1) + return cliplen(mbstr, len, limit); + + while (len > 0 && *mbstr) + { + l = pg_mblen(mbstr); + nch++; + if (nch > limit) + break; + clen += l; + len -= l; + mbstr += l; + } + return clen; +} /* mbcliplen for any single-byte encoding */ static int @@ -726,12 +765,12 @@ pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError) * report_invalid_encoding: complain about invalid multibyte character * * note: len is remaining length of string, not length of character; - * len must be greater than zero, as we always examine the first byte. + * len must be greater than zero (or we'd neglect initializing "buf"). */ void report_invalid_encoding(int encoding, const char *mbstr, int len) { - int l = pg_encoding_mblen(encoding, mbstr); + int l = pg_encoding_mblen_or_incomplete(encoding, mbstr, len); char buf[8 * 5 + 1]; char *p = buf; int j, @@ -758,7 +797,7 @@ report_invalid_encoding(int encoding, const char *mbstr, int len) * report_untranslatable_char: complain about untranslatable character * * note: len is remaining length of string, not length of character; - * len must be greater than zero, as we always examine the first byte. + * len must be greater than zero (or we'd neglect initializing "buf"). */ diff --git a/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_alignedalloc.c b/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_alignedalloc.c index 3de2c7bd..fd4b0e3f 100644 --- a/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_alignedalloc.c +++ b/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_alignedalloc.c @@ -54,6 +54,7 @@ AlignedAllocFree(void *pointer) GetMemoryChunkContext(unaligned)->name, chunk); #endif + /* Recursively pfree the unaligned chunk */ pfree(unaligned); } @@ -105,18 +106,32 @@ AlignedAllocRealloc(void *pointer, Size size, int flags) Assert(old_size >= redirchunk->requested_size); #endif + /* + * To keep things simple, we always allocate a new aligned chunk and copy + * data into it. Because of the above inaccuracy, this may end in copying + * more data than was in the original allocation request size, but that + * should be OK. + */ ctx = GetMemoryChunkContext(unaligned); newptr = MemoryContextAllocAligned(ctx, size, alignto, flags); - /* - * We may memcpy beyond the end of the original allocation request size, - * so we must mark the entire allocation as defined. - */ - if (likely(newptr != NULL)) + /* Cope cleanly with OOM */ + if (unlikely(newptr == NULL)) { - VALGRIND_MAKE_MEM_DEFINED(pointer, old_size); - memcpy(newptr, pointer, Min(size, old_size)); + VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk)); + return MemoryContextAllocationFailure(ctx, size, flags); } + + /* + * We may memcpy more than the original allocation request size, which + * would result in trying to copy trailing bytes that the original + * MemoryContextAllocAligned call marked NOACCESS. So we must mark the + * entire old_size as defined. That's slightly annoying, but probably not + * worth improving. + */ + VALGRIND_MAKE_MEM_DEFINED(pointer, old_size); + memcpy(newptr, pointer, Min(size, old_size)); + pfree(unaligned); return newptr; diff --git a/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_aset.c b/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_aset.c index ee5b337d..3aad0acb 100644 --- a/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_aset.c +++ b/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_aset.c @@ -1632,9 +1632,9 @@ AllocSetCheck(MemoryContext context) prevblock = block, block = block->next) { char *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ; - long blk_used = block->freeptr - bpoz; - long blk_data = 0; - long nchunks = 0; + Size blk_used = block->freeptr - bpoz; + Size blk_data = 0; + Size nchunks = 0; bool has_external_chunk = false; if (IsKeeperBlock(set, block)) diff --git a/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_bump.c b/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_bump.c index 453fb4fd..8d719946 100644 --- a/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_bump.c +++ b/c_src/libpg_query/src/postgres/src_backend_utils_mmgr_bump.c @@ -236,7 +236,7 @@ BumpAllocLarge(MemoryContext context, Size size, int flags) block = (BumpBlock *) malloc(blksize); if (block == NULL) - return NULL; + return MemoryContextAllocationFailure(context, size, flags); context->mem_allocated += blksize; diff --git a/c_src/libpg_query/src/postgres/src_common_stringinfo.c b/c_src/libpg_query/src/postgres/src_common_stringinfo.c index 75556396..fffc2022 100644 --- a/c_src/libpg_query/src/postgres/src_common_stringinfo.c +++ b/c_src/libpg_query/src/postgres/src_common_stringinfo.c @@ -9,6 +9,8 @@ * - enlargeStringInfo * - appendStringInfo * - appendStringInfoSpaces + * - makeStringInfo + * - destroyStringInfo *-------------------------------------------------------------------- */ @@ -51,7 +53,17 @@ * * Create an empty 'StringInfoData' & return a pointer to it. */ +StringInfo +makeStringInfo(void) +{ + StringInfo res; + + res = (StringInfo) palloc(sizeof(StringInfoData)); + initStringInfo(res); + + return res; +} /* * initStringInfo @@ -350,4 +362,12 @@ enlargeStringInfo(StringInfo str, int needed) * Frees a StringInfo and its buffer (opposite of makeStringInfo()). * This must only be called on palloc'd StringInfos. */ +void +destroyStringInfo(StringInfo str) +{ + /* don't allow destroys of read-only StringInfos */ + Assert(str->maxlen != 0); + pfree(str->data); + pfree(str); +} diff --git a/c_src/libpg_query/src/postgres/src_common_wchar.c b/c_src/libpg_query/src/postgres/src_common_wchar.c index 1483b073..6e31b761 100644 --- a/c_src/libpg_query/src/postgres/src_common_wchar.c +++ b/c_src/libpg_query/src/postgres/src_common_wchar.c @@ -76,6 +76,7 @@ * - pg_johab_dsplen * - pg_johab_verifychar * - pg_johab_verifystr + * - pg_encoding_mblen_or_incomplete * - pg_encoding_mblen *-------------------------------------------------------------------- */ @@ -94,6 +95,8 @@ */ #include "c.h" +#include + #include "mb/pg_wchar.h" #include "utils/ascii.h" @@ -2182,10 +2185,27 @@ const pg_wchar_tbl pg_wchar_table[] = { /* * Returns the byte length of a multibyte character. * - * Caution: when dealing with text that is not certainly valid in the - * specified encoding, the result may exceed the actual remaining - * string length. Callers that are not prepared to deal with that - * should use pg_encoding_mblen_bounded() instead. + * Choose "mblen" functions based on the input string characteristics. + * pg_encoding_mblen() can be used when ANY of these conditions are met: + * + * - The input string is zero-terminated + * + * - The input string is known to be valid in the encoding (e.g., string + * converted from database encoding) + * + * - The encoding is not GB18030 (e.g., when only database encodings are + * passed to 'encoding' parameter) + * + * encoding==GB18030 requires examining up to two bytes to determine character + * length. Therefore, callers satisfying none of those conditions must use + * pg_encoding_mblen_or_incomplete() instead, as access to mbstr[1] cannot be + * guaranteed to be within allocation bounds. + * + * When dealing with text that is not certainly valid in the specified + * encoding, the result may exceed the actual remaining string length. + * Callers that are not prepared to deal with that should use Min(remaining, + * pg_encoding_mblen_or_incomplete()). For zero-terminated strings, that and + * pg_encoding_mblen_bounded() are interchangeable. */ int pg_encoding_mblen(int encoding, const char *mbstr) @@ -2196,8 +2216,28 @@ pg_encoding_mblen(int encoding, const char *mbstr) } /* - * Returns the byte length of a multibyte character; but not more than - * the distance to end of string. + * Returns the byte length of a multibyte character (possibly not + * zero-terminated), or INT_MAX if too few bytes remain to determine a length. + */ +int +pg_encoding_mblen_or_incomplete(int encoding, const char *mbstr, + size_t remaining) +{ + /* + * Define zero remaining as too few, even for single-byte encodings. + * pg_gb18030_mblen() reads one or two bytes; single-byte encodings read + * zero; others read one. + */ + if (remaining < 1 || + (encoding == PG_GB18030 && IS_HIGHBIT_SET(*mbstr) && remaining < 2)) + return INT_MAX; + return pg_encoding_mblen(encoding, mbstr); +} + +/* + * Returns the byte length of a multibyte character; but not more than the + * distance to the terminating zero byte. For input that might lack a + * terminating zero, use Min(remaining, pg_encoding_mblen_or_incomplete()). */ diff --git a/c_src/libpg_query/src/postgres_deparse.c b/c_src/libpg_query/src/postgres_deparse.c index 09121d11..79f8c476 100644 --- a/c_src/libpg_query/src/postgres_deparse.c +++ b/c_src/libpg_query/src/postgres_deparse.c @@ -1,3 +1,5 @@ +#include "postgres_deparse.h" + #include "postgres.h" #include "catalog/index.h" #include "catalog/pg_am.h" @@ -16,22 +18,235 @@ #include "utils/timestamp.h" #include "utils/xml.h" +/* + * # Deparser overview + * + * The deparser works by walking the input parse tree and emitting into the + * currently active "part" as pointed to (indirectly) by the state struct. + * + * A lot of the structure of the deparser described below is meant to support + * the optional "pretty print" mode that can be enabled and configured through + * the deparser options, and inserts whitespace (newlines/spaces) as needed to + * make the output easier to read. + * + * ## Nesting levels + * + * Starting at the state struct we have a currently active "nesting level", + * which indicates the base indentation, as well as contains one or more part + * groups, each of which has one or more parts. + * + * Nesting levels are typically opened, or "increased", when processing a new + * statement contained within other statements, or for certain statement-like + * constructs (e.g. CASE clauses) that require custom indendation. + * + * Nesting levels are closed, or "decreased", when exiting such statements or + * statement-like constructs. During this operation all parts and subparts get + * flattened (turned into a simple list of parts), and are added to the parent + * nesting level. + * + * At the end of the tree walk the parts of the top most nesting level get + * emitted into the output string, formatted based on the deparse options. + * + * ## Part groups + * + * Part groups are usually started for each "major" keyword, which is chosen + * for how the output is intended to be laid out. For example, the "FROM" + * keyword in a SELECT statement is considered "major" and starts a new part + * group, vs the "JOIN" keyword is not, and as such both regular tables and + * JOIN clauses will be within one part group. + * + * ## Parts, indentation and merging + * + * The parts contained in part groups may be indented one additional level + * beyond the base indentation of the currently active nesting level, to help + * differentiate them from the major keywords. This can be turned off with + * DEPARSE_PART_NO_INDENT, for example as needed to format WITH clauses + * effectively. + * + * Parts may be merged with other parts within the same group, if the indent + * mode is set to DEPARSE_PART_INDENT_AND_MERGE. This is utilized to put + * certain items, for example the target list items in SELECT on one or more + * lines, breaking at separators as needed to respect the maximum line limit. + * + * ## Node context + * + * Node context is used when the same function in the deparser needs to behave + * differently depending on the parent node. For example, a SELECT statement + * needs wrapping parenthesis in certain situations where the parent statement + * uses a set operation (e.g. UNION). + * + * ## Comments + * + * Comments do not exist as nodes in a Postgres parse tree, and as such need to + * be passed in separately through the deparser options. They are placed in the + * output on a best effort basis, by matching against node locations. Comments + * will only be output at most once, but may not be output at all in certain + * cases, for example when the comment's specified match location is never + * reached by any of the nodes visited. + */ + typedef enum DeparseNodeContext { DEPARSE_NODE_CONTEXT_NONE, // Parent node type (and sometimes field) DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_SELECT, DEPARSE_NODE_CONTEXT_A_EXPR, DEPARSE_NODE_CONTEXT_CREATE_TYPE, DEPARSE_NODE_CONTEXT_ALTER_TYPE, DEPARSE_NODE_CONTEXT_SET_STATEMENT, DEPARSE_NODE_CONTEXT_FUNC_EXPR, + DEPARSE_NODE_CONTEXT_SELECT_SETOP, + DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE, // Identifier vs constant context DEPARSE_NODE_CONTEXT_IDENTIFIER, DEPARSE_NODE_CONTEXT_CONSTANT } DeparseNodeContext; +typedef enum DeparsePartIndentMode { + /* Don't indent parts at all, used in special cases (e.g. WITH clauses) */ + DEPARSE_PART_NO_INDENT, + + /* Indent parts but don't merge them (keep each on their own line) */ + DEPARSE_PART_INDENT, + + /* Indent parts and merge them together up to the max line length */ + DEPARSE_PART_INDENT_AND_MERGE +} DeparsePartIndentMode; + +// Each part is typically one line to be emitted in pretty print mode +typedef struct DeparseStatePart +{ + StringInfo str; + + /* If this gets emitted as its own line, number of spaces to be added as indentation */ + int indent; + + /* Allow merging this part with adjacent parts that are marked as mergeable */ + bool mergeable; +} DeparseStatePart; + +// A part group are typically all parts associated with a major keyword +typedef struct DeparseStatePartGroup +{ + const char *keyword; + List *parts; + DeparsePartIndentMode indent_mode; +} DeparseStatePartGroup; + +// Nesting levels may be statements, or complex parts of statements that should be indented (e.g. CASE) +typedef struct DeparseStateNestingLevel +{ + /* List of DeparseStatePartGroup items */ + List *part_groups; + + /* Add this much indentation to every part */ + int base_indent; +} DeparseStateNestingLevel; + +typedef struct DeparseState +{ + DeparseStateNestingLevel *current; + + /* List of DeparseStatePart items */ + List *result_parts; + + /* Deparse options originally passed in */ + PostgresDeparseOpts opts; + + /* Set of indexes of comments already placed in the output query */ + Bitmapset *emitted_comments; +} DeparseState; + +static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context); +static void deparseIntoClause(DeparseState *state, IntoClause *into_clause); +static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(DeparseState *state, ResTarget *res_target, DeparseNodeContext context); +static void deparseAlias(DeparseState *state, Alias *alias); +static void deparseWindowDef(DeparseState *state, WindowDef* window_def); +static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref); +static void deparseSubLink(DeparseState *state, SubLink* sub_link); +static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr); +static void deparseAStar(DeparseState *state, A_Star* a_star); +static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause); +static void deparseSortBy(DeparseState *state, SortBy* sort_by); +static void deparseParamRef(DeparseState *state, ParamRef* param_ref); +static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function); +static void deparseWithClause(DeparseState *state, WithClause *with_clause); +static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr); +static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte); +static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect); +static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func); +static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr * array_expr); +static void deparseRowExpr(DeparseState *state, RowExpr *row_expr); +static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context); +static void deparseTypeName(DeparseState *state, TypeName *type_name); +static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name); +static void deparseNullTest(DeparseState *state, NullTest *null_test); +static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr); +static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when); +static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection); +static void deparseAIndices(DeparseState *state, A_Indices *a_indices); +static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test); +static void deparseColumnDef(DeparseState *state, ColumnDef *column_def); +static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt); +static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(DeparseState *state, IndexElem* index_elem); +static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt); +static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt); +static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause); +static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default); +static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter); +static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec); +static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt); +static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func); +static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set); +static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context); +static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context); +static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize); +static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *json_is_predicate); +static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg); +static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg); +static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor); +static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor); +static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor); +static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr); +static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output); +static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr); +static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr); +static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr); +static void deparseJsonTable(DeparseState *state, JsonTable *json_table); +static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column); +static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns); +static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec); +static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior); +static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr); +static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes); +static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior); +static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior); +static void deparseConstraint(DeparseState *state, Constraint *constraint); +static void deparseSchemaStmt(DeparseState *state, Node *node); +static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item); +static void deparseAConst(DeparseState *state, A_Const *a_const); +static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(DeparseState *state, Node *node); +static void deparseRuleActionStmt(DeparseState *state, Node *node); +static void deparseExplainableStmt(DeparseState *state, Node *node); +static void deparseStmt(DeparseState *state, Node *node); +static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context); + static void -removeTrailingSpace(StringInfo str) +removeTrailingSpaceFromStr(StringInfo str) { if (str->len >= 1 && str->data[str->len - 1] == ' ') { str->len -= 1; @@ -39,37 +254,6 @@ removeTrailingSpace(StringInfo str) } } -/* - * Append a SQL string literal representing "val" to buf. - * - * Copied here from postgres_fdw/deparse.c to avoid adding - * many additional dependencies. - */ -static void -deparseStringLiteral(StringInfo buf, const char *val) -{ - const char *valptr; - - /* - * Rather than making assumptions about the remote server's value of - * standard_conforming_strings, always use E'foo' syntax if there are any - * backslashes. This will fail on remote servers before 8.1, but those - * are long out of support. - */ - if (strchr(val, '\\') != NULL) - appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); - appendStringInfoChar(buf, '\''); - for (valptr = val; *valptr; valptr++) - { - char ch = *valptr; - - if (SQL_STR_DOUBLE(ch, true)) - appendStringInfoChar(buf, ch); - appendStringInfoChar(buf, ch); - } - appendStringInfoChar(buf, '\''); -} - // Check whether the value is a reserved keyword, to determine escaping for output // // Note that since the parser lowercases all keywords, this does *not* match when the @@ -130,122 +314,410 @@ isOp(const char *val) return true; } -static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); -static void deparseIntoClause(StringInfo str, IntoClause *into_clause); -static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); -static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); -void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); -static void deparseAlias(StringInfo str, Alias *alias); -static void deparseWindowDef(StringInfo str, WindowDef* window_def); -static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); -static void deparseSubLink(StringInfo str, SubLink* sub_link); -static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); -static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); -static void deparseAStar(StringInfo str, A_Star* a_star); -static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); -static void deparseSortBy(StringInfo str, SortBy* sort_by); -static void deparseParamRef(StringInfo str, ParamRef* param_ref); -static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); -static void deparseWithClause(StringInfo str, WithClause *with_clause); -static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); -static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); -static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); -static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); -static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); -static void deparseRowExpr(StringInfo str, RowExpr *row_expr); -static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context); -static void deparseTypeName(StringInfo str, TypeName *type_name); -static void deparseIntervalTypmods(StringInfo str, TypeName *type_name); -static void deparseNullTest(StringInfo str, NullTest *null_test); -static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); -static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); -static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); -static void deparseAIndices(StringInfo str, A_Indices *a_indices); -static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); -static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); -static void deparseColumnDef(StringInfo str, ColumnDef *column_def); -static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); -static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); -static void deparseIndexElem(StringInfo str, IndexElem* index_elem); -static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); -static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); -static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); -static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); -static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); -static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); -static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); -static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); -static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); -static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); -static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); -static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); -static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); -static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); -static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeContext context); -static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); -static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr, DeparseNodeContext context); -static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); -static void deparseJsonIsPredicate(StringInfo str, JsonIsPredicate *json_is_predicate); -static void deparseJsonObjectAgg(StringInfo str, JsonObjectAgg *json_object_agg); -static void deparseJsonArrayAgg(StringInfo str, JsonArrayAgg *json_array_agg); -static void deparseJsonObjectConstructor(StringInfo str, JsonObjectConstructor *json_object_constructor); -static void deparseJsonArrayConstructor(StringInfo str, JsonArrayConstructor *json_array_constructor); -static void deparseJsonArrayQueryConstructor(StringInfo str, JsonArrayQueryConstructor *json_array_query_constructor); -static void deparseJsonValueExpr(StringInfo str, JsonValueExpr *json_value_expr); -static void deparseJsonOutput(StringInfo str, JsonOutput *json_output); -static void deparseJsonParseExpr(StringInfo str, JsonParseExpr *json_parse_expr); -static void deparseJsonScalarExpr(StringInfo str, JsonScalarExpr *json_scalar_expr); -static void deparseJsonSerializeExpr(StringInfo str, JsonSerializeExpr *json_serialize_expr); -static void deparseJsonTable(StringInfo str, JsonTable *json_table); -static void deparseJsonTableColumn(StringInfo str, JsonTableColumn *json_table_column); -static void deparseJsonTableColumns(StringInfo str, List *json_table_columns); -static void deparseJsonTablePathSpec(StringInfo str, JsonTablePathSpec *json_table_path_spec); -static void deparseJsonBehavior(StringInfo str, JsonBehavior *json_behavior); -static void deparseJsonFuncExpr(StringInfo str, JsonFuncExpr *json_func_expr); -static void deparseJsonQuotesClauseOpt(StringInfo str, JsonQuotes quotes); -static void deparseJsonOnErrorClauseOpt(StringInfo str, JsonBehavior *behavior); -static void deparseJsonOnEmptyClauseOpt(StringInfo str, JsonBehavior *behavior); -static void deparseConstraint(StringInfo str, Constraint *constraint); -static void deparseSchemaStmt(StringInfo str, Node *node); -static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); -static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); -static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); -static void deparseAConst(StringInfo str, A_Const *a_const); -static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); - -static void deparsePreparableStmt(StringInfo str, Node *node); -static void deparseRuleActionStmt(StringInfo str, Node *node); -static void deparseExplainableStmt(StringInfo str, Node *node); -static void deparseStmt(StringInfo str, Node *node); -static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context); +static DeparseStatePart * +makeDeparseStatePart(DeparseState *state, DeparseStateNestingLevel *level, DeparsePartIndentMode indent_mode) +{ + DeparseStatePart *part = palloc(sizeof(DeparseStatePart)); + part->str = makeStringInfo(); + part->indent = level->base_indent; + if (indent_mode != DEPARSE_PART_NO_INDENT) + part->indent += state->opts.indent_size; + part->mergeable = indent_mode == DEPARSE_PART_INDENT_AND_MERGE; + return part; +} +static void +freeDeparseStatePart(DeparseStatePart *part) +{ + pfree(part->str->data); + pfree(part->str); + pfree(part); +} + +// Returns current active part group, and initializes the first one (including an empty part) if needed +static DeparseStatePartGroup * +deparseGetCurrentPartGroup(DeparseState *state) +{ + DeparseStateNestingLevel *level = state->current; + if (level->part_groups) + return (DeparseStatePartGroup *) llast(level->part_groups); + + DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, level, part_group->indent_mode)); + level->part_groups = lappend(level->part_groups, part_group); + return part_group; +} + +static DeparseStatePart * +deparseGetCurrentPart(DeparseState *state) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + return (DeparseStatePart *) llast(part_group->parts); +} + +static void +deparseMarkCurrentPartNonMergable(DeparseState *state) +{ + DeparseStatePart *part = deparseGetCurrentPart(state); + part->mergeable = false; +} + +static StringInfo deparseGetCurrentStringInfo(DeparseState *state) +{ + DeparseStatePart *part = deparseGetCurrentPart(state); + Assert(part != NULL); + return part->str; +} + +static void deparseAppendStringInfo(DeparseState *state, const char *fmt,...) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + int save_errno = errno; + + for (;;) + { + va_list args; + int needed; + + /* Try to format the data. */ + errno = save_errno; + va_start(args, fmt); + needed = appendStringInfoVA(str, fmt, args); + va_end(args); + + if (needed == 0) + break; /* success */ + + /* Increase the buffer size and try again. */ + enlargeStringInfo(str, needed); + } +} + +static void deparseAppendStringInfoString(DeparseState *state, const char *s) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + appendStringInfoString(str, s); +} + +static void deparseAppendStringInfoChar(DeparseState *state, char ch) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + appendStringInfoChar(str, ch); +} + +static void +removeTrailingSpace(DeparseState *state) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + removeTrailingSpaceFromStr(str); +} + +static void +deparseRemoveTrailingEmptyPart(DeparseState *state) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + DeparseStatePart *last_part = deparseGetCurrentPart(state); + + if (last_part->str->len == 0) + { + freeDeparseStatePart(last_part); + part_group->parts = list_delete_last(part_group->parts); + } +} + +static void +deparseAppendPart(DeparseState *state, bool deduplicate) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + + // Remove previous part if its empty and we deduplicate. We don't keep + // the existing part since it may have the wrong indent level or mode. + if (deduplicate) + deparseRemoveTrailingEmptyPart(state); + + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, part_group->indent_mode)); +} + +static void +deparseAppendCommaAndPart(DeparseState *state) +{ + if (state->opts.commas_start_of_line) + { + deparseAppendPart(state, true); + deparseAppendStringInfoString(state, ", "); + } + else + { + deparseAppendStringInfoChar(state, ','); + deparseAppendPart(state, true); + } +} + +static void +deparseAppendPartGroup(DeparseState *state, const char *keyword, DeparsePartIndentMode indent_mode) +{ + DeparseStateNestingLevel *level = state->current; + DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); + + if (list_length(level->part_groups) > 0) + removeTrailingSpace(state); + + part_group->keyword = keyword; + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, indent_mode)); + part_group->indent_mode = indent_mode; + + level->part_groups = lappend(level->part_groups, part_group); +} + +static void +deparseAppendCommentsIfNeeded(DeparseState *state, ParseLoc location) +{ + for (int i = 0; i < state->opts.comment_count; i++) + { + if (bms_is_member(i, state->emitted_comments)) + continue; + + PostgresDeparseComment *comment = state->opts.comments[i]; + if (comment->match_location > location) + continue; + + // Emit one less leading newline if we already emitted one for formatting reasons + int newlines_before_comment = comment->newlines_before_comment; + if (state->opts.pretty_print && newlines_before_comment > 0 && + deparseGetCurrentPartGroup(state)->keyword != NULL && + deparseGetCurrentStringInfo(state)->len == 0) + newlines_before_comment -= 1; + + for (int j = 0; j < newlines_before_comment; j++) + { + if (state->opts.pretty_print) + deparseAppendPart(state, false); + else + deparseAppendStringInfoChar(state, '\n'); + } + + deparseAppendStringInfoString(state, comment->str); + + /* never merge comments with other parts */ + deparseMarkCurrentPartNonMergable(state); + + for (int j = 0; j < comment->newlines_after_comment; j++) + { + if (state->opts.pretty_print) + deparseAppendPart(state, false); + else + deparseAppendStringInfoChar(state, '\n'); + } + + state->emitted_comments = bms_add_member(state->emitted_comments, i); + } +} + +static void +deparseEmit(DeparseState *state, StringInfo str) +{ + ListCell *lc; + + /* If the last part is empty, drop it, so we don't confuse the newline output */ + DeparseStatePart *last_part = (DeparseStatePart *) llast(state->result_parts); + if (last_part && last_part->str->len == 0) + { + freeDeparseStatePart(last_part); + state->result_parts = list_delete_last(state->result_parts); + } + + foreach (lc, state->result_parts) + { + DeparseStatePart *part = (DeparseStatePart *) lfirst(lc); + bool last_part = list_cell_number(state->result_parts, lc) == list_length(state->result_parts) - 1; + + if (!state->opts.pretty_print && part->str->len > 0 && (part->str->data[0] == ')' || part->str->data[0] == ';')) + removeTrailingSpaceFromStr(str); + + if (state->opts.pretty_print) + { + for (int i = 0; i < part->indent; i++) + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, part->str->data); + removeTrailingSpaceFromStr(str); + + if (!last_part) + { + if (state->opts.pretty_print) + appendStringInfoChar(str, '\n'); + else if (str->data[str->len - 1] != '(') + appendStringInfoChar(str, ' '); + } + + freeDeparseStatePart(part); + } + list_free(state->result_parts); + state->result_parts = NIL; + + if (state->opts.pretty_print && state->opts.trailing_newline) + appendStringInfoChar(str, '\n'); +} + +static DeparseStateNestingLevel * +deparseStateIncreaseNestingLevel(DeparseState *state) +{ + DeparseStateNestingLevel *parent = state->current; + DeparseStateNestingLevel *level = palloc0(sizeof(DeparseStateNestingLevel)); + if (parent) + { + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + level->base_indent = parent->base_indent + state->opts.indent_size; + if (part_group->indent_mode != DEPARSE_PART_NO_INDENT) /* Indent again if parts next to us are also indented */ + level->base_indent += state->opts.indent_size; + + /* Parts with nested elements don't get merged, even if otherwise permitted */ + deparseMarkCurrentPartNonMergable(state); + } + state->current = level; + return parent; +} + +static void +deparseStateDecreaseNestingLevel(DeparseState *state, DeparseStateNestingLevel *parent_level) +{ + ListCell *lc; + ListCell *lc2; + DeparseStateNestingLevel *level = state->current; + Assert(level != NULL); + + foreach (lc, level->part_groups) + { + DeparseStatePartGroup *part_group = (DeparseStatePartGroup *) lfirst(lc); + + /* Merge parts */ + if (part_group->indent_mode == DEPARSE_PART_INDENT_AND_MERGE && list_length(part_group->parts) > 1) + { + DeparseStatePart *target = (DeparseStatePart *) linitial(part_group->parts); + for_each_from (lc2, part_group->parts, 1) + { + DeparseStatePart *part = (DeparseStatePart *) lfirst(lc2); + removeTrailingSpaceFromStr(target->str); + if (target->mergeable && part->mergeable && + target->indent + target->str->len + 1 + part->str->len <= state->opts.max_line_length) + { + if (target->str->len > 0 && target->str->data[target->str->len - 1] != '(') + appendStringInfoChar(target->str, ' '); + appendStringInfoString(target->str, part->str->data); + freeDeparseStatePart(part); + part_group->parts = foreach_delete_current(part_group->parts, lc2); + } + else + { + target = part; + } + } + } + + if (part_group->keyword != NULL) + { + DeparseStatePart *target = makeDeparseStatePart(state, level, false); + appendStringInfoString(target->str, part_group->keyword); + part_group->parts = list_insert_nth(part_group->parts, 0, target); + + if (list_length(part_group->parts) == 2 || part_group->indent_mode == DEPARSE_PART_NO_INDENT) + { + DeparseStatePart *part = (DeparseStatePart *) lsecond(part_group->parts); + if (part->str->len > 0) + appendStringInfo(target->str, " %s", part->str->data); + freeDeparseStatePart(part); + part_group->parts = list_delete_nth_cell(part_group->parts, 1); + } + } + + if (parent_level) + { + DeparseStatePartGroup *parent_part_group = (DeparseStatePartGroup *) llast(parent_level->part_groups); + parent_part_group->parts = list_concat(parent_part_group->parts, part_group->parts); + } + else + { + // If its the top level, save as results instead + state->result_parts = list_concat(state->result_parts, part_group->parts); + } + + list_free(part_group->parts); + pfree(part_group); + } + list_free(level->part_groups); + pfree(level); + + state->current = parent_level; + + if (parent_level) + { + /* Make sure parent statement writes that follow are on their own line */ + deparseAppendPart(state, true); + + /* Parts with nested elements don't get merged, even if otherwise permitted */ + deparseMarkCurrentPartNonMergable(state); + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies, and modified to work with deparser + * state. + */ +static void +deparseStringLiteral(DeparseState *state, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + deparseAppendStringInfoChar(state, ESCAPE_STRING_SYNTAX); + deparseAppendStringInfoChar(state, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + deparseAppendStringInfoChar(state, ch); + deparseAppendStringInfoChar(state, ch); + } + deparseAppendStringInfoChar(state, '\''); +} // "any_name" in gram.y -static void deparseAnyName(StringInfo str, List *parts) +static void deparseAnyName(DeparseState *state, List *parts) { ListCell *lc = NULL; foreach(lc, parts) { Assert(IsA(lfirst(lc), String)); - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(parts, lc)) - appendStringInfoChar(str, '.'); + deparseAppendStringInfoChar(state, '.'); } } -static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +static void deparseAnyNameSkipFirst(DeparseState *state, List *parts) { ListCell *lc = NULL; for_each_from(lc, parts, 1) { Assert(IsA(lfirst(lc), String)); - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(parts, lc)) - appendStringInfoChar(str, '.'); + deparseAppendStringInfoChar(state, '.'); } } -static void deparseAnyNameSkipLast(StringInfo str, List *parts) +static void deparseAnyNameSkipLast(DeparseState *state, List *parts) { ListCell *lc = NULL; @@ -253,50 +725,50 @@ static void deparseAnyNameSkipLast(StringInfo str, List *parts) { if (lnext(parts, lc)) { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (foreach_current_index(lc) < list_length(parts) - 2) - appendStringInfoChar(str, '.'); + deparseAppendStringInfoChar(state, '.'); } } } // "func_expr" in gram.y -static void deparseFuncExpr(StringInfo str, Node *node, DeparseNodeContext context) +static void deparseFuncExpr(DeparseState *state, Node *node, DeparseNodeContext context) { switch (nodeTag(node)) { case T_FuncCall: - deparseFuncCall(str, castNode(FuncCall, node), context); + deparseFuncCall(state, castNode(FuncCall, node), context); break; case T_SQLValueFunction: - deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); break; case T_MinMaxExpr: - deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); break; case T_CoalesceExpr: - deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); break; case T_XmlExpr: - deparseXmlExpr(str, castNode(XmlExpr, node), context); + deparseXmlExpr(state, castNode(XmlExpr, node), context); break; case T_XmlSerialize: - deparseXmlSerialize(str, castNode(XmlSerialize, node)); + deparseXmlSerialize(state, castNode(XmlSerialize, node)); break; case T_JsonObjectAgg: - deparseJsonObjectAgg(str, castNode(JsonObjectAgg, node)); + deparseJsonObjectAgg(state, castNode(JsonObjectAgg, node)); break; case T_JsonArrayAgg: - deparseJsonArrayAgg(str, castNode(JsonArrayAgg, node)); + deparseJsonArrayAgg(state, castNode(JsonArrayAgg, node)); break; case T_JsonObjectConstructor: - deparseJsonObjectConstructor(str, castNode(JsonObjectConstructor, node)); + deparseJsonObjectConstructor(state, castNode(JsonObjectConstructor, node)); break; case T_JsonArrayConstructor: - deparseJsonArrayConstructor(str, castNode(JsonArrayConstructor, node)); + deparseJsonArrayConstructor(state, castNode(JsonArrayConstructor, node)); break; case T_JsonArrayQueryConstructor: - deparseJsonArrayQueryConstructor(str, castNode(JsonArrayQueryConstructor, node)); + deparseJsonArrayQueryConstructor(state, castNode(JsonArrayQueryConstructor, node)); break; default: elog(ERROR, "deparse: unpermitted node type in func_expr: %d", @@ -305,10 +777,10 @@ static void deparseFuncExpr(StringInfo str, Node *node, DeparseNodeContext conte } } -static void deparseCExpr(StringInfo str, Node *node); +static void deparseCExpr(DeparseState *state, Node *node); // "a_expr" in gram.y -static void deparseExpr(StringInfo str, Node *node, DeparseNodeContext context) +static void deparseExpr(DeparseState *state, Node *node, DeparseNodeContext context) { if (node == NULL) return; @@ -323,46 +795,46 @@ static void deparseExpr(StringInfo str, Node *node, DeparseNodeContext context) case T_A_ArrayExpr: case T_RowExpr: case T_GroupingFunc: - deparseCExpr(str, node); + deparseCExpr(state, node); break; case T_TypeCast: - deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_CollateClause: - deparseCollateClause(str, castNode(CollateClause, node)); + deparseCollateClause(state, castNode(CollateClause, node)); break; case T_A_Expr: - deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAExpr(state, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_A_EXPR); break; case T_BoolExpr: - deparseBoolExpr(str, castNode(BoolExpr, node)); + deparseBoolExpr(state, castNode(BoolExpr, node)); break; case T_NullTest: - deparseNullTest(str, castNode(NullTest, node)); + deparseNullTest(state, castNode(NullTest, node)); break; case T_BooleanTest: - deparseBooleanTest(str, castNode(BooleanTest, node)); + deparseBooleanTest(state, castNode(BooleanTest, node)); break; case T_JsonIsPredicate: - deparseJsonIsPredicate(str, castNode(JsonIsPredicate, node)); + deparseJsonIsPredicate(state, castNode(JsonIsPredicate, node)); break; case T_SetToDefault: - deparseSetToDefault(str, castNode(SetToDefault, node)); + deparseSetToDefault(state, castNode(SetToDefault, node)); break; case T_MergeSupportFunc: - appendStringInfoString(str, "merge_action() "); + deparseAppendStringInfoString(state, "merge_action() "); break; case T_JsonParseExpr: - deparseJsonParseExpr(str, castNode(JsonParseExpr, node)); + deparseJsonParseExpr(state, castNode(JsonParseExpr, node)); break; case T_JsonScalarExpr: - deparseJsonScalarExpr(str, castNode(JsonScalarExpr, node)); + deparseJsonScalarExpr(state, castNode(JsonScalarExpr, node)); break; case T_JsonSerializeExpr: - deparseJsonSerializeExpr(str, castNode(JsonSerializeExpr, node)); + deparseJsonSerializeExpr(state, castNode(JsonSerializeExpr, node)); break; case T_JsonFuncExpr: - deparseJsonFuncExpr(str, castNode(JsonFuncExpr, node)); + deparseJsonFuncExpr(state, castNode(JsonFuncExpr, node)); break; case T_FuncCall: case T_SQLValueFunction: @@ -375,7 +847,7 @@ static void deparseExpr(StringInfo str, Node *node, DeparseNodeContext context) case T_JsonObjectConstructor: case T_JsonArrayConstructor: case T_JsonArrayQueryConstructor: - deparseFuncExpr(str, node, context); + deparseFuncExpr(state, node, context); break; default: // Note that this is also the fallthrough for deparseBExpr and deparseCExpr @@ -386,10 +858,10 @@ static void deparseExpr(StringInfo str, Node *node, DeparseNodeContext context) } // "b_expr" in gram.y -static void deparseBExpr(StringInfo str, Node *node) +static void deparseBExpr(DeparseState *state, Node *node) { if (IsA(node, XmlExpr)) { - deparseXmlExpr(str, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE); + deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE); return; } @@ -397,7 +869,7 @@ static void deparseBExpr(StringInfo str, Node *node) A_Expr *a_expr = castNode(A_Expr, node); // Other kinds are handled by "c_expr", with parens added around them if (a_expr->kind == AEXPR_OP || a_expr->kind == AEXPR_DISTINCT || a_expr->kind == AEXPR_NOT_DISTINCT) { - deparseAExpr(str, a_expr, DEPARSE_NODE_CONTEXT_NONE); + deparseAExpr(state, a_expr, DEPARSE_NODE_CONTEXT_NONE); return; } } @@ -405,24 +877,24 @@ static void deparseBExpr(StringInfo str, Node *node) if (IsA(node, BoolExpr)) { BoolExpr *bool_expr = castNode(BoolExpr, node); if (bool_expr->boolop == NOT_EXPR) { - deparseBoolExpr(str, bool_expr); + deparseBoolExpr(state, bool_expr); return; } } - deparseCExpr(str, node); + deparseCExpr(state, node); } // "AexprConst" in gram.y -static void deparseAexprConst(StringInfo str, Node *node) +static void deparseAexprConst(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_A_Const: - deparseAConst(str, castNode(A_Const, node)); + deparseAConst(state, castNode(A_Const, node)); break; case T_TypeCast: - deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); break; default: elog(ERROR, "deparse: unpermitted node type in AexprConst: %d", @@ -432,36 +904,36 @@ static void deparseAexprConst(StringInfo str, Node *node) } // "c_expr" in gram.y -static void deparseCExpr(StringInfo str, Node *node) +static void deparseCExpr(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_ColumnRef: - deparseColumnRef(str, castNode(ColumnRef, node)); + deparseColumnRef(state, castNode(ColumnRef, node)); break; case T_A_Const: - deparseAConst(str, castNode(A_Const, node)); + deparseAConst(state, castNode(A_Const, node)); break; case T_ParamRef: - deparseParamRef(str, castNode(ParamRef, node)); + deparseParamRef(state, castNode(ParamRef, node)); break; case T_A_Indirection: - deparseAIndirection(str, castNode(A_Indirection, node)); + deparseAIndirection(state, castNode(A_Indirection, node)); break; case T_CaseExpr: - deparseCaseExpr(str, castNode(CaseExpr, node)); + deparseCaseExpr(state, castNode(CaseExpr, node)); break; case T_SubLink: - deparseSubLink(str, castNode(SubLink, node)); + deparseSubLink(state, castNode(SubLink, node)); break; case T_A_ArrayExpr: - deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + deparseAArrayExpr(state, castNode(A_ArrayExpr, node)); break; case T_RowExpr: - deparseRowExpr(str, castNode(RowExpr, node)); + deparseRowExpr(state, castNode(RowExpr, node)); break; case T_GroupingFunc: - deparseGroupingFunc(str, castNode(GroupingFunc, node)); + deparseGroupingFunc(state, castNode(GroupingFunc, node)); break; case T_FuncCall: case T_SQLValueFunction: @@ -474,52 +946,52 @@ static void deparseCExpr(StringInfo str, Node *node) case T_JsonObjectConstructor: case T_JsonArrayConstructor: case T_JsonArrayQueryConstructor: - deparseFuncExpr(str, node, DEPARSE_NODE_CONTEXT_NONE); + deparseFuncExpr(state, node, DEPARSE_NODE_CONTEXT_NONE); break; default: - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); // Because we wrap this in parenthesis, the expression inside follows "a_expr" parser rules - deparseExpr(str, node, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); break; } } // "expr_list" in gram.y -static void deparseExprList(StringInfo str, List *exprs) +static void deparseExprList(DeparseState *state, List *exprs) { ListCell *lc; foreach(lc, exprs) { - deparseExpr(str, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (lnext(exprs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "ColId", "name", "database_name", "access_method" and "index_name" in gram.y -static void deparseColId(StringInfo str, char *s) +static void deparseColId(DeparseState *state, char *s) { - appendStringInfoString(str, quote_identifier(s)); + deparseAppendStringInfoString(state, quote_identifier(s)); } // "ColLabel", "attr_name" // // Note this is kept separate from ColId in case we ever want to be more // specific on how to handle keywords here -static void deparseColLabel(StringInfo str, char *s) +static void deparseColLabel(DeparseState *state, char *s) { - appendStringInfoString(str, quote_identifier(s)); + deparseAppendStringInfoString(state, quote_identifier(s)); } // "SignedIconst" and "Iconst" in gram.y -static void deparseSignedIconst(StringInfo str, Node *node) +static void deparseSignedIconst(DeparseState *state, Node *node) { - appendStringInfo(str, "%d", intVal(node)); + deparseAppendStringInfo(state, "%d", intVal(node)); } // "indirection" and "opt_indirection" in gram.y -static void deparseOptIndirection(StringInfo str, List *indirection, int N) +static void deparseOptIndirection(DeparseState *state, List *indirection, int N) { ListCell *lc = NULL; @@ -527,16 +999,16 @@ static void deparseOptIndirection(StringInfo str, List *indirection, int N) { if (IsA(lfirst(lc), String)) { - appendStringInfoChar(str, '.'); - deparseColLabel(str, strVal(lfirst(lc))); + deparseAppendStringInfoChar(state, '.'); + deparseColLabel(state, strVal(lfirst(lc))); } else if (IsA(lfirst(lc), A_Star)) { - appendStringInfoString(str, ".*"); + deparseAppendStringInfoString(state, ".*"); } else if (IsA(lfirst(lc), A_Indices)) { - deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + deparseAIndices(state, castNode(A_Indices, lfirst(lc))); } else { @@ -547,35 +1019,35 @@ static void deparseOptIndirection(StringInfo str, List *indirection, int N) } // "role_list" in gram.y -static void deparseRoleList(StringInfo str, List *roles) +static void deparseRoleList(DeparseState *state, List *roles) { ListCell *lc; foreach(lc, roles) { RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); - deparseRoleSpec(str, role_spec); + deparseRoleSpec(state, role_spec); if (lnext(roles, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "SimpleTypename" in gram.y -static void deparseSimpleTypename(StringInfo str, Node *node) +static void deparseSimpleTypename(DeparseState *state, Node *node) { - deparseTypeName(str, castNode(TypeName, node)); + deparseTypeName(state, castNode(TypeName, node)); } // "NumericOnly" in gram.y -static void deparseNumericOnly(StringInfo str, union ValUnion *value) +static void deparseNumericOnly(DeparseState *state, union ValUnion *value) { switch (nodeTag(value)) { case T_Integer: - appendStringInfo(str, "%d", value->ival.ival); + deparseAppendStringInfo(state, "%d", value->ival.ival); break; case T_Float: - appendStringInfoString(str, value->sval.sval); + deparseAppendStringInfoString(state, value->sval.sval); break; default: Assert(false); @@ -583,87 +1055,87 @@ static void deparseNumericOnly(StringInfo str, union ValUnion *value) } // "NumericOnly_list" in gram.y -static void deparseNumericOnlyList(StringInfo str, List *l) +static void deparseNumericOnlyList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { - deparseNumericOnly(str, (union ValUnion *) lfirst(lc)); + deparseNumericOnly(state, (union ValUnion *) lfirst(lc)); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "SeqOptElem" in gram.y -static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +static void deparseSeqOptElem(DeparseState *state, DefElem *def_elem) { ListCell *lc; if (strcmp(def_elem->defname, "as") == 0) { - appendStringInfoString(str, "AS "); - deparseSimpleTypename(str, def_elem->arg); + deparseAppendStringInfoString(state, "AS "); + deparseSimpleTypename(state, def_elem->arg); } else if (strcmp(def_elem->defname, "cache") == 0) { - appendStringInfoString(str, "CACHE "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "CACHE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "CYCLE"); + deparseAppendStringInfoString(state, "CYCLE"); } else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NO CYCLE"); + deparseAppendStringInfoString(state, "NO CYCLE"); } else if (strcmp(def_elem->defname, "increment") == 0) { - appendStringInfoString(str, "INCREMENT "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "INCREMENT "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) { - appendStringInfoString(str, "MAXVALUE "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "MAXVALUE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) { - appendStringInfoString(str, "NO MAXVALUE"); + deparseAppendStringInfoString(state, "NO MAXVALUE"); } else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) { - appendStringInfoString(str, "MINVALUE "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "MINVALUE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) { - appendStringInfoString(str, "NO MINVALUE"); + deparseAppendStringInfoString(state, "NO MINVALUE"); } else if (strcmp(def_elem->defname, "owned_by") == 0) { - appendStringInfoString(str, "OWNED BY "); - deparseAnyName(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "OWNED BY "); + deparseAnyName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "sequence_name") == 0) { - appendStringInfoString(str, "SEQUENCE NAME "); - deparseAnyName(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "SEQUENCE NAME "); + deparseAnyName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "start") == 0) { - appendStringInfoString(str, "START "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "START "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) { - appendStringInfoString(str, "RESTART"); + deparseAppendStringInfoString(state, "RESTART"); } else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) { - appendStringInfoString(str, "RESTART "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "RESTART "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else { @@ -672,37 +1144,37 @@ static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) } // "SeqOptList" in gram.y -static void deparseSeqOptList(StringInfo str, List *options) +static void deparseSeqOptList(DeparseState *state, List *options) { ListCell *lc; Assert(list_length(options) > 0); foreach (lc, options) { - deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseSeqOptElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } } // "OptSeqOptList" in gram.y -static void deparseOptSeqOptList(StringInfo str, List *options) +static void deparseOptSeqOptList(DeparseState *state, List *options) { if (list_length(options) > 0) - deparseSeqOptList(str, options); + deparseSeqOptList(state, options); } // "OptParenthesizedSeqOptList" in gram.y -static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +static void deparseOptParenthesizedSeqOptList(DeparseState *state, List *options) { if (list_length(options) > 0) { - appendStringInfoChar(str, '('); - deparseSeqOptList(str, options); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseSeqOptList(state, options); + deparseAppendStringInfoChar(state, ')'); } } // "opt_drop_behavior" in gram.y -static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +static void deparseOptDropBehavior(DeparseState *state, DropBehavior behavior) { switch (behavior) { @@ -710,24 +1182,24 @@ static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) // Default break; case DROP_CASCADE: - appendStringInfoString(str, "CASCADE "); + deparseAppendStringInfoString(state, "CASCADE "); break; } } // "any_operator" in gram.y -static void deparseAnyOperator(StringInfo str, List *op) +static void deparseAnyOperator(DeparseState *state, List *op) { Assert(isOp(strVal(llast(op)))); if (list_length(op) == 2) { - appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); - appendStringInfoChar(str, '.'); - appendStringInfoString(str, strVal(llast(op))); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(op)))); + deparseAppendStringInfoChar(state, '.'); + deparseAppendStringInfoString(state, strVal(llast(op))); } else if (list_length(op) == 1) { - appendStringInfoString(str, strVal(llast(op))); + deparseAppendStringInfoString(state, strVal(llast(op))); } else { @@ -736,68 +1208,68 @@ static void deparseAnyOperator(StringInfo str, List *op) } // "qual_Op" and "qual_all_Op" in gram.y -static void deparseQualOp(StringInfo str, List *op) +static void deparseQualOp(DeparseState *state, List *op) { if (list_length(op) == 1 && isOp(strVal(linitial(op)))) { - appendStringInfoString(str, strVal(linitial(op))); + deparseAppendStringInfoString(state, strVal(linitial(op))); } else { - appendStringInfoString(str, "OPERATOR("); - deparseAnyOperator(str, op); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, op); + deparseAppendStringInfoString(state, ")"); } } // "subquery_Op" in gram.y -static void deparseSubqueryOp(StringInfo str, List *op) +static void deparseSubqueryOp(DeparseState *state, List *op) { if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) { - appendStringInfoString(str, "LIKE"); + deparseAppendStringInfoString(state, "LIKE"); } else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) { - appendStringInfoString(str, "NOT LIKE"); + deparseAppendStringInfoString(state, "NOT LIKE"); } else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) { - appendStringInfoString(str, "ILIKE"); + deparseAppendStringInfoString(state, "ILIKE"); } else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) { - appendStringInfoString(str, "NOT ILIKE"); + deparseAppendStringInfoString(state, "NOT ILIKE"); } else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) { - appendStringInfoString(str, strVal(linitial(op))); + deparseAppendStringInfoString(state, strVal(linitial(op))); } else { - appendStringInfoString(str, "OPERATOR("); - deparseAnyOperator(str, op); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, op); + deparseAppendStringInfoString(state, ")"); } } // Not present directly in gram.y (usually matched by ColLabel) -static void deparseGenericDefElemName(StringInfo str, const char *in) +static void deparseGenericDefElemName(DeparseState *state, const char *in) { Assert(in != NULL); char *val = pstrdup(in); for (unsigned char *p = (unsigned char *) val; *p; p++) *p = pg_toupper(*p); - appendStringInfoString(str, val); + deparseAppendStringInfoString(state, val); pfree(val); } // "def_arg" and "operator_def_arg" in gram.y -static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +static void deparseDefArg(DeparseState *state, Node *arg, bool is_operator_def_arg) { if (IsA(arg, TypeName)) // func_type { - deparseTypeName(str, castNode(TypeName, arg)); + deparseTypeName(state, castNode(TypeName, arg)); } else if (IsA(arg, List)) // qual_all_Op { @@ -807,33 +1279,33 @@ static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) // Schema qualified operator if (list_length(l) == 2) { - appendStringInfoString(str, "OPERATOR("); - deparseAnyOperator(str, l); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, l); + deparseAppendStringInfoChar(state, ')'); } else if (list_length(l) == 1) { - appendStringInfoString(str, strVal(linitial(l))); + deparseAppendStringInfoString(state, strVal(linitial(l))); } } else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly { - deparseValue(str, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); + deparseValue(state, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); } else if (IsA(arg, String)) { char *s = strVal(arg); if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE { - appendStringInfoString(str, "NONE"); + deparseAppendStringInfoString(state, "NONE"); } else if (isReservedKeyword(s)) // reserved_keyword { - appendStringInfoString(str, s); + deparseAppendStringInfoString(state, s); } else // Sconst { - deparseStringLiteral(str, s); + deparseStringLiteral(state, s); } } else @@ -843,121 +1315,121 @@ static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) } // "definition" in gram.y -static void deparseDefinition(StringInfo str, List *options) +static void deparseDefinition(DeparseState *state, List *options) { ListCell *lc = NULL; - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach (lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); - appendStringInfoString(str, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); if (def_elem->arg != NULL) { - appendStringInfoString(str, " = "); - deparseDefArg(str, def_elem->arg, false); + deparseAppendStringInfoString(state, " = "); + deparseDefArg(state, def_elem->arg, false); } if (lnext(options, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } // "opt_definition" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseOptDefinition(StringInfo str, List *options) +static void deparseOptDefinition(DeparseState *state, List *options) { if (list_length(options) > 0) { - appendStringInfoString(str, "WITH "); - deparseDefinition(str, options); + deparseAppendStringInfoString(state, "WITH "); + deparseDefinition(state, options); } } // "create_generic_options" in gram.y -static void deparseCreateGenericOptions(StringInfo str, List *options) +static void deparseCreateGenericOptions(DeparseState *state, List *options) { ListCell *lc = NULL; if (options == NULL) return; - appendStringInfoString(str, "OPTIONS ("); + deparseAppendStringInfoString(state, "OPTIONS ("); foreach(lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); if (lnext(options, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ")"); } // "common_func_opt_item" in gram.y -static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +static void deparseCommonFuncOptItem(DeparseState *state, DefElem *def_elem) { if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + deparseAppendStringInfoString(state, "RETURNS NULL ON NULL INPUT"); } else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "CALLED ON NULL INPUT"); + deparseAppendStringInfoString(state, "CALLED ON NULL INPUT"); } else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) { - appendStringInfoString(str, "IMMUTABLE"); + deparseAppendStringInfoString(state, "IMMUTABLE"); } else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) { - appendStringInfoString(str, "STABLE"); + deparseAppendStringInfoString(state, "STABLE"); } else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) { - appendStringInfoString(str, "VOLATILE"); + deparseAppendStringInfoString(state, "VOLATILE"); } else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "SECURITY DEFINER"); + deparseAppendStringInfoString(state, "SECURITY DEFINER"); } else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "SECURITY INVOKER"); + deparseAppendStringInfoString(state, "SECURITY INVOKER"); } else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "LEAKPROOF"); + deparseAppendStringInfoString(state, "LEAKPROOF"); } else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOT LEAKPROOF"); + deparseAppendStringInfoString(state, "NOT LEAKPROOF"); } else if (strcmp(def_elem->defname, "cost") == 0) { - appendStringInfoString(str, "COST "); - deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "COST "); + deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); } else if (strcmp(def_elem->defname, "rows") == 0) { - appendStringInfoString(str, "ROWS "); - deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "ROWS "); + deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); } else if (strcmp(def_elem->defname, "support") == 0) { - appendStringInfoString(str, "SUPPORT "); - deparseAnyName(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "SUPPORT "); + deparseAnyName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause { - deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + deparseVariableSetStmt(state, castNode(VariableSetStmt, def_elem->arg)); } else if (strcmp(def_elem->defname, "parallel") == 0) { - appendStringInfoString(str, "PARALLEL "); - appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + deparseAppendStringInfoString(state, "PARALLEL "); + deparseAppendStringInfoString(state, quote_identifier(strVal(def_elem->arg))); } else { @@ -972,18 +1444,18 @@ static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) // // 1) when the string is empty (since an empty identifier can't be scanned) // 2) when the value is equal or larger than NAMEDATALEN (64+ characters) -static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +static void deparseNonReservedWordOrSconst(DeparseState *state, const char *val) { if (strlen(val) == 0) - appendStringInfoString(str, "''"); + deparseAppendStringInfoString(state, "''"); else if (strlen(val) >= NAMEDATALEN) - deparseStringLiteral(str, val); + deparseStringLiteral(state, val); else - appendStringInfoString(str, quote_identifier(val)); + deparseAppendStringInfoString(state, quote_identifier(val)); } // "func_as" in gram.y -static void deparseFuncAs(StringInfo str, List *l) +static void deparseFuncAs(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -992,119 +1464,119 @@ static void deparseFuncAs(StringInfo str, List *l) char *strval = strVal(lfirst(lc)); if (strstr(strval, "$$") == NULL) { - appendStringInfoString(str, "$$"); - appendStringInfoString(str, strval); - appendStringInfoString(str, "$$"); + deparseAppendStringInfoString(state, "$$"); + deparseAppendStringInfoString(state, strval); + deparseAppendStringInfoString(state, "$$"); } else { - deparseStringLiteral(str, strval); + deparseStringLiteral(state, strval); } if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "createfunc_opt_item" in gram.y -static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +static void deparseCreateFuncOptItem(DeparseState *state, DefElem *def_elem) { ListCell *lc = NULL; if (strcmp(def_elem->defname, "as") == 0) { - appendStringInfoString(str, "AS "); - deparseFuncAs(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "AS "); + deparseFuncAs(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "language") == 0) { - appendStringInfoString(str, "LANGUAGE "); - deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "transform") == 0) { List *l = castNode(List, def_elem->arg); - appendStringInfoString(str, "TRANSFORM "); + deparseAppendStringInfoString(state, "TRANSFORM "); foreach (lc, l) { - appendStringInfoString(str, "FOR TYPE "); - deparseTypeName(str, castNode(TypeName, lfirst(lc))); + deparseAppendStringInfoString(state, "FOR TYPE "); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } else if (strcmp(def_elem->defname, "window") == 0) { - appendStringInfoString(str, "WINDOW"); + deparseAppendStringInfoString(state, "WINDOW"); } else { - deparseCommonFuncOptItem(str, def_elem); + deparseCommonFuncOptItem(state, def_elem); } } // "alter_generic_options" in gram.y -static void deparseAlterGenericOptions(StringInfo str, List *options) +static void deparseAlterGenericOptions(DeparseState *state, List *options) { ListCell *lc = NULL; - appendStringInfoString(str, "OPTIONS ("); + deparseAppendStringInfoString(state, "OPTIONS ("); foreach(lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); switch (def_elem->defaction) { case DEFELEM_UNSPEC: - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); break; case DEFELEM_SET: - appendStringInfoString(str, "SET "); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "SET "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); break; case DEFELEM_ADD: - appendStringInfoString(str, "ADD "); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "ADD "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); break; case DEFELEM_DROP: - appendStringInfoString(str, "DROP "); - appendStringInfoString(str, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, "DROP "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); break; } if (lnext(options, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } // "func_name" in gram.y -static void deparseFuncName(StringInfo str, List *func_name) +static void deparseFuncName(DeparseState *state, List *func_name) { ListCell *lc = NULL; foreach(lc, func_name) { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(func_name, lc)) - appendStringInfoChar(str, '.'); + deparseAppendStringInfoChar(state, '.'); } } // "function_with_argtypes" in gram.y -static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +static void deparseFunctionWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) { ListCell *lc; - deparseFuncName(str, object_with_args->objname); + deparseFuncName(state, object_with_args->objname); if (!object_with_args->args_unspecified) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); List *objargs = object_with_args->objargs; if (object_with_args->objfuncargs) objargs = object_with_args->objfuncargs; @@ -1112,50 +1584,50 @@ static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_w foreach(lc, objargs) { if (IsA(lfirst(lc), FunctionParameter)) - deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); else - deparseTypeName(str, castNode(TypeName, lfirst(lc))); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(objargs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } } // "function_with_argtypes_list" in gram.y -static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +static void deparseFunctionWithArgtypesList(DeparseState *state, List *l) { ListCell *lc; foreach(lc, l) { - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "operator_with_argtypes" in gram.y -static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +static void deparseOperatorWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) { - deparseAnyOperator(str, object_with_args->objname); + deparseAnyOperator(state, object_with_args->objname); Assert(list_length(object_with_args->objargs) == 2); - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); if (linitial(object_with_args->objargs) == NULL) - appendStringInfoString(str, "NONE"); + deparseAppendStringInfoString(state, "NONE"); else - deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); - appendStringInfoString(str, ", "); + deparseTypeName(state, castNode(TypeName, linitial(object_with_args->objargs))); + deparseAppendStringInfoString(state, ", "); if (lsecond(object_with_args->objargs) == NULL) - appendStringInfoString(str, "NONE"); + deparseAppendStringInfoString(state, "NONE"); else - deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); - appendStringInfoChar(str, ')'); + deparseTypeName(state, castNode(TypeName, lsecond(object_with_args->objargs))); + deparseAppendStringInfoChar(state, ')'); } // "aggr_args" in gram.y -static void deparseAggrArgs(StringInfo str, List *aggr_args) +static void deparseAggrArgs(DeparseState *state, List *aggr_args) { Assert(list_length(aggr_args) == 2); @@ -1163,10 +1635,10 @@ static void deparseAggrArgs(StringInfo str, List *aggr_args) List *args = linitial(aggr_args); int order_by_pos = intVal(lsecond(aggr_args)); - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); if (args == NULL) { - appendStringInfoChar(str, '*'); + deparseAppendStringInfoChar(state, '*'); } else { @@ -1175,39 +1647,39 @@ static void deparseAggrArgs(StringInfo str, List *aggr_args) if (foreach_current_index(lc) == order_by_pos) { if (foreach_current_index(lc) > 0) - appendStringInfoChar(str, ' '); - appendStringInfoString(str, "ORDER BY "); + deparseAppendStringInfoChar(state, ' '); + deparseAppendStringInfoString(state, "ORDER BY "); } else if (foreach_current_index(lc) > 0) { - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); } // Repeat the last direct arg as a ordered arg to handle the // simplification done by makeOrderedSetArgs in gram.y if (order_by_pos == list_length(args)) { - appendStringInfoString(str, " ORDER BY "); - deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + deparseAppendStringInfoString(state, " ORDER BY "); + deparseFunctionParameter(state, castNode(FunctionParameter, llast(args))); } } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } // "aggregate_with_argtypes" in gram.y -static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +static void deparseAggregateWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) { ListCell *lc = NULL; - deparseFuncName(str, object_with_args->objname); + deparseFuncName(state, object_with_args->objname); - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) { - appendStringInfoChar(str, '*'); + deparseAppendStringInfoChar(state, '*'); } else { @@ -1218,32 +1690,32 @@ static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_ foreach(lc, objargs) { if (IsA(lfirst(lc), FunctionParameter)) - deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); else - deparseTypeName(str, castNode(TypeName, lfirst(lc))); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(objargs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } // "columnList" in gram.y -static void deparseColumnList(StringInfo str, List *columns) +static void deparseColumnList(DeparseState *state, List *columns) { ListCell *lc = NULL; foreach(lc, columns) { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(columns, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "OptTemp" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseOptTemp(StringInfo str, char relpersistence) +static void deparseOptTemp(DeparseState *state, char relpersistence) { switch (relpersistence) { @@ -1251,10 +1723,10 @@ static void deparseOptTemp(StringInfo str, char relpersistence) // Default break; case RELPERSISTENCE_UNLOGGED: - appendStringInfoString(str, "UNLOGGED "); + deparseAppendStringInfoString(state, "UNLOGGED "); break; case RELPERSISTENCE_TEMP: - appendStringInfoString(str, "TEMPORARY "); + deparseAppendStringInfoString(state, "TEMPORARY "); break; default: Assert(false); @@ -1263,32 +1735,32 @@ static void deparseOptTemp(StringInfo str, char relpersistence) } // "relation_expr_list" in gram.y -static void deparseRelationExprList(StringInfo str, List *relation_exprs) +static void deparseRelationExprList(DeparseState *state, List *relation_exprs) { ListCell *lc = NULL; foreach(lc, relation_exprs) { - deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); if (lnext(relation_exprs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "handler_name" in gram.y -static void deparseHandlerName(StringInfo str, List *handler_name) +static void deparseHandlerName(DeparseState *state, List *handler_name) { ListCell *lc = NULL; foreach(lc, handler_name) { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(handler_name, lc)) - appendStringInfoChar(str, '.'); + deparseAppendStringInfoChar(state, '.'); } } // "fdw_options" in gram.y -static void deparseFdwOptions(StringInfo str, List *fdw_options) +static void deparseFdwOptions(DeparseState *state, List *fdw_options) { ListCell *lc = NULL; @@ -1297,21 +1769,21 @@ static void deparseFdwOptions(StringInfo str, List *fdw_options) DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) { - appendStringInfoString(str, "HANDLER "); - deparseHandlerName(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) { - appendStringInfoString(str, "NO HANDLER "); + deparseAppendStringInfoString(state, "NO HANDLER "); } else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) { - appendStringInfoString(str, "VALIDATOR "); - deparseHandlerName(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "VALIDATOR "); + deparseHandlerName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) { - appendStringInfoString(str, "NO VALIDATOR "); + deparseAppendStringInfoString(state, "NO VALIDATOR "); } else { @@ -1319,40 +1791,40 @@ static void deparseFdwOptions(StringInfo str, List *fdw_options) } if (lnext(fdw_options, lc)) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } // "type_list" in gram.y -static void deparseTypeList(StringInfo str, List *type_list) +static void deparseTypeList(DeparseState *state, List *type_list) { ListCell *lc = NULL; foreach(lc, type_list) { - deparseTypeName(str, castNode(TypeName, lfirst(lc))); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(type_list, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "opt_boolean_or_string" in gram.y -static void deparseOptBooleanOrString(StringInfo str, char *s) +static void deparseOptBooleanOrString(DeparseState *state, char *s) { if (s == NULL) return; // No value set else if (strcmp(s, "true") == 0) - appendStringInfoString(str, "TRUE"); + deparseAppendStringInfoString(state, "TRUE"); else if (strcmp(s, "false") == 0) - appendStringInfoString(str, "FALSE"); + deparseAppendStringInfoString(state, "FALSE"); else if (strcmp(s, "on") == 0) - appendStringInfoString(str, "ON"); + deparseAppendStringInfoString(state, "ON"); else if (strcmp(s, "off") == 0) - appendStringInfoString(str, "OFF"); + deparseAppendStringInfoString(state, "OFF"); else - deparseNonReservedWordOrSconst(str, s); + deparseNonReservedWordOrSconst(state, s); } -static void deparseOptBoolean(StringInfo str, Node *node) +static void deparseOptBoolean(DeparseState *state, Node *node) { if (node == NULL) { @@ -1362,13 +1834,13 @@ static void deparseOptBoolean(StringInfo str, Node *node) switch (nodeTag(node)) { case T_String: - appendStringInfo(str, " %s", strVal(node)); + deparseAppendStringInfo(state, " %s", strVal(node)); break; case T_Integer: - appendStringInfo(str, " %d", intVal(node)); + deparseAppendStringInfo(state, " %d", intVal(node)); break; case T_Boolean: - appendStringInfo(str, " %s", boolVal(node) ? "TRUE" : "FALSE"); + deparseAppendStringInfo(state, " %s", boolVal(node) ? "TRUE" : "FALSE"); break; default: Assert(false); @@ -1414,13 +1886,13 @@ bool optBooleanValue(Node *node) // // Note this is kept separate from ColId in case we want to improve the // output of namespaced variable names -static void deparseVarName(StringInfo str, char *s) +static void deparseVarName(DeparseState *state, char *s) { - deparseColId(str, s); + deparseColId(state, s); } // "var_list" -static void deparseVarList(StringInfo str, List *l) +static void deparseVarList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1428,21 +1900,21 @@ static void deparseVarList(StringInfo str, List *l) { if (IsA(lfirst(lc), ParamRef)) { - deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + deparseParamRef(state, castNode(ParamRef, lfirst(lc))); } else if (IsA(lfirst(lc), A_Const)) { A_Const *a_const = castNode(A_Const, lfirst(lc)); if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) - deparseNumericOnly(str, (union ValUnion *) &a_const->val); + deparseNumericOnly(state, (union ValUnion *) &a_const->val); else if (IsA(&a_const->val, String)) - deparseOptBooleanOrString(str, strVal(&a_const->val)); + deparseOptBooleanOrString(state, strVal(&a_const->val)); else Assert(false); } else if (IsA(lfirst(lc), TypeCast)) { - deparseTypeCast(str, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); + deparseTypeCast(state, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); } else { @@ -1450,12 +1922,12 @@ static void deparseVarList(StringInfo str, List *l) } if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "transaction_mode_list" in gram.y -static void deparseTransactionModeList(StringInfo str, List *l) +static void deparseTransactionModeList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1466,33 +1938,33 @@ static void deparseTransactionModeList(StringInfo str, List *l) if (strcmp(def_elem->defname, "transaction_isolation") == 0) { char *s = strVal(&castNode(A_Const, def_elem->arg)->val); - appendStringInfoString(str, "ISOLATION LEVEL "); + deparseAppendStringInfoString(state, "ISOLATION LEVEL "); if (strcmp(s, "read uncommitted") == 0) - appendStringInfoString(str, "READ UNCOMMITTED"); + deparseAppendStringInfoString(state, "READ UNCOMMITTED"); else if (strcmp(s, "read committed") == 0) - appendStringInfoString(str, "READ COMMITTED"); + deparseAppendStringInfoString(state, "READ COMMITTED"); else if (strcmp(s, "repeatable read") == 0) - appendStringInfoString(str, "REPEATABLE READ"); + deparseAppendStringInfoString(state, "REPEATABLE READ"); else if (strcmp(s, "serializable") == 0) - appendStringInfoString(str, "SERIALIZABLE"); + deparseAppendStringInfoString(state, "SERIALIZABLE"); else Assert(false); } else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) { - appendStringInfoString(str, "READ ONLY"); + deparseAppendStringInfoString(state, "READ ONLY"); } else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) { - appendStringInfoString(str, "READ WRITE"); + deparseAppendStringInfoString(state, "READ WRITE"); } else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) { - appendStringInfoString(str, "DEFERRABLE"); + deparseAppendStringInfoString(state, "DEFERRABLE"); } else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) { - appendStringInfoString(str, "NOT DEFERRABLE"); + deparseAppendStringInfoString(state, "NOT DEFERRABLE"); } else { @@ -1500,12 +1972,12 @@ static void deparseTransactionModeList(StringInfo str, List *l) } if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "alter_identity_column_option_list" in gram.y -static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +static void deparseAlterIdentityColumnOptionList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1514,79 +1986,79 @@ static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) { - appendStringInfoString(str, "RESTART"); + deparseAppendStringInfoString(state, "RESTART"); } else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) { - appendStringInfoString(str, "RESTART "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseAppendStringInfoString(state, "RESTART "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "generated") == 0) { - appendStringInfoString(str, "SET GENERATED "); + deparseAppendStringInfoString(state, "SET GENERATED "); if (def_elem->arg == NULL) elog(ERROR, "deparse: missing argument for identity generation specification"); if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) - appendStringInfoString(str, "ALWAYS"); + deparseAppendStringInfoString(state, "ALWAYS"); else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) - appendStringInfoString(str, "BY DEFAULT"); + deparseAppendStringInfoString(state, "BY DEFAULT"); else Assert(false); } else { - appendStringInfoString(str, "SET "); - deparseSeqOptElem(str, def_elem); + deparseAppendStringInfoString(state, "SET "); + deparseSeqOptElem(state, def_elem); } if (lnext(l, lc)) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } // "reloptions" in gram.y -static void deparseRelOptions(StringInfo str, List *l) +static void deparseRelOptions(DeparseState *state, List *l) { ListCell *lc = NULL; - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, l) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (def_elem->defnamespace != NULL) { - appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); - appendStringInfoChar(str, '.'); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defnamespace)); + deparseAppendStringInfoChar(state, '.'); } if (def_elem->defname != NULL) - appendStringInfoString(str, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); if (def_elem->defname != NULL && def_elem->arg != NULL) - appendStringInfoChar(str, '='); + deparseAppendStringInfoChar(state, '='); if (def_elem->arg != NULL) - deparseDefArg(str, def_elem->arg, false); + deparseDefArg(state, def_elem->arg, false); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } // "OptWith" and "opt_reloptions" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseOptWith(StringInfo str, List *l) +static void deparseOptWith(DeparseState *state, List *l) { ListCell *lc = NULL; if (list_length(l) > 0) { - appendStringInfoString(str, "WITH "); - deparseRelOptions(str, l); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "WITH "); + deparseRelOptions(state, l); + deparseAppendStringInfoChar(state, ' '); } } // "target_list" and "opt_target_list" in gram.y -static void deparseTargetList(StringInfo str, List *l) +static void deparseTargetList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1597,22 +2069,22 @@ static void deparseTargetList(StringInfo str, List *l) if (res_target->val == NULL) elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); else if (IsA(res_target->val, ColumnRef)) - deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + deparseColumnRef(state, castNode(ColumnRef, res_target->val)); else - deparseExpr(str, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); if (res_target->name != NULL) { - appendStringInfoString(str, " AS "); - appendStringInfoString(str, quote_identifier(res_target->name)); + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); } if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } } // "insert_column_list" in gram.y -static void deparseInsertColumnList(StringInfo str, List *l) +static void deparseInsertColumnList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1620,15 +2092,15 @@ static void deparseInsertColumnList(StringInfo str, List *l) { ResTarget *res_target = castNode(ResTarget, lfirst(lc)); Assert(res_target->name != NULL); - appendStringInfoString(str, quote_identifier(res_target->name)); - deparseOptIndirection(str, res_target->indirection, 0); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + deparseOptIndirection(state, res_target->indirection, 0); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "xml_attribute_list" in gram.y -static void deparseXmlAttributeList(StringInfo str, List *l) +static void deparseXmlAttributeList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1637,21 +2109,21 @@ static void deparseXmlAttributeList(StringInfo str, List *l) ResTarget *res_target = castNode(ResTarget, lfirst(lc)); Assert(res_target->val != NULL); - deparseExpr(str, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); if (res_target->name != NULL) { - appendStringInfoString(str, " AS "); - appendStringInfoString(str, quote_identifier(res_target->name)); + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); } if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "xml_namespace_list" in gram.y -static void deparseXmlNamespaceList(StringInfo str, List *l) +static void deparseXmlNamespaceList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -1661,46 +2133,46 @@ static void deparseXmlNamespaceList(StringInfo str, List *l) Assert(res_target->val != NULL); if (res_target->name == NULL) - appendStringInfoString(str, "DEFAULT "); + deparseAppendStringInfoString(state, "DEFAULT "); - deparseExpr(str, res_target->val, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); if (res_target->name != NULL) { - appendStringInfoString(str, " AS "); - appendStringInfoString(str, quote_identifier(res_target->name)); + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); } if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "table_ref" in gram.y -static void deparseTableRef(StringInfo str, Node *node) +static void deparseTableRef(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_RangeVar: - deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_RangeTableSample: - deparseRangeTableSample(str, castNode(RangeTableSample, node)); + deparseRangeTableSample(state, castNode(RangeTableSample, node)); break; case T_RangeFunction: - deparseRangeFunction(str, castNode(RangeFunction, node)); + deparseRangeFunction(state, castNode(RangeFunction, node)); break; case T_RangeTableFunc: - deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + deparseRangeTableFunc(state, castNode(RangeTableFunc, node)); break; case T_RangeSubselect: - deparseRangeSubselect(str, castNode(RangeSubselect, node)); + deparseRangeSubselect(state, castNode(RangeSubselect, node)); break; case T_JoinExpr: - deparseJoinExpr(str, castNode(JoinExpr, node)); + deparseJoinExpr(state, castNode(JoinExpr, node)); break; case T_JsonTable: - deparseJsonTable(str, castNode(JsonTable, node)); + deparseJsonTable(state, castNode(JsonTable, node)); break; default: Assert(false); @@ -1708,155 +2180,163 @@ static void deparseTableRef(StringInfo str, Node *node) } // "from_list" in gram.y -static void deparseFromList(StringInfo str, List *l) +static void deparseFromList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { - deparseTableRef(str, lfirst(lc)); + deparseTableRef(state, lfirst(lc)); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } } // "from_clause" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseFromClause(StringInfo str, List *l) +static void deparseFromClause(DeparseState *state, List *l) { if (list_length(l) > 0) { - appendStringInfoString(str, "FROM "); - deparseFromList(str, l); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "FROM", DEPARSE_PART_INDENT); + deparseFromList(state, l); + deparseAppendStringInfoChar(state, ' '); } } // "where_clause" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseWhereClause(StringInfo str, Node *node) +static void deparseWhereClause(DeparseState *state, Node *node) { if (node != NULL) { - appendStringInfoString(str, "WHERE "); - deparseExpr(str, node, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } } // "where_or_current_clause" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseWhereOrCurrentClause(StringInfo str, Node *node) +static void deparseWhereOrCurrentClause(DeparseState *state, Node *node) { if (node == NULL) return; - appendStringInfoString(str, "WHERE "); + deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); if (IsA(node, CurrentOfExpr)) { CurrentOfExpr *current_of_expr = castNode(CurrentOfExpr, node); - appendStringInfoString(str, "CURRENT OF "); - appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); + deparseAppendStringInfoString(state, "CURRENT OF "); + deparseAppendStringInfoString(state, quote_identifier(current_of_expr->cursor_name)); } else { - deparseExpr(str, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } // "group_by_list" in gram.y -static void deparseGroupByList(StringInfo str, List *l) +static void deparseGroupByList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { if (IsA(lfirst(lc), GroupingSet)) - deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + deparseGroupingSet(state, castNode(GroupingSet, lfirst(lc))); else - deparseExpr(str, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } } // "set_target" in gram.y -static void deparseSetTarget(StringInfo str, ResTarget *res_target) +static void deparseSetTarget(DeparseState *state, ResTarget *res_target) { Assert(res_target->name != NULL); - deparseColId(str, res_target->name); - deparseOptIndirection(str, res_target->indirection, 0); + deparseColId(state, res_target->name); + deparseOptIndirection(state, res_target->indirection, 0); } // "any_name_list" in gram.y -static void deparseAnyNameList(StringInfo str, List *l) +static void deparseAnyNameList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { - deparseAnyName(str, castNode(List, lfirst(lc))); + deparseAnyName(state, castNode(List, lfirst(lc))); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "name_list" in gram.y -static void deparseNameList(StringInfo str, List *l) +static void deparseNameList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { - deparseColId(str, strVal(lfirst(lc))); + deparseColId(state, strVal(lfirst(lc))); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "opt_sort_clause" and "json_array_aggregate_order_by_clause_opt" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseOptSortClause(StringInfo str, List *l) +static void deparseOptSortClause(DeparseState *state, List *l, DeparseNodeContext context) { ListCell *lc = NULL; if (list_length(l) > 0) { - appendStringInfoString(str, "ORDER BY "); + if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) + deparseAppendPartGroup(state, "ORDER BY", DEPARSE_PART_INDENT_AND_MERGE); + else + deparseAppendStringInfoString(state, "ORDER BY "); foreach(lc, l) { - deparseSortBy(str, castNode(SortBy, lfirst(lc))); + deparseSortBy(state, castNode(SortBy, lfirst(lc))); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + { + if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) + deparseAppendCommaAndPart(state); + else + deparseAppendStringInfoString(state, ", "); + } } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } // "func_arg_expr" in gram.y -static void deparseFuncArgExpr(StringInfo str, Node *node) +static void deparseFuncArgExpr(DeparseState *state, Node *node) { if (IsA(node, NamedArgExpr)) { NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); - appendStringInfoString(str, named_arg_expr->name); - appendStringInfoString(str, " := "); - deparseExpr(str, (Node *) named_arg_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, named_arg_expr->name); + deparseAppendStringInfoString(state, " := "); + deparseExpr(state, (Node *) named_arg_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); } else { - deparseExpr(str, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); } } // "set_clause_list" in gram.y -static void deparseSetClauseList(StringInfo str, List *target_list) +static void deparseSetClauseList(DeparseState *state, List *target_list) { ListCell *lc; ListCell *lc2; @@ -1873,7 +2353,7 @@ static void deparseSetClauseList(StringInfo str, List *target_list) } if (foreach_current_index(lc) != 0) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); ResTarget *res_target = castNode(ResTarget, lfirst(lc)); Assert(res_target->val != NULL); @@ -1881,53 +2361,53 @@ static void deparseSetClauseList(StringInfo str, List *target_list) if (IsA(res_target->val, MultiAssignRef)) { MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); - appendStringInfoString(str, "("); + deparseAppendStringInfoString(state, "("); for_each_cell(lc2, target_list, lc) { - deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); - if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign + deparseSetTarget(state, castNode(ResTarget, lfirst(lc2))); + if ((foreach_current_index(lc2) - foreach_current_index(lc)) == r->ncolumns - 1) // Last element in this multi-assign break; else if (lnext(target_list, lc2)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") = "); - deparseExpr(str, r->source, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") = "); + deparseExpr(state, r->source, DEPARSE_NODE_CONTEXT_A_EXPR); skip_next_n_elems = r->ncolumns - 1; } else { - deparseSetTarget(str, res_target); - appendStringInfoString(str, " = "); - deparseExpr(str, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseSetTarget(state, res_target); + deparseAppendStringInfoString(state, " = "); + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); } } } // "func_expr_windowless" in gram.y -static void deparseFuncExprWindowless(StringInfo str, Node* node) +static void deparseFuncExprWindowless(DeparseState *state, Node* node) { switch (nodeTag(node)) { case T_FuncCall: - deparseFuncCall(str, castNode(FuncCall, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); + deparseFuncCall(state, castNode(FuncCall, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); break; case T_SQLValueFunction: - deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); break; case T_TypeCast: - deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); break; case T_CoalesceExpr: - deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); break; case T_MinMaxExpr: - deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); break; case T_XmlExpr: - deparseXmlExpr(str, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); + deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); break; case T_XmlSerialize: - deparseXmlSerialize(str, castNode(XmlSerialize, node)); + deparseXmlSerialize(state, castNode(XmlSerialize, node)); break; default: Assert(false); @@ -1937,23 +2417,23 @@ static void deparseFuncExprWindowless(StringInfo str, Node* node) // "opt_collate" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseOptCollate(StringInfo str, List *l) +static void deparseOptCollate(DeparseState *state, List *l) { if (list_length(l) > 0) { - appendStringInfoString(str, "COLLATE "); - deparseAnyName(str, l); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "COLLATE "); + deparseAnyName(state, l); + deparseAppendStringInfoChar(state, ' '); } } // "index_elem" in gram.y -static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +static void deparseIndexElem(DeparseState *state, IndexElem* index_elem) { if (index_elem->name != NULL) { - deparseColId(str, index_elem->name); - appendStringInfoChar(str, ' '); + deparseColId(state, index_elem->name); + deparseAppendStringInfoChar(state, ' '); } else if (index_elem->expr != NULL) { @@ -1966,13 +2446,13 @@ static void deparseIndexElem(StringInfo str, IndexElem* index_elem) case T_MinMaxExpr: // func_expr_common_subexpr case T_XmlExpr: // func_expr_common_subexpr case T_XmlSerialize: // func_expr_common_subexpr - deparseFuncExprWindowless(str, index_elem->expr); - appendStringInfoString(str, " "); + deparseFuncExprWindowless(state, index_elem->expr); + deparseAppendStringInfoString(state, " "); break; default: - appendStringInfoChar(str, '('); - deparseExpr(str, index_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, index_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } } else @@ -1980,16 +2460,16 @@ static void deparseIndexElem(StringInfo str, IndexElem* index_elem) Assert(false); } - deparseOptCollate(str, index_elem->collation); + deparseOptCollate(state, index_elem->collation); if (list_length(index_elem->opclass) > 0) { - deparseAnyName(str, index_elem->opclass); + deparseAnyName(state, index_elem->opclass); if (list_length(index_elem->opclassopts) > 0) - deparseRelOptions(str, index_elem->opclassopts); + deparseRelOptions(state, index_elem->opclassopts); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } switch (index_elem->ordering) @@ -1998,10 +2478,10 @@ static void deparseIndexElem(StringInfo str, IndexElem* index_elem) // Default break; case SORTBY_ASC: - appendStringInfoString(str, "ASC "); + deparseAppendStringInfoString(state, "ASC "); break; case SORTBY_DESC: - appendStringInfoString(str, "DESC "); + deparseAppendStringInfoString(state, "DESC "); break; case SORTBY_USING: // Not allowed in CREATE INDEX @@ -2015,44 +2495,44 @@ static void deparseIndexElem(StringInfo str, IndexElem* index_elem) // Default break; case SORTBY_NULLS_FIRST: - appendStringInfoString(str, "NULLS FIRST "); + deparseAppendStringInfoString(state, "NULLS FIRST "); break; case SORTBY_NULLS_LAST: - appendStringInfoString(str, "NULLS LAST "); + deparseAppendStringInfoString(state, "NULLS LAST "); break; } - removeTrailingSpace(str); + removeTrailingSpace(state); } // "qualified_name_list" in gram.y -static void deparseQualifiedNameList(StringInfo str, List *l) +static void deparseQualifiedNameList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { - deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); if (lnext(l, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "OptInherit" in gram.y // // Note this method adds a trailing space if a value is output -static void deparseOptInherit(StringInfo str, List *l) +static void deparseOptInherit(DeparseState *state, List *l) { if (list_length(l) > 0) { - appendStringInfoString(str, "INHERITS ("); - deparseQualifiedNameList(str, l); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "INHERITS ("); + deparseQualifiedNameList(state, l); + deparseAppendStringInfoString(state, ") "); } } // "privilege_target" in gram.y -static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +static void deparsePrivilegeTarget(DeparseState *state, GrantTargetType targtype, ObjectType objtype, List *objs) { switch (targtype) { @@ -2060,59 +2540,59 @@ static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, Obj switch (objtype) { case OBJECT_TABLE: - deparseQualifiedNameList(str, objs); + deparseQualifiedNameList(state, objs); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - deparseQualifiedNameList(str, objs); + deparseAppendStringInfoString(state, "SEQUENCE "); + deparseQualifiedNameList(state, objs); break; case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseNameList(state, objs); break; case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "FOREIGN SERVER "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "FOREIGN SERVER "); + deparseNameList(state, objs); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypesList(str, objs); + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypesList(state, objs); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypesList(str, objs); + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypesList(state, objs); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypesList(str, objs); + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypesList(state, objs); break; case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "DATABASE "); + deparseNameList(state, objs); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseAnyNameList(str, objs); + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyNameList(state, objs); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNameList(state, objs); break; case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - deparseNumericOnlyList(str, objs); + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseNumericOnlyList(state, objs); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "SCHEMA "); + deparseNameList(state, objs); break; case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseNameList(state, objs); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseAnyNameList(str, objs); + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyNameList(state, objs); break; default: // Other types are not supported here @@ -2124,24 +2604,24 @@ static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, Obj switch (objtype) { case OBJECT_TABLE: - appendStringInfoString(str, "ALL TABLES IN SCHEMA "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "ALL TABLES IN SCHEMA "); + deparseNameList(state, objs); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(state, objs); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(state, objs); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(state, objs); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); - deparseNameList(str, objs); + deparseAppendStringInfoString(state, "ALL ROUTINES IN SCHEMA "); + deparseNameList(state, objs); break; default: // Other types are not supported here @@ -2153,19 +2633,19 @@ static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, Obj switch (objtype) { case OBJECT_TABLE: - appendStringInfoString(str, "TABLES"); + deparseAppendStringInfoString(state, "TABLES"); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTIONS"); + deparseAppendStringInfoString(state, "FUNCTIONS"); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCES"); + deparseAppendStringInfoString(state, "SEQUENCES"); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPES"); + deparseAppendStringInfoString(state, "TYPES"); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMAS"); + deparseAppendStringInfoString(state, "SCHEMAS"); break; default: // Other types are not supported here @@ -2177,20 +2657,20 @@ static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, Obj } // "opclass_item_list" in gram.y -static void deparseOpclassItemList(StringInfo str, List *items) +static void deparseOpclassItemList(DeparseState *state, List *items) { ListCell *lc = NULL; foreach (lc, items) { - deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + deparseCreateOpClassItem(state, castNode(CreateOpClassItem, lfirst(lc))); if (lnext(items, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } // "createdb_opt_list" in gram.y -static void deparseCreatedbOptList(StringInfo str, List *l) +static void deparseCreatedbOptList(DeparseState *state, List *l) { ListCell *lc = NULL; @@ -2198,65 +2678,86 @@ static void deparseCreatedbOptList(StringInfo str, List *l) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "connection_limit") == 0) - appendStringInfoString(str, "CONNECTION LIMIT"); + deparseAppendStringInfoString(state, "CONNECTION LIMIT"); else - deparseGenericDefElemName(str, def_elem->defname); + deparseGenericDefElemName(state, def_elem->defname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (def_elem->arg == NULL) - appendStringInfoString(str, "DEFAULT"); + deparseAppendStringInfoString(state, "DEFAULT"); else if (IsA(def_elem->arg, Integer)) - deparseSignedIconst(str, def_elem->arg); + deparseSignedIconst(state, def_elem->arg); else if (IsA(def_elem->arg, String)) - deparseOptBooleanOrString(str, strVal(def_elem->arg)); + deparseOptBooleanOrString(state, strVal(def_elem->arg)); if (lnext(l, lc)) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } // "utility_option_list" in gram.y -static void deparseUtilityOptionList(StringInfo str, List *options) +static void deparseUtilityOptionList(DeparseState *state, List *options) { ListCell *lc = NULL; char *defname = NULL; if (list_length(options) > 0) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); - deparseGenericDefElemName(str, def_elem->defname); + deparseGenericDefElemName(state, def_elem->defname); if (def_elem->arg != NULL) { - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); else if (IsA(def_elem->arg, String)) - deparseOptBooleanOrString(str, strVal(def_elem->arg)); + deparseOptBooleanOrString(state, strVal(def_elem->arg)); else Assert(false); } if (lnext(options, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } } -static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context) { + if (stmt == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected NULL SelectStmt in protobuf input"))); + const ListCell *lc = NULL; const ListCell *lc2 = NULL; + bool need_parens = context == DEPARSE_NODE_CONTEXT_SELECT_SETOP && ( + list_length(stmt->sortClause) > 0 || + stmt->limitOffset != NULL || + stmt->limitCount != NULL || + list_length(stmt->lockingClause) > 0 || + stmt->withClause != NULL || + stmt->op != SETOP_NONE); + DeparseStateNestingLevel *parent_level = NULL; + + if (need_parens) + { + deparseAppendPart(state, true); + deparseAppendStringInfoChar(state, '('); + } + if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) + parent_level = deparseStateIncreaseNestingLevel(state); if (stmt->withClause) { - deparseWithClause(str, stmt->withClause); - appendStringInfoChar(str, ' '); + deparseWithClause(state, stmt->withClause); + deparseAppendStringInfoChar(state, ' '); } switch (stmt->op) { @@ -2264,197 +2765,191 @@ static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) if (list_length(stmt->valuesLists) > 0) { const ListCell *lc; - appendStringInfoString(str, "VALUES "); + deparseAppendPartGroup(state, "VALUES", DEPARSE_PART_INDENT_AND_MERGE); foreach(lc, stmt->valuesLists) { - appendStringInfoChar(str, '('); - deparseExprList(str, lfirst(lc)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, lfirst(lc)); + deparseAppendStringInfoChar(state, ')'); if (lnext(stmt->valuesLists, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); break; } - appendStringInfoString(str, "SELECT "); + deparseAppendPartGroup(state, "SELECT", DEPARSE_PART_INDENT_AND_MERGE); if (list_length(stmt->targetList) > 0) { if (stmt->distinctClause != NULL) { - appendStringInfoString(str, "DISTINCT "); + deparseMarkCurrentPartNonMergable(state); + deparseAppendStringInfoString(state, "DISTINCT "); if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) { - appendStringInfoString(str, "ON ("); - deparseExprList(str, stmt->distinctClause); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "ON ("); + deparseExprList(state, stmt->distinctClause); + deparseAppendStringInfoString(state, ") "); } + deparseAppendPart(state, true); } - deparseTargetList(str, stmt->targetList); - appendStringInfoChar(str, ' '); + deparseTargetList(state, stmt->targetList); + deparseAppendStringInfoChar(state, ' '); } if (stmt->intoClause != NULL) { - appendStringInfoString(str, "INTO "); - deparseOptTemp(str, stmt->intoClause->rel->relpersistence); - deparseIntoClause(str, stmt->intoClause); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "INTO", DEPARSE_PART_INDENT); + deparseOptTemp(state, stmt->intoClause->rel->relpersistence); + deparseIntoClause(state, stmt->intoClause); + deparseAppendStringInfoChar(state, ' '); } - deparseFromClause(str, stmt->fromClause); - deparseWhereClause(str, stmt->whereClause); + deparseFromClause(state, stmt->fromClause); + deparseWhereClause(state, stmt->whereClause); if (list_length(stmt->groupClause) > 0) { - appendStringInfoString(str, "GROUP BY "); + deparseAppendPartGroup(state, "GROUP BY", DEPARSE_PART_INDENT_AND_MERGE); if (stmt->groupDistinct) - appendStringInfoString(str, "DISTINCT "); - deparseGroupByList(str, stmt->groupClause); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "DISTINCT "); + deparseGroupByList(state, stmt->groupClause); + deparseAppendStringInfoChar(state, ' '); } if (stmt->havingClause != NULL) { - appendStringInfoString(str, "HAVING "); - deparseExpr(str, stmt->havingClause, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "HAVING", DEPARSE_PART_INDENT); + deparseExpr(state, stmt->havingClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } if (stmt->windowClause != NULL) { - appendStringInfoString(str, "WINDOW "); + deparseAppendPartGroup(state, "WINDOW", DEPARSE_PART_INDENT); foreach(lc, stmt->windowClause) { WindowDef *window_def = castNode(WindowDef, lfirst(lc)); Assert(window_def->name != NULL); - appendStringInfoString(str, window_def->name); - appendStringInfoString(str, " AS "); - deparseWindowDef(str, window_def); + deparseAppendStringInfoString(state, window_def->name); + deparseAppendStringInfoString(state, " AS "); + deparseWindowDef(state, window_def); if (lnext(stmt->windowClause, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } break; case SETOP_UNION: case SETOP_INTERSECT: case SETOP_EXCEPT: { - bool need_larg_parens = - list_length(stmt->larg->sortClause) > 0 || - stmt->larg->limitOffset != NULL || - stmt->larg->limitCount != NULL || - list_length(stmt->larg->lockingClause) > 0 || - stmt->larg->withClause != NULL || - stmt->larg->op != SETOP_NONE; - bool need_rarg_parens = - list_length(stmt->rarg->sortClause) > 0 || - stmt->rarg->limitOffset != NULL || - stmt->rarg->limitCount != NULL || - list_length(stmt->rarg->lockingClause) > 0 || - stmt->rarg->withClause != NULL || - stmt->rarg->op != SETOP_NONE; - if (need_larg_parens) - appendStringInfoChar(str, '('); - deparseSelectStmt(str, stmt->larg); - if (need_larg_parens) - appendStringInfoChar(str, ')'); + deparseSelectStmt(state, stmt->larg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); switch (stmt->op) { case SETOP_UNION: - appendStringInfoString(str, " UNION "); + if (stmt->all) + deparseAppendPartGroup(state, "UNION ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "UNION", DEPARSE_PART_NO_INDENT); break; case SETOP_INTERSECT: - appendStringInfoString(str, " INTERSECT "); + if (stmt->all) + deparseAppendPartGroup(state, "INTERSECT ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "INTERSECT", DEPARSE_PART_NO_INDENT); break; case SETOP_EXCEPT: - appendStringInfoString(str, " EXCEPT "); + if (stmt->all) + deparseAppendPartGroup(state, "EXCEPT ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "EXCEPT", DEPARSE_PART_NO_INDENT); break; default: Assert(false); } - if (stmt->all) - appendStringInfoString(str, "ALL "); - if (need_rarg_parens) - appendStringInfoChar(str, '('); - deparseSelectStmt(str, stmt->rarg); - if (need_rarg_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); + deparseAppendPart(state, true); + deparseSelectStmt(state, stmt->rarg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); + deparseAppendStringInfoChar(state, ' '); } break; } - deparseOptSortClause(str, stmt->sortClause); + deparseOptSortClause(state, stmt->sortClause, DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE); if (stmt->limitCount != NULL) { if (stmt->limitOption == LIMIT_OPTION_COUNT) - appendStringInfoString(str, "LIMIT "); + deparseAppendPartGroup(state, "LIMIT", DEPARSE_PART_INDENT); else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) - appendStringInfoString(str, "FETCH FIRST "); + deparseAppendStringInfoString(state, "FETCH FIRST "); if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) - deparseCExpr(str, stmt->limitCount); + deparseCExpr(state, stmt->limitCount); else - deparseExpr(str, stmt->limitCount, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseExpr(state, stmt->limitCount, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) - appendStringInfoString(str, "ROWS WITH TIES "); + deparseAppendStringInfoString(state, "ROWS WITH TIES "); } if (stmt->limitOffset != NULL) { - appendStringInfoString(str, "OFFSET "); - deparseExpr(str, stmt->limitOffset, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "OFFSET", DEPARSE_PART_INDENT); + deparseExpr(state, stmt->limitOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } if (list_length(stmt->lockingClause) > 0) { foreach(lc, stmt->lockingClause) { - deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + deparseLockingClause(state, castNode(LockingClause, lfirst(lc))); if (lnext(stmt->lockingClause, lc)) - appendStringInfoString(str, " "); + deparseAppendStringInfoString(state, " "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); + + /* Note that parent_level can be NULL, so we repeat the full if condition here */ + if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) + deparseStateDecreaseNestingLevel(state, parent_level); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); } -static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +static void deparseIntoClause(DeparseState *state, IntoClause *into_clause) { ListCell *lc; - deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + deparseRangeVar(state, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ if (list_length(into_clause->colNames) > 0) { - appendStringInfoChar(str, '('); - deparseColumnList(str, into_clause->colNames); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, into_clause->colNames); + deparseAppendStringInfoChar(state, ')'); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (into_clause->accessMethod != NULL) { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(into_clause->accessMethod)); + deparseAppendStringInfoChar(state, ' '); } - deparseOptWith(str, into_clause->options); + deparseOptWith(state, into_clause->options); switch (into_clause->onCommit) { @@ -2462,86 +2957,126 @@ static void deparseIntoClause(StringInfo str, IntoClause *into_clause) // No clause break; case ONCOMMIT_PRESERVE_ROWS: - appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); break; case ONCOMMIT_DELETE_ROWS: - appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); break; case ONCOMMIT_DROP: - appendStringInfoString(str, "ON COMMIT DROP "); + deparseAppendStringInfoString(state, "ON COMMIT DROP "); break; } if (into_clause->tableSpaceName != NULL) { - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(into_clause->tableSpaceName)); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context) { if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "ONLY "); + deparseAppendStringInfoString(state, "ONLY "); if (range_var->catalogname != NULL) { - appendStringInfoString(str, quote_identifier(range_var->catalogname)); - appendStringInfoChar(str, '.'); + deparseAppendStringInfoString(state, quote_identifier(range_var->catalogname)); + deparseAppendStringInfoChar(state, '.'); } if (range_var->schemaname != NULL) { - appendStringInfoString(str, quote_identifier(range_var->schemaname)); - appendStringInfoChar(str, '.'); + deparseAppendStringInfoString(state, quote_identifier(range_var->schemaname)); + deparseAppendStringInfoChar(state, '.'); } Assert(range_var->relname != NULL); - appendStringInfoString(str, quote_identifier(range_var->relname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(range_var->relname)); + deparseAppendStringInfoChar(state, ' '); if (range_var->alias != NULL) { if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) - appendStringInfoString(str, "AS "); - deparseAlias(str, range_var->alias); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "AS "); + deparseAlias(state, range_var->alias); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt) { + PostgresDeparseOpts opts; + MemSet(&opts, 0, sizeof(PostgresDeparseOpts)); // zero initialized means pretty print = false + deparseRawStmtOpts(str, raw_stmt, opts); +} + +void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts opts) +{ + DeparseState *state = NULL; if (raw_stmt->stmt == NULL) elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); - deparseStmt(str, raw_stmt->stmt); + state = palloc0(sizeof(DeparseState)); + state->opts = opts; + if (state->opts.indent_size == 0) + state->opts.indent_size = 4; + if (state->opts.max_line_length == 0) + state->opts.max_line_length = 80; + + /* Check for any comments at the start of the statement */ + if (state->opts.comment_count > 0) + { + /* + * Filter out comments that are placed before this statement starts, this + * avoids emitting comments multiple times in multi-statement queries. + */ + for (int i = 0; i < state->opts.comment_count; i++) + { + if (state->opts.comments[i]->match_location < raw_stmt->stmt_location) + state->emitted_comments = bms_add_member(state->emitted_comments, i); + } + + deparseStateIncreaseNestingLevel(state); + deparseAppendCommentsIfNeeded(state, raw_stmt->stmt_location); + deparseRemoveTrailingEmptyPart(state); + deparseStateDecreaseNestingLevel(state, NULL); + } + + deparseStmt(state, raw_stmt->stmt); + + deparseEmit(state, str); + + bms_free(state->emitted_comments); + pfree(state); } -static void deparseAlias(StringInfo str, Alias *alias) +static void deparseAlias(DeparseState *state, Alias *alias) { - appendStringInfoString(str, quote_identifier(alias->aliasname)); + deparseAppendStringInfoString(state, quote_identifier(alias->aliasname)); if (list_length(alias->colnames) > 0) { const ListCell *lc = NULL; - appendStringInfoChar(str, '('); - deparseNameList(str, alias->colnames); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, alias->colnames); + deparseAppendStringInfoChar(state, ')'); } } -static void deparseAConst(StringInfo str, A_Const *a_const) +static void deparseAConst(DeparseState *state, A_Const *a_const) { union ValUnion *val = a_const->isnull ? NULL : &a_const->val; - deparseValue(str, val, DEPARSE_NODE_CONTEXT_CONSTANT); + deparseAppendCommentsIfNeeded(state, a_const->location); + deparseValue(state, val, DEPARSE_NODE_CONTEXT_CONSTANT); } -static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeContext context) +static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context) { const ListCell *lc = NULL; @@ -2556,15 +3091,15 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) */ - appendStringInfoString(str, "OVERLAY("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " PLACING "); - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FROM "); - deparseExpr(str, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FOR "); - deparseExpr(str, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "OVERLAY("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PLACING "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOR "); + deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2576,16 +3111,16 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) */ Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); - appendStringInfoString(str, "SUBSTRING("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FROM "); - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, "SUBSTRING("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (list_length(func_call->args) == 3) { - appendStringInfoString(str, " FOR "); - deparseExpr(str, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOR "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2598,11 +3133,11 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) * Note that the first and second arguments are switched in this format */ - appendStringInfoString(str, "POSITION("); - deparseBExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, " IN "); - deparseBExpr(str, linitial(func_call->args)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "POSITION("); + deparseBExpr(state, lsecond(func_call->args)); + deparseAppendStringInfoString(state, " IN "); + deparseBExpr(state, linitial(func_call->args)); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2614,13 +3149,13 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * "OVERLAY" is a keyword on its own merit, and only accepts the * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) */ - appendStringInfoString(str, "overlay("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " placing "); - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " from "); - deparseExpr(str, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "overlay("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " placing "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " from "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2632,9 +3167,9 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * "collation for" is a keyword on its own merit, and only accepts the * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) */ - appendStringInfoString(str, "collation for ("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "collation for ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2646,11 +3181,11 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * "EXTRACT" is a keyword on its own merit, and only accepts the * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) */ - appendStringInfoString(str, "extract ("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FROM "); - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "extract ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2663,18 +3198,18 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) * format: (start_1, end_1) overlaps (start_2, end_2) */ - appendStringInfoChar(str, '('); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ", "); - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); - - appendStringInfoString(str, "overlaps "); - appendStringInfoChar(str, '('); - deparseExpr(str, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ", "); - deparseExpr(str, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + + deparseAppendStringInfoString(state, "overlaps "); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2691,19 +3226,19 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * Note that the first and second arguments are switched in this format */ Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); - appendStringInfoString(str, "TRIM ("); + deparseAppendStringInfoString(state, "TRIM ("); if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) - appendStringInfoString(str, "LEADING "); + deparseAppendStringInfoString(state, "LEADING "); else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) - appendStringInfoString(str, "BOTH "); + deparseAppendStringInfoString(state, "BOTH "); else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) - appendStringInfoString(str, "TRAILING "); + deparseAppendStringInfoString(state, "TRAILING "); if (list_length(func_call->args) == 2) - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FROM "); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2727,28 +3262,28 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont // If we're not inside an a_expr context, we must add wrapping parenthesis around the AT ... syntax if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); } if (IsA(e, A_Expr)) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); } - deparseExpr(str, (Node*) e, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, (Node*) e, DEPARSE_NODE_CONTEXT_A_EXPR); if (IsA(e, A_Expr)) { - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } if (isLocal) - appendStringInfoString(str, " AT LOCAL"); + deparseAppendStringInfoString(state, " AT LOCAL"); else { - appendStringInfoString(str, " AT TIME ZONE "); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AT TIME ZONE "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); } if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } return; @@ -2762,17 +3297,17 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) */ Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); - appendStringInfoString(str, "normalize ("); + deparseAppendStringInfoString(state, "normalize ("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (list_length(func_call->args) == 2) { - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); Assert(IsA(lsecond(func_call->args), A_Const)); A_Const *aconst = lsecond(func_call->args); - deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2785,15 +3320,15 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont */ Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " IS "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " IS "); if (list_length(func_call->args) == 2) { Assert(IsA(lsecond(func_call->args), A_Const)); A_Const *aconst = lsecond(func_call->args); - deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); } - appendStringInfoString(str, " NORMALIZED "); + deparseAppendStringInfoString(state, " NORMALIZED "); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && @@ -2801,118 +3336,132 @@ static void deparseFuncCall(StringInfo str, FuncCall *func_call, DeparseNodeCont strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && list_length(func_call->args) == 2) { - appendStringInfoString(str, "xmlexists ("); - deparseExpr(str, linitial(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); - appendStringInfoString(str, " PASSING "); - deparseExpr(str, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "xmlexists ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoString(state, " PASSING "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoChar(state, ')'); return; } else if (func_call->funcformat == COERCE_SQL_SYNTAX && list_length(func_call->funcname) == 2 && strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && strcmp(strVal(lsecond(func_call->funcname)), "system_user") == 0) { - appendStringInfoString(str, "SYSTEM_USER"); + deparseAppendStringInfoString(state, "SYSTEM_USER"); return; } - deparseFuncName(str, func_call->funcname); - appendStringInfoChar(str, '('); + deparseFuncName(state, func_call->funcname); + deparseAppendStringInfoChar(state, '('); if (func_call->agg_distinct) - appendStringInfoString(str, "DISTINCT "); + deparseAppendStringInfoString(state, "DISTINCT "); if (func_call->agg_star) { - appendStringInfoChar(str, '*'); + deparseAppendStringInfoChar(state, '*'); } else if (list_length(func_call->args) > 0) { foreach(lc, func_call->args) { if (func_call->func_variadic && !lnext(func_call->args, lc)) - appendStringInfoString(str, "VARIADIC "); - deparseFuncArgExpr(str, lfirst(lc)); + deparseAppendStringInfoString(state, "VARIADIC "); + deparseFuncArgExpr(state, lfirst(lc)); if (lnext(func_call->args, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (func_call->agg_order != NULL && !func_call->agg_within_group) { - deparseOptSortClause(str, func_call->agg_order); + deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); } - removeTrailingSpace(str); - appendStringInfoString(str, ") "); + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); if (func_call->agg_order != NULL && func_call->agg_within_group) { - appendStringInfoString(str, "WITHIN GROUP ("); - deparseOptSortClause(str, func_call->agg_order); - removeTrailingSpace(str); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "WITHIN GROUP ("); + deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); } if (func_call->agg_filter) { - appendStringInfoString(str, "FILTER (WHERE "); - deparseExpr(str, func_call->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, func_call->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } if (func_call->over) { - appendStringInfoString(str, "OVER "); + deparseAppendStringInfoString(state, "OVER "); if (func_call->over->name) - appendStringInfoString(str, func_call->over->name); + deparseAppendStringInfoString(state, func_call->over->name); else - deparseWindowDef(str, func_call->over); + deparseWindowDef(state, func_call->over); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseWindowDef(StringInfo str, WindowDef* window_def) +static void deparseWindowDef(DeparseState *state, WindowDef* window_def) { ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; // The parent node is responsible for outputting window_def->name - appendStringInfoChar(str, '('); + // Special case completely empty window clauses and return early + if (!window_def->refname && list_length(window_def->partitionClause) == 0 && + list_length(window_def->orderClause) == 0 && + !(window_def->frameOptions & FRAMEOPTION_NONDEFAULT)) + { + deparseAppendStringInfoString(state, "()"); + return; + } + + deparseAppendStringInfoChar(state, '('); + parent_level = deparseStateIncreaseNestingLevel(state); if (window_def->refname != NULL) { - appendStringInfoString(str, quote_identifier(window_def->refname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(window_def->refname)); + deparseAppendStringInfoChar(state, ' '); } if (list_length(window_def->partitionClause) > 0) { - appendStringInfoString(str, "PARTITION BY "); - deparseExprList(str, window_def->partitionClause); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "PARTITION BY "); + deparseExprList(state, window_def->partitionClause); + deparseAppendStringInfoChar(state, ' '); } - deparseOptSortClause(str, window_def->orderClause); + removeTrailingSpace(state); + deparseAppendPart(state, true); + deparseOptSortClause(state, window_def->orderClause, DEPARSE_NODE_CONTEXT_NONE); if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) { + deparseAppendPartGroup(state, NULL, DEPARSE_PART_NO_INDENT); if (window_def->frameOptions & FRAMEOPTION_RANGE) - appendStringInfoString(str, "RANGE "); + deparseAppendStringInfoString(state, "RANGE "); else if (window_def->frameOptions & FRAMEOPTION_ROWS) - appendStringInfoString(str, "ROWS "); + deparseAppendStringInfoString(state, "ROWS "); else if (window_def->frameOptions & FRAMEOPTION_GROUPS) - appendStringInfoString(str, "GROUPS "); + deparseAppendStringInfoString(state, "GROUPS "); if (window_def->frameOptions & FRAMEOPTION_BETWEEN) - appendStringInfoString(str, "BETWEEN "); + deparseAppendStringInfoString(state, "BETWEEN "); // frame_start if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) { - appendStringInfoString(str, "UNBOUNDED PRECEDING "); + deparseAppendStringInfoString(state, "UNBOUNDED PRECEDING "); } else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) { @@ -2920,24 +3469,24 @@ static void deparseWindowDef(StringInfo str, WindowDef* window_def) } else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) { - appendStringInfoString(str, "CURRENT ROW "); + deparseAppendStringInfoString(state, "CURRENT ROW "); } else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) { Assert(window_def->startOffset != NULL); - deparseExpr(str, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " PRECEDING "); + deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PRECEDING "); } else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) { Assert(window_def->startOffset != NULL); - deparseExpr(str, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FOLLOWING "); + deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOLLOWING "); } if (window_def->frameOptions & FRAMEOPTION_BETWEEN) { - appendStringInfoString(str, "AND "); + deparseAppendStringInfoString(state, "AND "); // frame_end if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) @@ -2946,99 +3495,102 @@ static void deparseWindowDef(StringInfo str, WindowDef* window_def) } else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) { - appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + deparseAppendStringInfoString(state, "UNBOUNDED FOLLOWING "); } else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) { - appendStringInfoString(str, "CURRENT ROW "); + deparseAppendStringInfoString(state, "CURRENT ROW "); } else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) { Assert(window_def->endOffset != NULL); - deparseExpr(str, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " PRECEDING "); + deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PRECEDING "); } else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) { Assert(window_def->endOffset != NULL); - deparseExpr(str, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " FOLLOWING "); + deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOLLOWING "); } } if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) - appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + deparseAppendStringInfoString(state, "EXCLUDE CURRENT ROW "); else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) - appendStringInfoString(str, "EXCLUDE GROUP "); + deparseAppendStringInfoString(state, "EXCLUDE GROUP "); else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) - appendStringInfoString(str, "EXCLUDE TIES "); + deparseAppendStringInfoString(state, "EXCLUDE TIES "); } - removeTrailingSpace(str); - appendStringInfoChar(str, ')'); + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); } -static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref) { Assert(list_length(column_ref->fields) >= 1); + deparseAppendCommentsIfNeeded(state, column_ref->location); + if (IsA(linitial(column_ref->fields), A_Star)) - deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + deparseAStar(state, castNode(A_Star, linitial(column_ref->fields))); else if (IsA(linitial(column_ref->fields), String)) - deparseColLabel(str, strVal(linitial(column_ref->fields))); + deparseColLabel(state, strVal(linitial(column_ref->fields))); - deparseOptIndirection(str, column_ref->fields, 1); + deparseOptIndirection(state, column_ref->fields, 1); } -static void deparseSubLink(StringInfo str, SubLink* sub_link) +static void deparseSubLink(DeparseState *state, SubLink* sub_link) { switch (sub_link->subLinkType) { case EXISTS_SUBLINK: - appendStringInfoString(str, "EXISTS ("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "EXISTS ("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); return; case ALL_SUBLINK: - deparseExpr(str, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, sub_link->operName); - appendStringInfoString(str, " ALL ("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); + deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, sub_link->operName); + deparseAppendStringInfoString(state, " ALL ("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); return; case ANY_SUBLINK: - deparseExpr(str, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); if (list_length(sub_link->operName) > 0) { - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, sub_link->operName); - appendStringInfoString(str, " ANY "); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, sub_link->operName); + deparseAppendStringInfoString(state, " ANY "); } else { - appendStringInfoString(str, " IN "); + deparseAppendStringInfoString(state, " IN "); } - appendStringInfoChar(str, '('); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); return; case ROWCOMPARE_SUBLINK: // Not present in raw parse trees Assert(false); return; case EXPR_SUBLINK: - appendStringInfoString(str, "("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); return; case MULTIEXPR_SUBLINK: // Not present in raw parse trees Assert(false); return; case ARRAY_SUBLINK: - appendStringInfoString(str, "ARRAY("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "ARRAY("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); return; case CTE_SUBLINK: /* for SubPlans only */ // Not present in raw parse trees @@ -3047,14 +3599,23 @@ static void deparseSubLink(StringInfo str, SubLink* sub_link) } } +// Checks whether a node needs parens when used in a "b_expr" context (because the node is handled by the "a_expr" rule in gram.y) +static bool +needsParensAsBExpr(Node *node) +{ + if (node == NULL) + return false; + return IsA(node, BoolExpr) || IsA(node, BooleanTest) || IsA(node, NullTest) || IsA(node, A_Expr); +} + // This handles "A_Expr" parse tree objects, which are a subset of the rules in "a_expr" (handled by deparseExpr) -static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context) { ListCell *lc; char *name; - bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, BooleanTest) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); - bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, BooleanTest) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + bool need_lexpr_parens = needsParensAsBExpr(a_expr->lexpr); + bool need_rexpr_parens = needsParensAsBExpr(a_expr->rexpr); switch (a_expr->kind) { case AEXPR_OP: /* normal operator */ @@ -3062,39 +3623,39 @@ static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext cont if (a_expr->lexpr != NULL) { if (need_lexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->lexpr, context); if (need_lexpr_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); } - deparseQualOp(str, a_expr->name); + deparseQualOp(state, a_expr->name); if (a_expr->rexpr != NULL) { - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (need_rexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->rexpr, context); if (need_rexpr_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } } return; case AEXPR_OP_ANY: /* scalar op ANY (array) */ - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, a_expr->name); - appendStringInfoString(str, " ANY("); - deparseExpr(str, a_expr->rexpr, context); - appendStringInfoChar(str, ')'); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, a_expr->name); + deparseAppendStringInfoString(state, " ANY("); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); return; case AEXPR_OP_ALL: /* scalar op ALL (array) */ - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, a_expr->name); - appendStringInfoString(str, " ALL("); - deparseExpr(str, a_expr->rexpr, context); - appendStringInfoChar(str, ')'); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, a_expr->name); + deparseAppendStringInfoString(state, " ALL("); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); return; case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ Assert(list_length(a_expr->name) == 1); @@ -3102,103 +3663,103 @@ static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext cont Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); if (need_lexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->lexpr, context); if (need_lexpr_parens) - appendStringInfoChar(str, ')'); - appendStringInfoString(str, " IS DISTINCT FROM "); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoString(state, " IS DISTINCT FROM "); if (need_rexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->rexpr, context); if (need_rexpr_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); return; case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ Assert(list_length(a_expr->name) == 1); Assert(IsA(linitial(a_expr->name), String)); Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoString(str, " IS NOT DISTINCT FROM "); - deparseExpr(str, a_expr->rexpr, context); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoString(state, " IS NOT DISTINCT FROM "); + deparseExpr(state, a_expr->rexpr, context); return; case AEXPR_NULLIF: /* NULLIF - name must be "=" */ Assert(list_length(a_expr->name) == 1); Assert(IsA(linitial(a_expr->name), String)); Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); - appendStringInfoString(str, "NULLIF("); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoString(str, ", "); - deparseExpr(str, a_expr->rexpr, context); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "NULLIF("); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); return; case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ Assert(list_length(a_expr->name) == 1); Assert(IsA(linitial(a_expr->name), String)); Assert(IsA(a_expr->rexpr, List)); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "=") == 0) { - appendStringInfoString(str, "IN "); + deparseAppendStringInfoString(state, "IN "); } else if (strcmp(name, "<>") == 0) { - appendStringInfoString(str, "NOT IN "); + deparseAppendStringInfoString(state, "NOT IN "); } else { Assert(false); } - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); if (IsA(a_expr->rexpr, SubLink)) - deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + deparseSubLink(state, castNode(SubLink, a_expr->rexpr)); else - deparseExprList(str, castNode(List, a_expr->rexpr)); - appendStringInfoChar(str, ')'); + deparseExprList(state, castNode(List, a_expr->rexpr)); + deparseAppendStringInfoChar(state, ')'); return; case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ Assert(list_length(a_expr->name) == 1); Assert(IsA(linitial(a_expr->name), String)); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "~~") == 0) { - appendStringInfoString(str, "LIKE "); + deparseAppendStringInfoString(state, "LIKE "); } else if (strcmp(name, "!~~") == 0) { - appendStringInfoString(str, "NOT LIKE "); + deparseAppendStringInfoString(state, "NOT LIKE "); } else { Assert(false); } - deparseExpr(str, a_expr->rexpr, context); + deparseExpr(state, a_expr->rexpr, context); return; case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ Assert(list_length(a_expr->name) == 1); Assert(IsA(linitial(a_expr->name), String)); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "~~*") == 0) { - appendStringInfoString(str, "ILIKE "); + deparseAppendStringInfoString(state, "ILIKE "); } else if (strcmp(name, "!~~*") == 0) { - appendStringInfoString(str, "NOT ILIKE "); + deparseAppendStringInfoString(state, "NOT ILIKE "); } else { Assert(false); } - deparseExpr(str, a_expr->rexpr, context); + deparseExpr(state, a_expr->rexpr, context); return; case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ Assert(list_length(a_expr->name) == 1); Assert(IsA(linitial(a_expr->name), String)); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "~") == 0) { - appendStringInfoString(str, "SIMILAR TO "); + deparseAppendStringInfoString(state, "SIMILAR TO "); } else if (strcmp(name, "!~") == 0) { - appendStringInfoString(str, "NOT SIMILAR TO "); + deparseAppendStringInfoString(state, "NOT SIMILAR TO "); } else { Assert(false); } @@ -3209,11 +3770,11 @@ static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext cont Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); Assert(list_length(n->args) == 1 || list_length(n->args) == 2); - deparseExpr(str, linitial(n->args), context); + deparseExpr(state, linitial(n->args), context); if (list_length(n->args) == 2) { - appendStringInfoString(str, " ESCAPE "); - deparseExpr(str, lsecond(n->args), context); + deparseAppendStringInfoString(state, " ESCAPE "); + deparseExpr(state, lsecond(n->args), context); } return; @@ -3225,21 +3786,21 @@ static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext cont Assert(IsA(linitial(a_expr->name), String)); Assert(IsA(a_expr->rexpr, List)); - deparseExpr(str, a_expr->lexpr, context); - appendStringInfoChar(str, ' '); - appendStringInfoString(str, strVal(linitial(a_expr->name))); - appendStringInfoChar(str, ' '); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseAppendStringInfoString(state, strVal(linitial(a_expr->name))); + deparseAppendStringInfoChar(state, ' '); foreach(lc, castNode(List, a_expr->rexpr)) { - deparseExpr(str, lfirst(lc), context); + deparseExpr(state, lfirst(lc), context); if (lnext(castNode(List, a_expr->rexpr), lc)) - appendStringInfoString(str, " AND "); + deparseAppendStringInfoString(state, " AND "); } return; } } -static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr) { const ListCell *lc = NULL; switch (bool_expr->boolop) @@ -3251,15 +3812,18 @@ static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); if (need_parens) - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); - deparseExpr(str, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); if (lnext(bool_expr->args, lc)) - appendStringInfoString(str, " AND "); + { + deparseAppendPart(state, true); + deparseAppendStringInfoString(state, "AND "); + } } return; case OR_EXPR: @@ -3269,71 +3833,71 @@ static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); if (need_parens) - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); - deparseExpr(str, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); if (lnext(bool_expr->args, lc)) - appendStringInfoString(str, " OR "); + deparseAppendStringInfoString(state, " OR "); } return; case NOT_EXPR: Assert(list_length(bool_expr->args) == 1); bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); - appendStringInfoString(str, "NOT "); + deparseAppendStringInfoString(state, "NOT "); if (need_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, linitial(bool_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, linitial(bool_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); return; } } -static void deparseAStar(StringInfo str, A_Star *a_star) +static void deparseAStar(DeparseState *state, A_Star *a_star) { - appendStringInfoChar(str, '*'); + deparseAppendStringInfoChar(state, '*'); } -static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause) { ListCell *lc; if (collate_clause->arg != NULL) { bool need_parens = IsA(collate_clause->arg, A_Expr); if (need_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, collate_clause->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, collate_clause->arg, DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "COLLATE "); - deparseAnyName(str, collate_clause->collname); + deparseAppendStringInfoString(state, "COLLATE "); + deparseAnyName(state, collate_clause->collname); } // "sortby" in gram.y -static void deparseSortBy(StringInfo str, SortBy* sort_by) +static void deparseSortBy(DeparseState *state, SortBy* sort_by) { - deparseExpr(str, sort_by->node, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseExpr(state, sort_by->node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); switch (sort_by->sortby_dir) { case SORTBY_DEFAULT: break; case SORTBY_ASC: - appendStringInfoString(str, "ASC "); + deparseAppendStringInfoString(state, "ASC "); break; case SORTBY_DESC: - appendStringInfoString(str, "DESC "); + deparseAppendStringInfoString(state, "DESC "); break; case SORTBY_USING: - appendStringInfoString(str, "USING "); - deparseQualOp(str, sort_by->useOp); + deparseAppendStringInfoString(state, "USING "); + deparseQualOp(state, sort_by->useOp); break; } @@ -3342,130 +3906,129 @@ static void deparseSortBy(StringInfo str, SortBy* sort_by) case SORTBY_NULLS_DEFAULT: break; case SORTBY_NULLS_FIRST: - appendStringInfoString(str, "NULLS FIRST "); + deparseAppendStringInfoString(state, "NULLS FIRST "); break; case SORTBY_NULLS_LAST: - appendStringInfoString(str, "NULLS LAST "); + deparseAppendStringInfoString(state, "NULLS LAST "); break; } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseParamRef(StringInfo str, ParamRef* param_ref) +static void deparseParamRef(DeparseState *state, ParamRef* param_ref) { if (param_ref->number == 0) { - appendStringInfoChar(str, '?'); + deparseAppendStringInfoChar(state, '?'); } else { - appendStringInfo(str, "$%d", param_ref->number); + deparseAppendStringInfo(state, "$%d", param_ref->number); } } -static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function) { switch (sql_value_function->op) { case SVFOP_CURRENT_DATE: - appendStringInfoString(str, "current_date"); + deparseAppendStringInfoString(state, "current_date"); break; case SVFOP_CURRENT_TIME: - appendStringInfoString(str, "current_time"); + deparseAppendStringInfoString(state, "current_time"); break; case SVFOP_CURRENT_TIME_N: - appendStringInfoString(str, "current_time"); // with precision + deparseAppendStringInfoString(state, "current_time"); // with precision break; case SVFOP_CURRENT_TIMESTAMP: - appendStringInfoString(str, "current_timestamp"); + deparseAppendStringInfoString(state, "current_timestamp"); break; case SVFOP_CURRENT_TIMESTAMP_N: - appendStringInfoString(str, "current_timestamp"); // with precision + deparseAppendStringInfoString(state, "current_timestamp"); // with precision break; case SVFOP_LOCALTIME: - appendStringInfoString(str, "localtime"); + deparseAppendStringInfoString(state, "localtime"); break; case SVFOP_LOCALTIME_N: - appendStringInfoString(str, "localtime"); // with precision + deparseAppendStringInfoString(state, "localtime"); // with precision break; case SVFOP_LOCALTIMESTAMP: - appendStringInfoString(str, "localtimestamp"); + deparseAppendStringInfoString(state, "localtimestamp"); break; case SVFOP_LOCALTIMESTAMP_N: - appendStringInfoString(str, "localtimestamp"); // with precision + deparseAppendStringInfoString(state, "localtimestamp"); // with precision break; case SVFOP_CURRENT_ROLE: - appendStringInfoString(str, "current_role"); + deparseAppendStringInfoString(state, "current_role"); break; case SVFOP_CURRENT_USER: - appendStringInfoString(str, "current_user"); + deparseAppendStringInfoString(state, "current_user"); break; case SVFOP_USER: - appendStringInfoString(str, "user"); + deparseAppendStringInfoString(state, "user"); break; case SVFOP_SESSION_USER: - appendStringInfoString(str, "session_user"); + deparseAppendStringInfoString(state, "session_user"); break; case SVFOP_CURRENT_CATALOG: - appendStringInfoString(str, "current_catalog"); + deparseAppendStringInfoString(state, "current_catalog"); break; case SVFOP_CURRENT_SCHEMA: - appendStringInfoString(str, "current_schema"); + deparseAppendStringInfoString(state, "current_schema"); break; } if (sql_value_function->typmod != -1) { - appendStringInfo(str, "(%d)", sql_value_function->typmod); + deparseAppendStringInfo(state, "(%d)", sql_value_function->typmod); } } -static void deparseWithClause(StringInfo str, WithClause *with_clause) +static void deparseWithClause(DeparseState *state, WithClause *with_clause) { ListCell *lc; - appendStringInfoString(str, "WITH "); + deparseAppendPartGroup(state, "WITH", DEPARSE_PART_NO_INDENT); if (with_clause->recursive) - appendStringInfoString(str, "RECURSIVE "); - + deparseAppendStringInfoString(state, "RECURSIVE "); + foreach(lc, with_clause->ctes) { - deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + deparseCommonTableExpr(state, castNode(CommonTableExpr, lfirst(lc))); if (lnext(with_clause->ctes, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - removeTrailingSpace(str); + removeTrailingSpace(state); } // "joined_table" in gram.y -static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr) { ListCell *lc; bool need_alias_parens = join_expr->alias != NULL; bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; if (need_alias_parens) - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); - deparseTableRef(str, join_expr->larg); - - appendStringInfoChar(str, ' '); + deparseTableRef(state, join_expr->larg); + deparseAppendPart(state, true); if (join_expr->isNatural) - appendStringInfoString(str, "NATURAL "); + deparseAppendStringInfoString(state, "NATURAL "); switch (join_expr->jointype) { case JOIN_INNER: /* matching tuple pairs only */ if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) - appendStringInfoString(str, "CROSS "); + deparseAppendStringInfoString(state, "CROSS "); break; case JOIN_LEFT: /* pairs + unmatched LHS tuples */ - appendStringInfoString(str, "LEFT "); + deparseAppendStringInfoString(state, "LEFT "); break; case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ - appendStringInfoString(str, "FULL "); + deparseAppendStringInfoString(state, "FULL "); break; case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ - appendStringInfoString(str, "RIGHT "); + deparseAppendStringInfoString(state, "RIGHT "); break; case JOIN_SEMI: case JOIN_ANTI: @@ -3476,224 +4039,226 @@ static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) Assert(false); break; } - - appendStringInfoString(str, "JOIN "); + + deparseAppendStringInfoString(state, "JOIN "); if (need_rarg_parens) - appendStringInfoChar(str, '('); - deparseTableRef(str, join_expr->rarg); + deparseAppendStringInfoChar(state, '('); + deparseTableRef(state, join_expr->rarg); if (need_rarg_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); if (join_expr->quals != NULL) { - appendStringInfoString(str, "ON "); - deparseExpr(str, join_expr->quals, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ON "); + deparseExpr(state, join_expr->quals, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } if (list_length(join_expr->usingClause) > 0) { - appendStringInfoString(str, "USING ("); - deparseNameList(str, join_expr->usingClause); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "USING ("); + deparseNameList(state, join_expr->usingClause); + deparseAppendStringInfoString(state, ") "); if (join_expr->join_using_alias) { - appendStringInfoString(str, "AS "); - appendStringInfoString(str, join_expr->join_using_alias->aliasname); + deparseAppendStringInfoString(state, "AS "); + deparseAppendStringInfoString(state, join_expr->join_using_alias->aliasname); } } if (need_alias_parens) - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); if (join_expr->alias != NULL) - deparseAlias(str, join_expr->alias); + deparseAlias(state, join_expr->alias); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCTESearchClause(StringInfo str, CTESearchClause *search_clause) +static void deparseCTESearchClause(DeparseState *state, CTESearchClause *search_clause) { - appendStringInfoString(str, " SEARCH "); + deparseAppendStringInfoString(state, " SEARCH "); if (search_clause->search_breadth_first) - appendStringInfoString(str, "BREADTH "); + deparseAppendStringInfoString(state, "BREADTH "); else - appendStringInfoString(str, "DEPTH "); + deparseAppendStringInfoString(state, "DEPTH "); - appendStringInfoString(str, "FIRST BY "); + deparseAppendStringInfoString(state, "FIRST BY "); if (search_clause->search_col_list) - deparseColumnList(str, search_clause->search_col_list); + deparseColumnList(state, search_clause->search_col_list); - appendStringInfoString(str, " SET "); - appendStringInfoString(str, quote_identifier(search_clause->search_seq_column)); + deparseAppendStringInfoString(state, " SET "); + deparseAppendStringInfoString(state, quote_identifier(search_clause->search_seq_column)); } // "opt_cycle_clause" in gram.y -static void deparseCTECycleClause(StringInfo str, CTECycleClause *cycle_clause) +static void deparseCTECycleClause(DeparseState *state, CTECycleClause *cycle_clause) { - appendStringInfoString(str, " CYCLE "); + deparseAppendStringInfoString(state, " CYCLE "); if (cycle_clause->cycle_col_list) - deparseColumnList(str, cycle_clause->cycle_col_list); + deparseColumnList(state, cycle_clause->cycle_col_list); - appendStringInfoString(str, " SET "); - appendStringInfoString(str, quote_identifier(cycle_clause->cycle_mark_column)); + deparseAppendStringInfoString(state, " SET "); + deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_mark_column)); if (cycle_clause->cycle_mark_value) { - appendStringInfoString(str, " TO "); - deparseAexprConst(str, cycle_clause->cycle_mark_value); + deparseAppendStringInfoString(state, " TO "); + deparseAexprConst(state, cycle_clause->cycle_mark_value); } if (cycle_clause->cycle_mark_default) { - appendStringInfoString(str, " DEFAULT "); - deparseAexprConst(str, cycle_clause->cycle_mark_default); + deparseAppendStringInfoString(state, " DEFAULT "); + deparseAexprConst(state, cycle_clause->cycle_mark_default); } - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(cycle_clause->cycle_path_column)); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_path_column)); } -static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte) { - deparseColId(str, cte->ctename); + deparseAppendCommentsIfNeeded(state, cte->location); + + deparseColId(state, cte->ctename); if (list_length(cte->aliascolnames) > 0) { - appendStringInfoChar(str, '('); - deparseNameList(str, cte->aliascolnames); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, cte->aliascolnames); + deparseAppendStringInfoChar(state, ')'); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "AS "); + deparseAppendStringInfoString(state, "AS "); switch (cte->ctematerialized) { case CTEMaterializeDefault: /* no option specified */ break; case CTEMaterializeAlways: - appendStringInfoString(str, "MATERIALIZED "); + deparseAppendStringInfoString(state, "MATERIALIZED "); break; case CTEMaterializeNever: - appendStringInfoString(str, "NOT MATERIALIZED "); + deparseAppendStringInfoString(state, "NOT MATERIALIZED "); break; } - appendStringInfoChar(str, '('); - deparsePreparableStmt(str, cte->ctequery); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparsePreparableStmt(state, cte->ctequery); + deparseAppendStringInfoChar(state, ')'); if (cte->search_clause) - deparseCTESearchClause(str, cte->search_clause); + deparseCTESearchClause(state, cte->search_clause); if (cte->cycle_clause) - deparseCTECycleClause(str, cte->cycle_clause); + deparseCTECycleClause(state, cte->cycle_clause); } -static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect) { if (range_subselect->lateral) - appendStringInfoString(str, "LATERAL "); + deparseAppendStringInfoString(state, "LATERAL "); - appendStringInfoChar(str, '('); - deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseSelectStmt(state, castNode(SelectStmt, range_subselect->subquery), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); if (range_subselect->alias != NULL) { - appendStringInfoChar(str, ' '); - deparseAlias(str, range_subselect->alias); + deparseAppendStringInfoChar(state, ' '); + deparseAlias(state, range_subselect->alias); } } -static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func) { ListCell *lc; ListCell *lc2; if (range_func->lateral) - appendStringInfoString(str, "LATERAL "); + deparseAppendStringInfoString(state, "LATERAL "); if (range_func->is_rowsfrom) { - appendStringInfoString(str, "ROWS FROM "); - appendStringInfoChar(str, '('); + deparseAppendStringInfoString(state, "ROWS FROM "); + deparseAppendStringInfoChar(state, '('); foreach(lc, range_func->functions) { List *lfunc = castNode(List, lfirst(lc)); Assert(list_length(lfunc) == 2); - deparseFuncExprWindowless(str, linitial(lfunc)); - appendStringInfoChar(str, ' '); + deparseFuncExprWindowless(state, linitial(lfunc)); + deparseAppendStringInfoChar(state, ' '); List *coldeflist = castNode(List, lsecond(lfunc)); if (list_length(coldeflist) > 0) { - appendStringInfoString(str, "AS ("); + deparseAppendStringInfoString(state, "AS ("); foreach(lc2, coldeflist) { - deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc2))); if (lnext(coldeflist, lc2)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } if (lnext(range_func->functions, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } else { Assert(list_length(linitial(range_func->functions)) == 2); - deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + deparseFuncExprWindowless(state, linitial(linitial(range_func->functions))); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (range_func->ordinality) - appendStringInfoString(str, "WITH ORDINALITY "); + deparseAppendStringInfoString(state, "WITH ORDINALITY "); if (range_func->alias != NULL) { - deparseAlias(str, range_func->alias); - appendStringInfoChar(str, ' '); + deparseAlias(state, range_func->alias); + deparseAppendStringInfoChar(state, ' '); } if (list_length(range_func->coldeflist) > 0) { if (range_func->alias == NULL) - appendStringInfoString(str, "AS "); - appendStringInfoChar(str, '('); + deparseAppendStringInfoString(state, "AS "); + deparseAppendStringInfoChar(state, '('); foreach(lc, range_func->coldeflist) { - deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); if (lnext(range_func->coldeflist, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr *array_expr) { ListCell *lc; - appendStringInfoString(str, "ARRAY["); - deparseExprList(str, array_expr->elements); - appendStringInfoChar(str, ']'); + deparseAppendStringInfoString(state, "ARRAY["); + deparseExprList(state, array_expr->elements); + deparseAppendStringInfoChar(state, ']'); } -static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +static void deparseRowExpr(DeparseState *state, RowExpr *row_expr) { ListCell *lc; switch (row_expr->row_format) { case COERCE_EXPLICIT_CALL: - appendStringInfoString(str, "ROW"); + deparseAppendStringInfoString(state, "ROW"); break; case COERCE_SQL_SYNTAX: case COERCE_EXPLICIT_CAST: @@ -3705,24 +4270,31 @@ static void deparseRowExpr(StringInfo str, RowExpr *row_expr) break; } - appendStringInfoString(str, "("); - deparseExprList(str, row_expr->args); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "("); + deparseExprList(state, row_expr->args); + deparseAppendStringInfoChar(state, ')'); } -static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context) +static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context) { - bool need_parens = false; + if (type_cast->arg == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected NULL arg in TypeCast"))); + if (type_cast->typeName == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected NULL typeName in TypeCast"))); - Assert(type_cast->typeName != NULL); + bool need_parens = needsParensAsBExpr(type_cast->arg); - if (IsA(type_cast->arg, A_Expr) || context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) + if (context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) { - appendStringInfoString(str, "CAST("); - deparseExpr(str, type_cast->arg, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " AS "); - deparseTypeName(str, type_cast->typeName); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "CAST("); + deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, type_cast->typeName); + deparseAppendStringInfoChar(state, ')'); return; } @@ -3736,8 +4308,8 @@ static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeCont char *typename = strVal(lsecond(type_cast->typeName->names)); if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) { - appendStringInfoString(str, "char "); - deparseAConst(str, a_const); + deparseAppendStringInfoString(state, "char "); + deparseAConst(state, a_const); return; } else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) @@ -3749,20 +4321,20 @@ static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeCont char *const_val = strVal(&a_const->val); if (strcmp(const_val, "t") == 0) { - appendStringInfoString(str, "true"); + deparseAppendStringInfoString(state, "true"); return; } if (strcmp(const_val, "f") == 0) { - appendStringInfoString(str, "false"); + deparseAppendStringInfoString(state, "false"); return; } } else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) { - appendStringInfoString(str, "interval "); - deparseAConst(str, a_const); - deparseIntervalTypmods(str, type_cast->typeName); + deparseAppendStringInfoString(state, "interval "); + deparseAConst(state, a_const); + deparseIntervalTypmods(state, type_cast->typeName); return; } } @@ -3777,164 +4349,169 @@ static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeCont strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && a_const->location > type_cast->typeName->location) { - appendStringInfoString(str, " point "); - deparseAConst(str, a_const); + deparseAppendStringInfoString(state, " point "); + deparseAConst(state, a_const); return; } } if (need_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, type_cast->arg, DEPARSE_NODE_CONTEXT_NONE /* could be either a_expr or b_expr (we could pass this down, but that'd require two kinds of contexts most likely) */); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_NONE /* could be either a_expr or b_expr (we could pass this down, but that'd require two kinds of contexts most likely) */); if (need_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); - appendStringInfoString(str, "::"); - deparseTypeName(str, type_cast->typeName); + deparseAppendStringInfoString(state, "::"); + deparseTypeName(state, type_cast->typeName); } -static void deparseTypeName(StringInfo str, TypeName *type_name) +static void deparseTypeName(DeparseState *state, TypeName *type_name) { + if (type_name == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected NULL TypeName in protobuf input"))); + ListCell *lc; bool skip_typmods = false; if (type_name->setof) - appendStringInfoString(str, "SETOF "); + deparseAppendStringInfoString(state, "SETOF "); if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) { const char *name = strVal(lsecond(type_name->names)); if (strcmp(name, "bpchar") == 0) { - appendStringInfoString(str, "char"); + deparseAppendStringInfoString(state, "char"); } else if (strcmp(name, "varchar") == 0) { - appendStringInfoString(str, "varchar"); + deparseAppendStringInfoString(state, "varchar"); } else if (strcmp(name, "numeric") == 0) { - appendStringInfoString(str, "numeric"); + deparseAppendStringInfoString(state, "numeric"); } else if (strcmp(name, "bool") == 0) { - appendStringInfoString(str, "boolean"); + deparseAppendStringInfoString(state, "boolean"); } else if (strcmp(name, "int2") == 0) { - appendStringInfoString(str, "smallint"); + deparseAppendStringInfoString(state, "smallint"); } else if (strcmp(name, "int4") == 0) { - appendStringInfoString(str, "int"); + deparseAppendStringInfoString(state, "int"); } else if (strcmp(name, "int8") == 0) { - appendStringInfoString(str, "bigint"); + deparseAppendStringInfoString(state, "bigint"); } else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) { - appendStringInfoString(str, "real"); + deparseAppendStringInfoString(state, "real"); } else if (strcmp(name, "float8") == 0) { - appendStringInfoString(str, "double precision"); + deparseAppendStringInfoString(state, "double precision"); } else if (strcmp(name, "time") == 0) { - appendStringInfoString(str, "time"); + deparseAppendStringInfoString(state, "time"); } else if (strcmp(name, "timetz") == 0) { - appendStringInfoString(str, "time "); + deparseAppendStringInfoString(state, "time "); if (list_length(type_name->typmods) > 0) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, type_name->typmods) { - deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); if (lnext(type_name->typmods, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } - appendStringInfoString(str, "with time zone"); + deparseAppendStringInfoString(state, "with time zone"); skip_typmods = true; } else if (strcmp(name, "timestamp") == 0) { - appendStringInfoString(str, "timestamp"); + deparseAppendStringInfoString(state, "timestamp"); } else if (strcmp(name, "timestamptz") == 0) { - appendStringInfoString(str, "timestamp "); + deparseAppendStringInfoString(state, "timestamp "); if (list_length(type_name->typmods) > 0) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, type_name->typmods) { - deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); if (lnext(type_name->typmods, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } - appendStringInfoString(str, "with time zone"); + deparseAppendStringInfoString(state, "with time zone"); skip_typmods = true; } else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) { - appendStringInfoString(str, "interval"); + deparseAppendStringInfoString(state, "interval"); } else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) { - appendStringInfoString(str, "interval"); - deparseIntervalTypmods(str, type_name); + deparseAppendStringInfoString(state, "interval"); + deparseIntervalTypmods(state, type_name); skip_typmods = true; } else { - appendStringInfoString(str, "pg_catalog."); - appendStringInfoString(str, name); + deparseAppendStringInfoString(state, "pg_catalog."); + deparseAppendStringInfoString(state, name); } } else { - deparseAnyName(str, type_name->names); + deparseAnyName(state, type_name->names); } if (list_length(type_name->typmods) > 0 && !skip_typmods) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, type_name->typmods) { if (IsA(lfirst(lc), A_Const)) - deparseAConst(str, lfirst(lc)); + deparseAConst(state, lfirst(lc)); else if (IsA(lfirst(lc), ParamRef)) - deparseParamRef(str, lfirst(lc)); + deparseParamRef(state, lfirst(lc)); else if (IsA(lfirst(lc), ColumnRef)) - deparseColumnRef(str, lfirst(lc)); + deparseColumnRef(state, lfirst(lc)); else Assert(false); if (lnext(type_name->typmods, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } foreach(lc, type_name->arrayBounds) { - appendStringInfoChar(str, '['); + deparseAppendStringInfoChar(state, '['); if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) - deparseSignedIconst(str, lfirst(lc)); - appendStringInfoChar(str, ']'); + deparseSignedIconst(state, lfirst(lc)); + deparseAppendStringInfoChar(state, ']'); } if (type_name->pct_type) - appendStringInfoString(str, "%type"); + deparseAppendStringInfoString(state, "%type"); } // Handle typemods for Interval types separately @@ -3942,7 +4519,7 @@ static void deparseTypeName(StringInfo str, TypeName *type_name) // For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` // the `INTERVAL` keyword is specified first. // In all other contexts, intervals use the `'x'::interval` style. -static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) +static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name) { const char *name = strVal(lsecond(type_name->names)); Assert(strcmp(name, "interval") == 0); @@ -3956,43 +4533,43 @@ static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) switch (fields) { case INTERVAL_MASK(YEAR): - appendStringInfoString(str, " year"); + deparseAppendStringInfoString(state, " year"); break; case INTERVAL_MASK(MONTH): - appendStringInfoString(str, " month"); + deparseAppendStringInfoString(state, " month"); break; case INTERVAL_MASK(DAY): - appendStringInfoString(str, " day"); + deparseAppendStringInfoString(state, " day"); break; case INTERVAL_MASK(HOUR): - appendStringInfoString(str, " hour"); + deparseAppendStringInfoString(state, " hour"); break; case INTERVAL_MASK(MINUTE): - appendStringInfoString(str, " minute"); + deparseAppendStringInfoString(state, " minute"); break; case INTERVAL_MASK(SECOND): - appendStringInfoString(str, " second"); + deparseAppendStringInfoString(state, " second"); break; case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): - appendStringInfoString(str, " year to month"); + deparseAppendStringInfoString(state, " year to month"); break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): - appendStringInfoString(str, " day to hour"); + deparseAppendStringInfoString(state, " day to hour"); break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): - appendStringInfoString(str, " day to minute"); + deparseAppendStringInfoString(state, " day to minute"); break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): - appendStringInfoString(str, " day to second"); + deparseAppendStringInfoString(state, " day to second"); break; case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): - appendStringInfoString(str, " hour to minute"); + deparseAppendStringInfoString(state, " hour to minute"); break; case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): - appendStringInfoString(str, " hour to second"); + deparseAppendStringInfoString(state, " hour to second"); break; case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): - appendStringInfoString(str, " minute to second"); + deparseAppendStringInfoString(state, " minute to second"); break; case INTERVAL_FULL_RANGE: // Nothing @@ -4006,66 +4583,70 @@ static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) { int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); if (precision != INTERVAL_FULL_PRECISION) - appendStringInfo(str, "(%d)", precision); + deparseAppendStringInfo(state, "(%d)", precision); } } -static void deparseNullTest(StringInfo str, NullTest *null_test) +static void deparseNullTest(DeparseState *state, NullTest *null_test) { // argisrow is always false in raw parser output Assert(null_test->argisrow == false); - deparseExpr(str, (Node *) null_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, (Node *) null_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); switch (null_test->nulltesttype) { case IS_NULL: - appendStringInfoString(str, " IS NULL"); + deparseAppendStringInfoString(state, " IS NULL"); break; case IS_NOT_NULL: - appendStringInfoString(str, " IS NOT NULL"); + deparseAppendStringInfoString(state, " IS NOT NULL"); break; } } // "case_expr" in gram.y -static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr) { ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; - appendStringInfoString(str, "CASE "); + deparseAppendStringInfoString(state, "CASE "); if (case_expr->arg != NULL) { - deparseExpr(str, (Node *) case_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseExpr(state, (Node *) case_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, case_expr->args) { - deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseCaseWhen(state, castNode(CaseWhen, lfirst(lc))); } if (case_expr->defresult != NULL) { - appendStringInfoString(str, "ELSE "); - deparseExpr(str, (Node *) case_expr->defresult, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "ELSE", DEPARSE_PART_INDENT); + deparseExpr(state, (Node *) case_expr->defresult, DEPARSE_NODE_CONTEXT_A_EXPR); } - appendStringInfoString(str, "END"); + deparseAppendStringInfoChar(state, ' '); + deparseStateDecreaseNestingLevel(state, parent_level); + + deparseAppendStringInfoString(state, "END"); } // "when_clause" in gram.y -static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when) { - appendStringInfoString(str, "WHEN "); - deparseExpr(str, (Node *) case_when->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " THEN "); - deparseExpr(str, (Node *) case_when->result, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendPartGroup(state, "WHEN", DEPARSE_PART_INDENT); + deparseExpr(state, (Node *) case_when->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " THEN "); + deparseExpr(state, (Node *) case_when->result, DEPARSE_NODE_CONTEXT_A_EXPR); } -static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection) { ListCell *lc; bool need_parens = @@ -4078,81 +4659,81 @@ static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) IsA(a_indirection->arg, JsonFuncExpr); if (need_parens) - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); - deparseExpr(str, a_indirection->arg, need_parens ? DEPARSE_NODE_CONTEXT_A_EXPR : DEPARSE_NODE_CONTEXT_NONE); + deparseExpr(state, a_indirection->arg, need_parens ? DEPARSE_NODE_CONTEXT_A_EXPR : DEPARSE_NODE_CONTEXT_NONE); if (need_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); - deparseOptIndirection(str, a_indirection->indirection, 0); + deparseOptIndirection(state, a_indirection->indirection, 0); } -static void deparseAIndices(StringInfo str, A_Indices *a_indices) +static void deparseAIndices(DeparseState *state, A_Indices *a_indices) { - appendStringInfoChar(str, '['); + deparseAppendStringInfoChar(state, '['); if (a_indices->lidx != NULL) - deparseExpr(str, a_indices->lidx, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, a_indices->lidx, DEPARSE_NODE_CONTEXT_A_EXPR); if (a_indices->is_slice) - appendStringInfoChar(str, ':'); + deparseAppendStringInfoChar(state, ':'); if (a_indices->uidx != NULL) - deparseExpr(str, a_indices->uidx, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ']'); + deparseExpr(state, a_indices->uidx, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ']'); } -static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr) { - appendStringInfoString(str, "COALESCE("); - deparseExprList(str, coalesce_expr->args); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "COALESCE("); + deparseExprList(state, coalesce_expr->args); + deparseAppendStringInfoChar(state, ')'); } -static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr) { switch (min_max_expr->op) { case IS_GREATEST: - appendStringInfoString(str, "GREATEST("); + deparseAppendStringInfoString(state, "GREATEST("); break; case IS_LEAST: - appendStringInfoString(str, "LEAST("); + deparseAppendStringInfoString(state, "LEAST("); break; } - deparseExprList(str, min_max_expr->args); - appendStringInfoChar(str, ')'); + deparseExprList(state, min_max_expr->args); + deparseAppendStringInfoChar(state, ')'); } -static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test) { bool need_parens = IsA(boolean_test->arg, BoolExpr); if (need_parens) - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); - deparseExpr(str, (Node *) boolean_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, (Node *) boolean_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); switch (boolean_test->booltesttype) { case IS_TRUE: - appendStringInfoString(str, " IS TRUE"); + deparseAppendStringInfoString(state, " IS TRUE"); break; case IS_NOT_TRUE: - appendStringInfoString(str, " IS NOT TRUE"); + deparseAppendStringInfoString(state, " IS NOT TRUE"); break; case IS_FALSE: - appendStringInfoString(str, " IS FALSE"); + deparseAppendStringInfoString(state, " IS FALSE"); break; case IS_NOT_FALSE: - appendStringInfoString(str, " IS NOT FALSE"); + deparseAppendStringInfoString(state, " IS NOT FALSE"); break; case IS_UNKNOWN: - appendStringInfoString(str, " IS UNKNOWN"); + deparseAppendStringInfoString(state, " IS UNKNOWN"); break; case IS_NOT_UNKNOWN: - appendStringInfoString(str, " IS NOT UNKNOWN"); + deparseAppendStringInfoString(state, " IS NOT UNKNOWN"); break; default: Assert(false); @@ -4160,64 +4741,64 @@ static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) } // "columnDef" and "alter_table_cmd" in gram.y -static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +static void deparseColumnDef(DeparseState *state, ColumnDef *column_def) { ListCell *lc; if (column_def->colname != NULL) { - appendStringInfoString(str, quote_identifier(column_def->colname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(column_def->colname)); + deparseAppendStringInfoChar(state, ' '); } if (column_def->typeName != NULL) { - deparseTypeName(str, column_def->typeName); - appendStringInfoChar(str, ' '); + deparseTypeName(state, column_def->typeName); + deparseAppendStringInfoChar(state, ' '); } if (column_def->storage_name) { - appendStringInfoString(str, "STORAGE "); - appendStringInfoString(str, column_def->storage_name); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "STORAGE "); + deparseAppendStringInfoString(state, column_def->storage_name); + deparseAppendStringInfoChar(state, ' '); } if (column_def->raw_default != NULL) { - appendStringInfoString(str, "USING "); - deparseExpr(str, column_def->raw_default, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseExpr(state, column_def->raw_default, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } if (column_def->compression != NULL) { - appendStringInfoString(str, "COMPRESSION "); - appendStringInfoString(str, column_def->compression); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "COMPRESSION "); + deparseAppendStringInfoString(state, column_def->compression); + deparseAppendStringInfoChar(state, ' '); } if (column_def->fdwoptions != NULL) { - deparseCreateGenericOptions(str, column_def->fdwoptions); - appendStringInfoChar(str, ' '); + deparseCreateGenericOptions(state, column_def->fdwoptions); + deparseAppendStringInfoChar(state, ' '); } foreach(lc, column_def->constraints) { - deparseConstraint(str, castNode(Constraint, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseConstraint(state, castNode(Constraint, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } if (column_def->collClause != NULL) { - deparseCollateClause(str, column_def->collClause); + deparseCollateClause(state, column_def->collClause); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseInsertOverride(StringInfo str, OverridingKind override) +static void deparseInsertOverride(DeparseState *state, OverridingKind override) { switch (override) { @@ -4225,101 +4806,103 @@ static void deparseInsertOverride(StringInfo str, OverridingKind override) // Do nothing break; case OVERRIDING_USER_VALUE: - appendStringInfoString(str, "OVERRIDING USER VALUE "); + deparseAppendStringInfoString(state, "OVERRIDING USER VALUE "); break; case OVERRIDING_SYSTEM_VALUE: - appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + deparseAppendStringInfoString(state, "OVERRIDING SYSTEM VALUE "); break; } } -static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt) { ListCell *lc; ListCell *lc2; + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); if (insert_stmt->withClause != NULL) { - deparseWithClause(str, insert_stmt->withClause); - appendStringInfoChar(str, ' '); + deparseWithClause(state, insert_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "INSERT INTO "); - deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "INSERT INTO", DEPARSE_PART_INDENT); + deparseRangeVar(state, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + deparseAppendStringInfoChar(state, ' '); if (list_length(insert_stmt->cols) > 0) { - appendStringInfoChar(str, '('); - deparseInsertColumnList(str, insert_stmt->cols); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseInsertColumnList(state, insert_stmt->cols); + deparseAppendStringInfoString(state, ") "); } - deparseInsertOverride(str, insert_stmt->override); + deparseInsertOverride(state, insert_stmt->override); if (insert_stmt->selectStmt != NULL) { - deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); - appendStringInfoChar(str, ' '); + deparseSelectStmt(state, castNode(SelectStmt, insert_stmt->selectStmt), DEPARSE_NODE_CONTEXT_INSERT_SELECT); + deparseAppendStringInfoChar(state, ' '); } else { - appendStringInfoString(str, "DEFAULT VALUES "); + deparseAppendStringInfoString(state, "DEFAULT VALUES "); } if (insert_stmt->onConflictClause != NULL) { - deparseOnConflictClause(str, insert_stmt->onConflictClause); - appendStringInfoChar(str, ' '); + deparseOnConflictClause(state, insert_stmt->onConflictClause); + deparseAppendStringInfoChar(state, ' '); } if (list_length(insert_stmt->returningList) > 0) { - appendStringInfoString(str, "RETURNING "); - deparseTargetList(str, insert_stmt->returningList); + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, insert_stmt->returningList); } - removeTrailingSpace(str); + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); } -static void deparseInferClause(StringInfo str, InferClause *infer_clause) +static void deparseInferClause(DeparseState *state, InferClause *infer_clause) { ListCell *lc; if (list_length(infer_clause->indexElems) > 0) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, infer_clause->indexElems) { - deparseIndexElem(str, lfirst(lc)); + deparseIndexElem(state, lfirst(lc)); if (lnext(infer_clause->indexElems, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } if (infer_clause->conname != NULL) { - appendStringInfoString(str, "ON CONSTRAINT "); - appendStringInfoString(str, quote_identifier(infer_clause->conname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ON CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(infer_clause->conname)); + deparseAppendStringInfoChar(state, ' '); } - deparseWhereClause(str, infer_clause->whereClause); + deparseWhereClause(state, infer_clause->whereClause); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause) { ListCell *lc; - appendStringInfoString(str, "ON CONFLICT "); + deparseAppendPartGroup(state, "ON CONFLICT", DEPARSE_PART_INDENT); if (on_conflict_clause->infer != NULL) { - deparseInferClause(str, on_conflict_clause->infer); - appendStringInfoChar(str, ' '); + deparseInferClause(state, on_conflict_clause->infer); + deparseAppendStringInfoChar(state, ' '); } switch (on_conflict_clause->action) @@ -4328,140 +4911,145 @@ static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflic Assert(false); break; case ONCONFLICT_NOTHING: - appendStringInfoString(str, "DO NOTHING "); + deparseAppendStringInfoString(state, "DO NOTHING "); break; case ONCONFLICT_UPDATE: - appendStringInfoString(str, "DO UPDATE "); + deparseAppendStringInfoString(state, "DO UPDATE "); break; } if (list_length(on_conflict_clause->targetList) > 0) { - appendStringInfoString(str, "SET "); - deparseSetClauseList(str, on_conflict_clause->targetList); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); + deparseSetClauseList(state, on_conflict_clause->targetList); + deparseAppendStringInfoChar(state, ' '); } - deparseWhereClause(str, on_conflict_clause->whereClause); + deparseWhereClause(state, on_conflict_clause->whereClause); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt) { ListCell* lc; ListCell* lc2; ListCell* lc3; + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); if (update_stmt->withClause != NULL) { - deparseWithClause(str, update_stmt->withClause); - appendStringInfoChar(str, ' '); + deparseWithClause(state, update_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "UPDATE "); - deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "UPDATE", DEPARSE_PART_INDENT); + deparseRangeVar(state, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (list_length(update_stmt->targetList) > 0) { - appendStringInfoString(str, "SET "); - deparseSetClauseList(str, update_stmt->targetList); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); + deparseSetClauseList(state, update_stmt->targetList); + deparseAppendStringInfoChar(state, ' '); } - deparseFromClause(str, update_stmt->fromClause); - deparseWhereOrCurrentClause(str, update_stmt->whereClause); + deparseFromClause(state, update_stmt->fromClause); + deparseWhereOrCurrentClause(state, update_stmt->whereClause); if (list_length(update_stmt->returningList) > 0) { - appendStringInfoString(str, "RETURNING "); - deparseTargetList(str, update_stmt->returningList); + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, update_stmt->returningList); } - removeTrailingSpace(str); + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); } // "MergeStmt" in gram.y -static void deparseMergeStmt(StringInfo str, MergeStmt *merge_stmt) +static void deparseMergeStmt(DeparseState *state, MergeStmt *merge_stmt) { + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + if (merge_stmt->withClause != NULL) { - deparseWithClause(str, merge_stmt->withClause); - appendStringInfoChar(str, ' '); + deparseWithClause(state, merge_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "MERGE INTO "); - deparseRangeVar(str, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "MERGE", DEPARSE_PART_INDENT); + deparseAppendStringInfoString(state, "INTO "); + deparseRangeVar(state, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "USING "); - deparseTableRef(str, merge_stmt->sourceRelation); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); + deparseTableRef(state, merge_stmt->sourceRelation); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "ON "); - deparseExpr(str, merge_stmt->joinCondition, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ON "); + deparseExpr(state, merge_stmt->joinCondition, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); ListCell *lc; foreach (lc, merge_stmt->mergeWhenClauses) { MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); - appendStringInfoString(str, "WHEN "); + deparseAppendStringInfoString(state, "WHEN "); switch (clause->matchKind) { case MERGE_WHEN_MATCHED: - appendStringInfoString(str, "MATCHED "); + deparseAppendStringInfoString(state, "MATCHED "); break; case MERGE_WHEN_NOT_MATCHED_BY_SOURCE: - appendStringInfoString(str, "NOT MATCHED BY SOURCE "); + deparseAppendStringInfoString(state, "NOT MATCHED BY SOURCE "); break; case MERGE_WHEN_NOT_MATCHED_BY_TARGET: - appendStringInfoString(str, "NOT MATCHED "); + deparseAppendStringInfoString(state, "NOT MATCHED "); break; } if (clause->condition) { - appendStringInfoString(str, "AND "); - deparseExpr(str, clause->condition, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "AND "); + deparseExpr(state, clause->condition, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "THEN "); + deparseAppendStringInfoString(state, "THEN "); switch (clause->commandType) { case CMD_INSERT: - appendStringInfoString(str, "INSERT "); + deparseAppendStringInfoString(state, "INSERT "); if (clause->targetList) { - appendStringInfoChar(str, '('); - deparseInsertColumnList(str, clause->targetList); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseInsertColumnList(state, clause->targetList); + deparseAppendStringInfoString(state, ") "); } - deparseInsertOverride(str, clause->override); + deparseInsertOverride(state, clause->override); if (clause->values) { - appendStringInfoString(str, "VALUES ("); - deparseExprList(str, clause->values); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, "VALUES ("); + deparseExprList(state, clause->values); + deparseAppendStringInfoString(state, ")"); } else { - appendStringInfoString(str, "DEFAULT VALUES "); + deparseAppendStringInfoString(state, "DEFAULT VALUES "); } break; case CMD_UPDATE: - appendStringInfoString(str, "UPDATE SET "); - deparseSetClauseList(str, clause->targetList); + deparseAppendStringInfoString(state, "UPDATE SET "); + deparseSetClauseList(state, clause->targetList); break; case CMD_DELETE: - appendStringInfoString(str, "DELETE"); + deparseAppendStringInfoString(state, "DELETE"); break; case CMD_NOTHING: - appendStringInfoString(str, "DO NOTHING"); + deparseAppendStringInfoString(state, "DO NOTHING"); break; default: elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); @@ -4469,47 +5057,53 @@ static void deparseMergeStmt(StringInfo str, MergeStmt *merge_stmt) } if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } if (merge_stmt->returningList) { - appendStringInfoString(str, " RETURNING "); - deparseTargetList(str, merge_stmt->returningList); + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, merge_stmt->returningList); } + + deparseStateDecreaseNestingLevel(state, parent_level); } -static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt) { + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + if (delete_stmt->withClause != NULL) { - deparseWithClause(str, delete_stmt->withClause); - appendStringInfoChar(str, ' '); + deparseWithClause(state, delete_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "DELETE FROM "); - deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "DELETE", DEPARSE_PART_INDENT); + deparseAppendStringInfoString(state, "FROM "); + deparseRangeVar(state, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (delete_stmt->usingClause != NULL) { - appendStringInfoString(str, "USING "); - deparseFromList(str, delete_stmt->usingClause); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); + deparseFromList(state, delete_stmt->usingClause); + deparseAppendStringInfoChar(state, ' '); } - deparseWhereOrCurrentClause(str, delete_stmt->whereClause); + deparseWhereOrCurrentClause(state, delete_stmt->whereClause); if (list_length(delete_stmt->returningList) > 0) { - appendStringInfoString(str, "RETURNING "); - deparseTargetList(str, delete_stmt->returningList); + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, delete_stmt->returningList); } - removeTrailingSpace(str); + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); } -static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause) { ListCell *lc; @@ -4520,79 +5114,80 @@ static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) Assert(false); break; case LCS_FORKEYSHARE: - appendStringInfoString(str, "FOR KEY SHARE "); + deparseAppendPartGroup(state, "FOR KEY SHARE", DEPARSE_PART_INDENT); break; case LCS_FORSHARE: - appendStringInfoString(str, "FOR SHARE "); + deparseAppendPartGroup(state, "FOR SHARE", DEPARSE_PART_INDENT); break; case LCS_FORNOKEYUPDATE: - appendStringInfoString(str, "FOR NO KEY UPDATE "); + deparseAppendPartGroup(state, "FOR NO KEY UPDATE", DEPARSE_PART_INDENT); break; case LCS_FORUPDATE: - appendStringInfoString(str, "FOR UPDATE "); + deparseAppendPartGroup(state, "FOR UPDATE", DEPARSE_PART_INDENT); break; } if (list_length(locking_clause->lockedRels) > 0) { - appendStringInfoString(str, "OF "); - deparseQualifiedNameList(str, locking_clause->lockedRels); + deparseAppendStringInfoString(state, "OF "); + deparseQualifiedNameList(state, locking_clause->lockedRels); + deparseAppendStringInfoChar(state, ' '); } switch (locking_clause->waitPolicy) { case LockWaitError: - appendStringInfoString(str, "NOWAIT"); + deparseAppendStringInfoString(state, "NOWAIT"); break; case LockWaitSkip: - appendStringInfoString(str, "SKIP LOCKED"); + deparseAppendStringInfoString(state, "SKIP LOCKED"); break; case LockWaitBlock: // Default break; } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default) { - appendStringInfoString(str, "DEFAULT"); + deparseAppendStringInfoString(state, "DEFAULT"); } -static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt) { ListCell *lc; ListCell *lc2; - appendStringInfoString(str, "CREATE CAST ("); - deparseTypeName(str, create_cast_stmt->sourcetype); - appendStringInfoString(str, " AS "); - deparseTypeName(str, create_cast_stmt->targettype); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "CREATE CAST ("); + deparseTypeName(state, create_cast_stmt->sourcetype); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, create_cast_stmt->targettype); + deparseAppendStringInfoString(state, ") "); if (create_cast_stmt->func != NULL) { - appendStringInfoString(str, "WITH FUNCTION "); - deparseFunctionWithArgtypes(str, create_cast_stmt->func); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_cast_stmt->func); + deparseAppendStringInfoChar(state, ' '); } else if (create_cast_stmt->inout) { - appendStringInfoString(str, "WITH INOUT "); + deparseAppendStringInfoString(state, "WITH INOUT "); } else { - appendStringInfoString(str, "WITHOUT FUNCTION "); + deparseAppendStringInfoString(state, "WITHOUT FUNCTION "); } switch (create_cast_stmt->context) { case COERCION_IMPLICIT: - appendStringInfoString(str, "AS IMPLICIT"); + deparseAppendStringInfoString(state, "AS IMPLICIT"); break; case COERCION_ASSIGNMENT: - appendStringInfoString(str, "AS ASSIGNMENT"); + deparseAppendStringInfoString(state, "AS ASSIGNMENT"); break; case COERCION_PLPGSQL: // Not present in raw parser output @@ -4604,174 +5199,174 @@ static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_st } } -static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +static void deparseCreateOpClassStmt(DeparseState *state, CreateOpClassStmt *create_op_class_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "CREATE OPERATOR CLASS "); + deparseAppendStringInfoString(state, "CREATE OPERATOR CLASS "); - deparseAnyName(str, create_op_class_stmt->opclassname); - appendStringInfoChar(str, ' '); + deparseAnyName(state, create_op_class_stmt->opclassname); + deparseAppendStringInfoChar(state, ' '); if (create_op_class_stmt->isDefault) - appendStringInfoString(str, "DEFAULT "); + deparseAppendStringInfoString(state, "DEFAULT "); - appendStringInfoString(str, "FOR TYPE "); - deparseTypeName(str, create_op_class_stmt->datatype); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR TYPE "); + deparseTypeName(state, create_op_class_stmt->datatype); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_op_class_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); if (create_op_class_stmt->opfamilyname != NULL) { - appendStringInfoString(str, "FAMILY "); - deparseAnyName(str, create_op_class_stmt->opfamilyname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FAMILY "); + deparseAnyName(state, create_op_class_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "AS "); - deparseOpclassItemList(str, create_op_class_stmt->items); + deparseAppendStringInfoString(state, "AS "); + deparseOpclassItemList(state, create_op_class_stmt->items); } -static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +static void deparseCreateOpFamilyStmt(DeparseState *state, CreateOpFamilyStmt *create_op_family_stmt) { - appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + deparseAppendStringInfoString(state, "CREATE OPERATOR FAMILY "); - deparseAnyName(str, create_op_family_stmt->opfamilyname); - appendStringInfoChar(str, ' '); + deparseAnyName(state, create_op_family_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_op_family_stmt->amname)); } -static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item) { ListCell *lc = NULL; switch (create_op_class_item->itemtype) { case OPCLASS_ITEM_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - appendStringInfo(str, "%d ", create_op_class_item->number); + deparseAppendStringInfoString(state, "OPERATOR "); + deparseAppendStringInfo(state, "%d ", create_op_class_item->number); if (create_op_class_item->name != NULL) { if (create_op_class_item->name->objargs != NULL) - deparseOperatorWithArgtypes(str, create_op_class_item->name); + deparseOperatorWithArgtypes(state, create_op_class_item->name); else - deparseAnyOperator(str, create_op_class_item->name->objname); - appendStringInfoChar(str, ' '); + deparseAnyOperator(state, create_op_class_item->name->objname); + deparseAppendStringInfoChar(state, ' '); } if (create_op_class_item->order_family != NULL) { - appendStringInfoString(str, "FOR ORDER BY "); - deparseAnyName(str, create_op_class_item->order_family); + deparseAppendStringInfoString(state, "FOR ORDER BY "); + deparseAnyName(state, create_op_class_item->order_family); } if (create_op_class_item->class_args != NULL) { - appendStringInfoChar(str, '('); - deparseTypeList(str, create_op_class_item->class_args); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, create_op_class_item->class_args); + deparseAppendStringInfoChar(state, ')'); } - removeTrailingSpace(str); + removeTrailingSpace(state); break; case OPCLASS_ITEM_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - appendStringInfo(str, "%d ", create_op_class_item->number); + deparseAppendStringInfoString(state, "FUNCTION "); + deparseAppendStringInfo(state, "%d ", create_op_class_item->number); if (create_op_class_item->class_args != NULL) { - appendStringInfoChar(str, '('); - deparseTypeList(str, create_op_class_item->class_args); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, create_op_class_item->class_args); + deparseAppendStringInfoString(state, ") "); } if (create_op_class_item->name != NULL) - deparseFunctionWithArgtypes(str, create_op_class_item->name); - removeTrailingSpace(str); + deparseFunctionWithArgtypes(state, create_op_class_item->name); + removeTrailingSpace(state); break; case OPCLASS_ITEM_STORAGETYPE: - appendStringInfoString(str, "STORAGE "); - deparseTypeName(str, create_op_class_item->storedtype); + deparseAppendStringInfoString(state, "STORAGE "); + deparseTypeName(state, create_op_class_item->storedtype); break; default: Assert(false); } } -static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +static void deparseTableLikeClause(DeparseState *state, TableLikeClause *table_like_clause) { - appendStringInfoString(str, "LIKE "); - deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "LIKE "); + deparseRangeVar(state, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) - appendStringInfoString(str, "INCLUDING ALL "); + deparseAppendStringInfoString(state, "INCLUDING ALL "); else { if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) - appendStringInfoString(str, "INCLUDING COMMENTS "); + deparseAppendStringInfoString(state, "INCLUDING COMMENTS "); if (table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) - appendStringInfoString(str, "INCLUDING COMPRESSION "); + deparseAppendStringInfoString(state, "INCLUDING COMPRESSION "); if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) - appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + deparseAppendStringInfoString(state, "INCLUDING CONSTRAINTS "); if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) - appendStringInfoString(str, "INCLUDING DEFAULTS "); + deparseAppendStringInfoString(state, "INCLUDING DEFAULTS "); if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) - appendStringInfoString(str, "INCLUDING IDENTITY "); + deparseAppendStringInfoString(state, "INCLUDING IDENTITY "); if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) - appendStringInfoString(str, "INCLUDING GENERATED "); + deparseAppendStringInfoString(state, "INCLUDING GENERATED "); if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) - appendStringInfoString(str, "INCLUDING INDEXES "); + deparseAppendStringInfoString(state, "INCLUDING INDEXES "); if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) - appendStringInfoString(str, "INCLUDING STATISTICS "); + deparseAppendStringInfoString(state, "INCLUDING STATISTICS "); if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) - appendStringInfoString(str, "INCLUDING STORAGE "); + deparseAppendStringInfoString(state, "INCLUDING STORAGE "); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt) { ListCell *lc; Assert(create_domain_stmt->typeName != NULL); - appendStringInfoString(str, "CREATE DOMAIN "); - deparseAnyName(str, create_domain_stmt->domainname); - appendStringInfoString(str, " AS "); + deparseAppendStringInfoString(state, "CREATE DOMAIN "); + deparseAnyName(state, create_domain_stmt->domainname); + deparseAppendStringInfoString(state, " AS "); - deparseTypeName(str, create_domain_stmt->typeName); - appendStringInfoChar(str, ' '); + deparseTypeName(state, create_domain_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); if (create_domain_stmt->collClause != NULL) { - deparseCollateClause(str, create_domain_stmt->collClause); - appendStringInfoChar(str, ' '); + deparseCollateClause(state, create_domain_stmt->collClause); + deparseAppendStringInfoChar(state, ' '); } foreach(lc, create_domain_stmt->constraints) { - deparseConstraint(str, castNode(Constraint, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseConstraint(state, castNode(Constraint, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +static void deparseCreateExtensionStmt(DeparseState *state, CreateExtensionStmt *create_extension_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "CREATE EXTENSION "); + deparseAppendStringInfoString(state, "CREATE EXTENSION "); if (create_extension_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - deparseColId(str, create_extension_stmt->extname); - appendStringInfoChar(str, ' '); + deparseColId(state, create_extension_stmt->extname); + deparseAppendStringInfoChar(state, ' '); foreach (lc, create_extension_stmt->options) { @@ -4779,129 +5374,129 @@ static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *crea if (strcmp(def_elem->defname, "schema") == 0) { - appendStringInfoString(str, "SCHEMA "); - deparseColId(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "SCHEMA "); + deparseColId(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "new_version") == 0) { - appendStringInfoString(str, "VERSION "); - deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "VERSION "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "cascade") == 0) { - appendStringInfoString(str, "CASCADE"); + deparseAppendStringInfoString(state, "CASCADE"); } else { Assert(false); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } // "ColConstraintElem" and "ConstraintElem" in gram.y -static void deparseConstraint(StringInfo str, Constraint *constraint) +static void deparseConstraint(DeparseState *state, Constraint *constraint) { ListCell *lc; if (constraint->conname != NULL) { - appendStringInfoString(str, "CONSTRAINT "); - appendStringInfoString(str, quote_identifier(constraint->conname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(constraint->conname)); + deparseAppendStringInfoChar(state, ' '); } switch (constraint->contype) { case CONSTR_NULL: - appendStringInfoString(str, "NULL "); + deparseAppendStringInfoString(state, "NULL "); break; case CONSTR_NOTNULL: - appendStringInfoString(str, "NOT NULL "); + deparseAppendStringInfoString(state, "NOT NULL "); break; case CONSTR_DEFAULT: - appendStringInfoString(str, "DEFAULT "); - deparseBExpr(str, constraint->raw_expr); + deparseAppendStringInfoString(state, "DEFAULT "); + deparseBExpr(state, constraint->raw_expr); break; case CONSTR_IDENTITY: - appendStringInfoString(str, "GENERATED "); + deparseAppendStringInfoString(state, "GENERATED "); switch (constraint->generated_when) { case ATTRIBUTE_IDENTITY_ALWAYS: - appendStringInfoString(str, "ALWAYS "); + deparseAppendStringInfoString(state, "ALWAYS "); break; case ATTRIBUTE_IDENTITY_BY_DEFAULT: - appendStringInfoString(str, "BY DEFAULT "); + deparseAppendStringInfoString(state, "BY DEFAULT "); break; default: Assert(false); } - appendStringInfoString(str, "AS IDENTITY "); - deparseOptParenthesizedSeqOptList(str, constraint->options); + deparseAppendStringInfoString(state, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(state, constraint->options); break; case CONSTR_GENERATED: Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); - appendStringInfoString(str, "GENERATED ALWAYS AS ("); - deparseExpr(str, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") STORED "); + deparseAppendStringInfoString(state, "GENERATED ALWAYS AS ("); + deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") STORED "); break; case CONSTR_CHECK: - appendStringInfoString(str, "CHECK ("); - deparseExpr(str, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "CHECK ("); + deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); break; case CONSTR_PRIMARY: - appendStringInfoString(str, "PRIMARY KEY "); + deparseAppendStringInfoString(state, "PRIMARY KEY "); break; case CONSTR_UNIQUE: - appendStringInfoString(str, "UNIQUE "); + deparseAppendStringInfoString(state, "UNIQUE "); if (constraint->nulls_not_distinct) - appendStringInfoString(str, "NULLS NOT DISTINCT "); + deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); break; case CONSTR_EXCLUSION: - appendStringInfoString(str, "EXCLUDE "); + deparseAppendStringInfoString(state, "EXCLUDE "); if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(constraint->access_method)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(constraint->access_method)); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, constraint->exclusions) { List *exclusion = castNode(List, lfirst(lc)); Assert(list_length(exclusion) == 2); - deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); - appendStringInfoString(str, " WITH "); - deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + deparseIndexElem(state, castNode(IndexElem, linitial(exclusion))); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyOperator(state, castNode(List, lsecond(exclusion))); if (lnext(constraint->exclusions, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); if (constraint->where_clause != NULL) { - appendStringInfoString(str, "WHERE ("); - deparseExpr(str, constraint->where_clause, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "WHERE ("); + deparseExpr(state, constraint->where_clause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } break; case CONSTR_FOREIGN: if (list_length(constraint->fk_attrs) > 0) - appendStringInfoString(str, "FOREIGN KEY "); + deparseAppendStringInfoString(state, "FOREIGN KEY "); break; case CONSTR_ATTR_DEFERRABLE: - appendStringInfoString(str, "DEFERRABLE "); + deparseAppendStringInfoString(state, "DEFERRABLE "); break; case CONSTR_ATTR_NOT_DEFERRABLE: - appendStringInfoString(str, "NOT DEFERRABLE "); + deparseAppendStringInfoString(state, "NOT DEFERRABLE "); break; case CONSTR_ATTR_DEFERRED: - appendStringInfoString(str, "INITIALLY DEFERRED "); + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); break; case CONSTR_ATTR_IMMEDIATE: - appendStringInfoString(str, "INITIALLY IMMEDIATE "); + deparseAppendStringInfoString(state, "INITIALLY IMMEDIATE "); break; } @@ -4915,29 +5510,29 @@ static void deparseConstraint(StringInfo str, Constraint *constraint) } if (!valueOnly) { - appendStringInfoChar(str, '('); - deparseColumnList(str, constraint->keys); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, constraint->keys); + deparseAppendStringInfoString(state, ") "); } } if (list_length(constraint->fk_attrs) > 0) { - appendStringInfoChar(str, '('); - deparseColumnList(str, constraint->fk_attrs); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, constraint->fk_attrs); + deparseAppendStringInfoString(state, ") "); } if (constraint->pktable != NULL) { - appendStringInfoString(str, "REFERENCES "); - deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "REFERENCES "); + deparseRangeVar(state, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (list_length(constraint->pk_attrs) > 0) { - appendStringInfoChar(str, '('); - deparseColumnList(str, constraint->pk_attrs); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, constraint->pk_attrs); + deparseAppendStringInfoString(state, ") "); } } @@ -4947,7 +5542,7 @@ static void deparseConstraint(StringInfo str, Constraint *constraint) // Default break; case FKCONSTR_MATCH_FULL: - appendStringInfoString(str, "MATCH FULL "); + deparseAppendStringInfoString(state, "MATCH FULL "); break; case FKCONSTR_MATCH_PARTIAL: // Not implemented in Postgres @@ -4964,16 +5559,16 @@ static void deparseConstraint(StringInfo str, Constraint *constraint) // Default break; case FKCONSTR_ACTION_RESTRICT: - appendStringInfoString(str, "ON UPDATE RESTRICT "); + deparseAppendStringInfoString(state, "ON UPDATE RESTRICT "); break; case FKCONSTR_ACTION_CASCADE: - appendStringInfoString(str, "ON UPDATE CASCADE "); + deparseAppendStringInfoString(state, "ON UPDATE CASCADE "); break; case FKCONSTR_ACTION_SETNULL: - appendStringInfoString(str, "ON UPDATE SET NULL "); + deparseAppendStringInfoString(state, "ON UPDATE SET NULL "); break; case FKCONSTR_ACTION_SETDEFAULT: - appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + deparseAppendStringInfoString(state, "ON UPDATE SET DEFAULT "); break; default: // Not specified @@ -4986,29 +5581,29 @@ static void deparseConstraint(StringInfo str, Constraint *constraint) // Default break; case FKCONSTR_ACTION_RESTRICT: - appendStringInfoString(str, "ON DELETE RESTRICT "); + deparseAppendStringInfoString(state, "ON DELETE RESTRICT "); break; case FKCONSTR_ACTION_CASCADE: - appendStringInfoString(str, "ON DELETE CASCADE "); + deparseAppendStringInfoString(state, "ON DELETE CASCADE "); break; case FKCONSTR_ACTION_SETNULL: case FKCONSTR_ACTION_SETDEFAULT: - appendStringInfoString(str, "ON DELETE SET "); + deparseAppendStringInfoString(state, "ON DELETE SET "); switch (constraint->fk_del_action) { - case FKCONSTR_ACTION_SETDEFAULT: appendStringInfoString(str, "DEFAULT "); break; - case FKCONSTR_ACTION_SETNULL: appendStringInfoString(str, "NULL "); break; + case FKCONSTR_ACTION_SETDEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); break; + case FKCONSTR_ACTION_SETNULL: deparseAppendStringInfoString(state, "NULL "); break; } if (constraint->fk_del_set_cols) { - appendStringInfoString(str, "("); + deparseAppendStringInfoString(state, "("); ListCell *lc; foreach (lc, constraint->fk_del_set_cols) { - appendStringInfoString(str, strVal(lfirst(lc))); + deparseAppendStringInfoString(state, strVal(lfirst(lc))); if (lfirst(lc) != llast(constraint->fk_del_set_cols)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ")"); } break; default: @@ -5018,9 +5613,9 @@ static void deparseConstraint(StringInfo str, Constraint *constraint) if (list_length(constraint->including) > 0) { - appendStringInfoString(str, "INCLUDE ("); - deparseColumnList(str, constraint->including); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "INCLUDE ("); + deparseColumnList(state, constraint->including); + deparseAppendStringInfoString(state, ") "); } switch (constraint->contype) @@ -5028,98 +5623,98 @@ static void deparseConstraint(StringInfo str, Constraint *constraint) case CONSTR_PRIMARY: case CONSTR_UNIQUE: case CONSTR_EXCLUSION: - deparseOptWith(str, constraint->options); + deparseOptWith(state, constraint->options); break; default: break; } if (constraint->indexname != NULL) - appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + deparseAppendStringInfo(state, "USING INDEX %s ", quote_identifier(constraint->indexname)); if (constraint->indexspace != NULL) - appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + deparseAppendStringInfo(state, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); if (constraint->deferrable) - appendStringInfoString(str, "DEFERRABLE "); + deparseAppendStringInfoString(state, "DEFERRABLE "); if (constraint->initdeferred) - appendStringInfoString(str, "INITIALLY DEFERRED "); + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); if (constraint->is_no_inherit) - appendStringInfoString(str, "NO INHERIT "); + deparseAppendStringInfoString(state, "NO INHERIT "); if (constraint->skip_validation) - appendStringInfoString(str, "NOT VALID "); + deparseAppendStringInfoString(state, "NOT VALID "); - removeTrailingSpace(str); + removeTrailingSpace(state); } // "ReturnStmt" in gram.y -static void deparseReturnStmt(StringInfo str, ReturnStmt *return_stmt) +static void deparseReturnStmt(DeparseState *state, ReturnStmt *return_stmt) { - appendStringInfoString(str, "RETURN "); - deparseExpr(str, return_stmt->returnval, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, "RETURN "); + deparseExpr(state, return_stmt->returnval, DEPARSE_NODE_CONTEXT_A_EXPR); } -static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +static void deparseCreateFunctionStmt(DeparseState *state, CreateFunctionStmt *create_function_stmt) { ListCell *lc; bool tableFunc = false; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (create_function_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); if (create_function_stmt->is_procedure) - appendStringInfoString(str, "PROCEDURE "); + deparseAppendStringInfoString(state, "PROCEDURE "); else - appendStringInfoString(str, "FUNCTION "); + deparseAppendStringInfoString(state, "FUNCTION "); - deparseFuncName(str, create_function_stmt->funcname); + deparseFuncName(state, create_function_stmt->funcname); - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, create_function_stmt->parameters) { FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); if (function_parameter->mode != FUNC_PARAM_TABLE) { - deparseFunctionParameter(str, function_parameter); + deparseFunctionParameter(state, function_parameter); if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } else { tableFunc = true; } } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); if (tableFunc) { - appendStringInfoString(str, "RETURNS TABLE ("); + deparseAppendStringInfoString(state, "RETURNS TABLE ("); foreach(lc, create_function_stmt->parameters) { FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); if (function_parameter->mode == FUNC_PARAM_TABLE) { - deparseFunctionParameter(str, function_parameter); + deparseFunctionParameter(state, function_parameter); if (lnext(create_function_stmt->parameters, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } else if (create_function_stmt->returnType != NULL) { - appendStringInfoString(str, "RETURNS "); - deparseTypeName(str, create_function_stmt->returnType); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "RETURNS "); + deparseTypeName(state, create_function_stmt->returnType); + deparseAppendStringInfoChar(state, ' '); } foreach(lc, create_function_stmt->options) { - deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseCreateFuncOptItem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } if (create_function_stmt->sql_body) @@ -5128,11 +5723,11 @@ static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create */ if (IsA(create_function_stmt->sql_body, ReturnStmt)) { - deparseReturnStmt(str, castNode(ReturnStmt, create_function_stmt->sql_body)); + deparseReturnStmt(state, castNode(ReturnStmt, create_function_stmt->sql_body)); } else { - appendStringInfoString(str, "BEGIN ATOMIC "); + deparseAppendStringInfoString(state, "BEGIN ATOMIC "); if (IsA(create_function_stmt->sql_body, List), linitial((List *) create_function_stmt->sql_body) != NULL) { List *body_stmt_list = castNode(List, linitial((List *) create_function_stmt->sql_body)); @@ -5140,40 +5735,40 @@ static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create { if (IsA(lfirst(lc), ReturnStmt)) { - deparseReturnStmt(str, lfirst_node(ReturnStmt, lc)); - appendStringInfoString(str, "; "); + deparseReturnStmt(state, lfirst_node(ReturnStmt, lc)); + deparseAppendStringInfoString(state, "; "); } else { - deparseStmt(str, lfirst(lc)); - appendStringInfoString(str, "; "); + deparseStmt(state, lfirst(lc)); + deparseAppendStringInfoString(state, "; "); } } } - appendStringInfoString(str, "END "); + deparseAppendStringInfoString(state, "END "); } } - removeTrailingSpace(str); + removeTrailingSpace(state); } // "func_arg", "func_arg_with_default" and other places in gram.y -static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter) { switch (function_parameter->mode) { case FUNC_PARAM_IN: /* input only */ - appendStringInfoString(str, "IN "); + deparseAppendStringInfoString(state, "IN "); break; case FUNC_PARAM_OUT: /* output only */ - appendStringInfoString(str, "OUT "); + deparseAppendStringInfoString(state, "OUT "); break; case FUNC_PARAM_INOUT: /* both */ - appendStringInfoString(str, "INOUT "); + deparseAppendStringInfoString(state, "INOUT "); break; case FUNC_PARAM_VARIADIC: /* variadic (always input) */ - appendStringInfoString(str, "VARIADIC "); + deparseAppendStringInfoString(state, "VARIADIC "); break; case FUNC_PARAM_TABLE: /* table function output column */ // No special annotation, the caller is expected to correctly put @@ -5189,204 +5784,204 @@ static void deparseFunctionParameter(StringInfo str, FunctionParameter *function if (function_parameter->name != NULL) { - appendStringInfoString(str, function_parameter->name); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, function_parameter->name); + deparseAppendStringInfoChar(state, ' '); } - deparseTypeName(str, function_parameter->argType); - appendStringInfoChar(str, ' '); + deparseTypeName(state, function_parameter->argType); + deparseAppendStringInfoChar(state, ' '); if (function_parameter->defexpr != NULL) { - appendStringInfoString(str, "= "); - deparseExpr(str, function_parameter->defexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, "= "); + deparseExpr(state, function_parameter->defexpr, DEPARSE_NODE_CONTEXT_A_EXPR); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +static void deparseCheckPointStmt(DeparseState *state, CheckPointStmt *check_point_stmt) { - appendStringInfoString(str, "CHECKPOINT"); + deparseAppendStringInfoString(state, "CHECKPOINT"); } -static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +static void deparseCreateSchemaStmt(DeparseState *state, CreateSchemaStmt *create_schema_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE SCHEMA "); + deparseAppendStringInfoString(state, "CREATE SCHEMA "); if (create_schema_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); if (create_schema_stmt->schemaname) { - deparseColId(str, create_schema_stmt->schemaname); - appendStringInfoChar(str, ' '); + deparseColId(state, create_schema_stmt->schemaname); + deparseAppendStringInfoChar(state, ' '); } if (create_schema_stmt->authrole != NULL) { - appendStringInfoString(str, "AUTHORIZATION "); - deparseRoleSpec(str, create_schema_stmt->authrole); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "AUTHORIZATION "); + deparseRoleSpec(state, create_schema_stmt->authrole); + deparseAppendStringInfoChar(state, ' '); } if (create_schema_stmt->schemaElts) { foreach(lc, create_schema_stmt->schemaElts) { - deparseSchemaStmt(str, lfirst(lc)); + deparseSchemaStmt(state, lfirst(lc)); if (lnext(create_schema_stmt->schemaElts, lc)) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +static void deparseAlterRoleSetStmt(DeparseState *state, AlterRoleSetStmt *alter_role_set_stmt) { - appendStringInfoString(str, "ALTER ROLE "); + deparseAppendStringInfoString(state, "ALTER ROLE "); if (alter_role_set_stmt->role == NULL) - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); else - deparseRoleSpec(str, alter_role_set_stmt->role); + deparseRoleSpec(state, alter_role_set_stmt->role); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (alter_role_set_stmt->database != NULL) { - appendStringInfoString(str, "IN DATABASE "); - appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "IN DATABASE "); + deparseAppendStringInfoString(state, quote_identifier(alter_role_set_stmt->database)); + deparseAppendStringInfoChar(state, ' '); } - deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); + deparseVariableSetStmt(state, alter_role_set_stmt->setstmt); } -static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +static void deparseCreateConversionStmt(DeparseState *state, CreateConversionStmt *create_conversion_stmt) { - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (create_conversion_stmt->def) - appendStringInfoString(str, "DEFAULT "); + deparseAppendStringInfoString(state, "DEFAULT "); - appendStringInfoString(str, "CONVERSION "); - deparseAnyName(str, create_conversion_stmt->conversion_name); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, create_conversion_stmt->conversion_name); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "FOR "); - deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); - appendStringInfoString(str, " TO "); - deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + deparseAppendStringInfoString(state, "FOR "); + deparseStringLiteral(state, create_conversion_stmt->for_encoding_name); + deparseAppendStringInfoString(state, " TO "); + deparseStringLiteral(state, create_conversion_stmt->to_encoding_name); - appendStringInfoString(str, "FROM "); - deparseAnyName(str, create_conversion_stmt->func_name); + deparseAppendStringInfoString(state, "FROM "); + deparseAnyName(state, create_conversion_stmt->func_name); } -static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec) { switch (role_spec->roletype) { case ROLESPEC_CSTRING: Assert(role_spec->rolename != NULL); - appendStringInfoString(str, quote_identifier(role_spec->rolename)); + deparseAppendStringInfoString(state, quote_identifier(role_spec->rolename)); break; case ROLESPEC_CURRENT_ROLE: - appendStringInfoString(str, "CURRENT_ROLE"); + deparseAppendStringInfoString(state, "CURRENT_ROLE"); break; case ROLESPEC_CURRENT_USER: - appendStringInfoString(str, "CURRENT_USER"); + deparseAppendStringInfoString(state, "CURRENT_USER"); break; case ROLESPEC_SESSION_USER: - appendStringInfoString(str, "SESSION_USER"); + deparseAppendStringInfoString(state, "SESSION_USER"); break; case ROLESPEC_PUBLIC: - appendStringInfoString(str, "public"); + deparseAppendStringInfoString(state, "public"); break; } } // "part_elem" in gram.y -static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +static void deparsePartitionElem(DeparseState *state, PartitionElem *partition_elem) { ListCell *lc; if (partition_elem->name != NULL) { - deparseColId(str, partition_elem->name); - appendStringInfoChar(str, ' '); + deparseColId(state, partition_elem->name); + deparseAppendStringInfoChar(state, ' '); } else if (partition_elem->expr != NULL) { - appendStringInfoChar(str, '('); - deparseExpr(str, partition_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, partition_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } - deparseOptCollate(str, partition_elem->collation); - deparseAnyName(str, partition_elem->opclass); + deparseOptCollate(state, partition_elem->collation); + deparseAnyName(state, partition_elem->opclass); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +static void deparsePartitionSpec(DeparseState *state, PartitionSpec *partition_spec) { ListCell *lc; - appendStringInfoString(str, "PARTITION BY "); + deparseAppendPartGroup(state, "PARTITION BY", DEPARSE_PART_INDENT); switch (partition_spec->strategy) { case PARTITION_STRATEGY_LIST: - appendStringInfoString(str, "LIST"); + deparseAppendStringInfoString(state, "LIST"); break; case PARTITION_STRATEGY_HASH: - appendStringInfoString(str, "HASH"); + deparseAppendStringInfoString(state, "HASH"); break; case PARTITION_STRATEGY_RANGE: - appendStringInfoString(str, "RANGE"); + deparseAppendStringInfoString(state, "RANGE"); break; } - appendStringInfoChar(str, '('); + deparseAppendStringInfoString(state, " ("); foreach(lc, partition_spec->partParams) { - deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + deparsePartitionElem(state, castNode(PartitionElem, lfirst(lc))); if (lnext(partition_spec->partParams, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } -static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +static void deparsePartitionBoundSpec(DeparseState *state, PartitionBoundSpec *partition_bound_spec) { ListCell *lc; if (partition_bound_spec->is_default) { - appendStringInfoString(str, "DEFAULT"); + deparseAppendStringInfoString(state, "DEFAULT"); return; } - appendStringInfoString(str, "FOR VALUES "); + deparseAppendStringInfoString(state, "FOR VALUES "); switch (partition_bound_spec->strategy) { case PARTITION_STRATEGY_HASH: - appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + deparseAppendStringInfo(state, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); break; case PARTITION_STRATEGY_LIST: - appendStringInfoString(str, "IN ("); - deparseExprList(str, partition_bound_spec->listdatums); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "IN ("); + deparseExprList(state, partition_bound_spec->listdatums); + deparseAppendStringInfoChar(state, ')'); break; case PARTITION_STRATEGY_RANGE: - appendStringInfoString(str, "FROM ("); - deparseExprList(str, partition_bound_spec->lowerdatums); - appendStringInfoString(str, ") TO ("); - deparseExprList(str, partition_bound_spec->upperdatums); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "FROM ("); + deparseExprList(state, partition_bound_spec->lowerdatums); + deparseAppendStringInfoString(state, ") TO ("); + deparseExprList(state, partition_bound_spec->upperdatums); + deparseAppendStringInfoChar(state, ')'); break; default: Assert(false); @@ -5394,113 +5989,116 @@ static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partit } } -static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +static void deparsePartitionCmd(DeparseState *state, PartitionCmd *partition_cmd) { - deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); if (partition_cmd->bound != NULL) { - appendStringInfoChar(str, ' '); - deparsePartitionBoundSpec(str, partition_cmd->bound); + deparseAppendStringInfoChar(state, ' '); + deparsePartitionBoundSpec(state, partition_cmd->bound); } if (partition_cmd->concurrent) - appendStringInfoString(str, " CONCURRENTLY "); + deparseAppendStringInfoString(state, " CONCURRENTLY "); } // "TableElement" in gram.y -static void deparseTableElement(StringInfo str, Node *node) +static void deparseTableElement(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_ColumnDef: - deparseColumnDef(str, castNode(ColumnDef, node)); + deparseColumnDef(state, castNode(ColumnDef, node)); break; case T_TableLikeClause: - deparseTableLikeClause(str, castNode(TableLikeClause, node)); + deparseTableLikeClause(state, castNode(TableLikeClause, node)); break; case T_Constraint: - deparseConstraint(str, castNode(Constraint, node)); + deparseConstraint(state, castNode(Constraint, node)); break; default: Assert(false); } } -static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +static void deparseCreateStmt(DeparseState *state, CreateStmt *create_stmt, bool is_foreign_table) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (is_foreign_table) - appendStringInfoString(str, "FOREIGN "); + deparseAppendStringInfoString(state, "FOREIGN "); - deparseOptTemp(str, create_stmt->relation->relpersistence); + deparseOptTemp(state, create_stmt->relation->relpersistence); - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); if (create_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (create_stmt->ofTypename != NULL) { - appendStringInfoString(str, "OF "); - deparseTypeName(str, create_stmt->ofTypename); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "OF "); + deparseTypeName(state, create_stmt->ofTypename); + deparseAppendStringInfoChar(state, ' '); } if (create_stmt->partbound != NULL) { Assert(list_length(create_stmt->inhRelations) == 1); - appendStringInfoString(str, "PARTITION OF "); - deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "PARTITION OF "); + deparseRangeVar(state, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); } if (list_length(create_stmt->tableElts) > 0) { + DeparseStateNestingLevel *parent_level = NULL; // In raw parse output tableElts contains both columns and constraints // (and the constraints field is NIL) - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); + parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, create_stmt->tableElts) { - deparseTableElement(str, lfirst(lc)); + deparseTableElement(state, lfirst(lc)); if (lnext(create_stmt->tableElts, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } - appendStringInfoString(str, ") "); + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoString(state, ") "); } else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) { - appendStringInfoString(str, "() "); + deparseAppendStringInfoString(state, "() "); } if (create_stmt->partbound != NULL) { - deparsePartitionBoundSpec(str, create_stmt->partbound); - appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(state, create_stmt->partbound); + deparseAppendStringInfoChar(state, ' '); } else { - deparseOptInherit(str, create_stmt->inhRelations); + deparseOptInherit(state, create_stmt->inhRelations); } if (create_stmt->partspec != NULL) { - deparsePartitionSpec(str, create_stmt->partspec); - appendStringInfoChar(str, ' '); + deparsePartitionSpec(state, create_stmt->partspec); + deparseAppendStringInfoChar(state, ' '); } if (create_stmt->accessMethod != NULL) { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_stmt->accessMethod)); } - deparseOptWith(str, create_stmt->options); + deparseOptWith(state, create_stmt->options); switch (create_stmt->oncommit) { @@ -5508,276 +6106,276 @@ static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_f // No ON COMMIT clause break; case ONCOMMIT_PRESERVE_ROWS: - appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); break; case ONCOMMIT_DELETE_ROWS: - appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); break; case ONCOMMIT_DROP: - appendStringInfoString(str, "ON COMMIT DROP "); + deparseAppendStringInfoString(state, "ON COMMIT DROP "); break; } if (create_stmt->tablespacename != NULL) { - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(create_stmt->tablespacename)); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +static void deparseCreateFdwStmt(DeparseState *state, CreateFdwStmt *create_fdw_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); - appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CREATE FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(create_fdw_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); if (list_length(create_fdw_stmt->func_options) > 0) { - deparseFdwOptions(str, create_fdw_stmt->func_options); - appendStringInfoChar(str, ' '); + deparseFdwOptions(state, create_fdw_stmt->func_options); + deparseAppendStringInfoChar(state, ' '); } - deparseCreateGenericOptions(str, create_fdw_stmt->options); + deparseCreateGenericOptions(state, create_fdw_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +static void deparseAlterFdwStmt(DeparseState *state, AlterFdwStmt *alter_fdw_stmt) { - appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); - appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(alter_fdw_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); if (list_length(alter_fdw_stmt->func_options) > 0) { - deparseFdwOptions(str, alter_fdw_stmt->func_options); - appendStringInfoChar(str, ' '); + deparseFdwOptions(state, alter_fdw_stmt->func_options); + deparseAppendStringInfoChar(state, ' '); } if (list_length(alter_fdw_stmt->options) > 0) - deparseAlterGenericOptions(str, alter_fdw_stmt->options); + deparseAlterGenericOptions(state, alter_fdw_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +static void deparseCreateForeignServerStmt(DeparseState *state, CreateForeignServerStmt *create_foreign_server_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE SERVER "); + deparseAppendStringInfoString(state, "CREATE SERVER "); if (create_foreign_server_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); if (create_foreign_server_stmt->servertype != NULL) { - appendStringInfoString(str, "TYPE "); - deparseStringLiteral(str, create_foreign_server_stmt->servertype); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TYPE "); + deparseStringLiteral(state, create_foreign_server_stmt->servertype); + deparseAppendStringInfoChar(state, ' '); } if (create_foreign_server_stmt->version != NULL) { - appendStringInfoString(str, "VERSION "); - deparseStringLiteral(str, create_foreign_server_stmt->version); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "VERSION "); + deparseStringLiteral(state, create_foreign_server_stmt->version); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); - deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + deparseCreateGenericOptions(state, create_foreign_server_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +static void deparseAlterForeignServerStmt(DeparseState *state, AlterForeignServerStmt *alter_foreign_server_stmt) { - appendStringInfoString(str, "ALTER SERVER "); + deparseAppendStringInfoString(state, "ALTER SERVER "); - appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(alter_foreign_server_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); if (alter_foreign_server_stmt->has_version) { - appendStringInfoString(str, "VERSION "); + deparseAppendStringInfoString(state, "VERSION "); if (alter_foreign_server_stmt->version != NULL) - deparseStringLiteral(str, alter_foreign_server_stmt->version); + deparseStringLiteral(state, alter_foreign_server_stmt->version); else - appendStringInfoString(str, "NULL"); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "NULL"); + deparseAppendStringInfoChar(state, ' '); } if (list_length(alter_foreign_server_stmt->options) > 0) - deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + deparseAlterGenericOptions(state, alter_foreign_server_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +static void deparseCreateUserMappingStmt(DeparseState *state, CreateUserMappingStmt *create_user_mapping_stmt) { - appendStringInfoString(str, "CREATE USER MAPPING "); + deparseAppendStringInfoString(state, "CREATE USER MAPPING "); if (create_user_mapping_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - appendStringInfoString(str, "FOR "); - deparseRoleSpec(str, create_user_mapping_stmt->user); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR "); + deparseRoleSpec(state, create_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "SERVER "); - appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(create_user_mapping_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); - deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + deparseCreateGenericOptions(state, create_user_mapping_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +static void deparseCreatedbStmt(DeparseState *state, CreatedbStmt *createdb_stmt) { - appendStringInfoString(str, "CREATE DATABASE "); - deparseColId(str, createdb_stmt->dbname); - appendStringInfoChar(str, ' '); - deparseCreatedbOptList(str, createdb_stmt->options); - removeTrailingSpace(str); + deparseAppendStringInfoString(state, "CREATE DATABASE "); + deparseColId(state, createdb_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseCreatedbOptList(state, createdb_stmt->options); + removeTrailingSpace(state); } -static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +static void deparseAlterUserMappingStmt(DeparseState *state, AlterUserMappingStmt *alter_user_mapping_stmt) { - appendStringInfoString(str, "ALTER USER MAPPING FOR "); - deparseRoleSpec(str, alter_user_mapping_stmt->user); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER USER MAPPING FOR "); + deparseRoleSpec(state, alter_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "SERVER "); - appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(alter_user_mapping_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); - deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + deparseAlterGenericOptions(state, alter_user_mapping_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +static void deparseDropUserMappingStmt(DeparseState *state, DropUserMappingStmt *drop_user_mapping_stmt) { - appendStringInfoString(str, "DROP USER MAPPING "); + deparseAppendStringInfoString(state, "DROP USER MAPPING "); if (drop_user_mapping_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - appendStringInfoString(str, "FOR "); - deparseRoleSpec(str, drop_user_mapping_stmt->user); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR "); + deparseRoleSpec(state, drop_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "SERVER "); - appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(drop_user_mapping_stmt->servername)); } -static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +static void deparseSecLabelStmt(DeparseState *state, SecLabelStmt *sec_label_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "SECURITY LABEL "); + deparseAppendStringInfoString(state, "SECURITY LABEL "); if (sec_label_stmt->provider != NULL) { - appendStringInfoString(str, "FOR "); - appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR "); + deparseAppendStringInfoString(state, quote_identifier(sec_label_stmt->provider)); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "ON "); + deparseAppendStringInfoString(state, "ON "); switch (sec_label_stmt->objtype) { case OBJECT_COLUMN: - appendStringInfoString(str, "COLUMN "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "COLUMN "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "SEQUENCE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "TABLE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "VIEW "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "DATABASE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "PUBLICATION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_ROLE: - appendStringInfoString(str, "ROLE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "ROLE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "TYPE "); + deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "DOMAIN "); + deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); break; case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - deparseValue(str, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseValue(state, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; default: // Not supported in the parser @@ -5785,36 +6383,36 @@ static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) break; } - appendStringInfoString(str, " IS "); + deparseAppendStringInfoString(state, " IS "); if (sec_label_stmt->label != NULL) - deparseStringLiteral(str, sec_label_stmt->label); + deparseStringLiteral(state, sec_label_stmt->label); else - appendStringInfoString(str, "NULL"); + deparseAppendStringInfoString(state, "NULL"); } -static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +static void deparseCreateForeignTableStmt(DeparseState *state, CreateForeignTableStmt *create_foreign_table_stmt) { ListCell *lc; - deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + deparseCreateStmt(state, &create_foreign_table_stmt->base, true); - appendStringInfoString(str, " SERVER "); - appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, " SERVER "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_table_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); if (list_length(create_foreign_table_stmt->options) > 0) - deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + deparseAlterGenericOptions(state, create_foreign_table_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +static void deparseImportForeignSchemaStmt(DeparseState *state, ImportForeignSchemaStmt *import_foreign_schema_stmt) { - appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + deparseAppendStringInfoString(state, "IMPORT FOREIGN SCHEMA "); - appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, import_foreign_schema_stmt->remote_schema); + deparseAppendStringInfoChar(state, ' '); switch (import_foreign_schema_stmt->list_type) { @@ -5822,44 +6420,44 @@ static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaSt // Default break; case FDW_IMPORT_SCHEMA_LIMIT_TO: - appendStringInfoString(str, "LIMIT TO ("); - deparseRelationExprList(str, import_foreign_schema_stmt->table_list); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "LIMIT TO ("); + deparseRelationExprList(state, import_foreign_schema_stmt->table_list); + deparseAppendStringInfoString(state, ") "); break; case FDW_IMPORT_SCHEMA_EXCEPT: - appendStringInfoString(str, "EXCEPT ("); - deparseRelationExprList(str, import_foreign_schema_stmt->table_list); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "EXCEPT ("); + deparseRelationExprList(state, import_foreign_schema_stmt->table_list); + deparseAppendStringInfoString(state, ") "); break; } - appendStringInfoString(str, "FROM SERVER "); - appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FROM SERVER "); + deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->server_name)); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "INTO "); - appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "INTO "); + deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->local_schema)); + deparseAppendStringInfoChar(state, ' '); - deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + deparseCreateGenericOptions(state, import_foreign_schema_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +static void deparseCreateTableAsStmt(DeparseState *state, CreateTableAsStmt *create_table_as_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); - deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + deparseOptTemp(state, create_table_as_stmt->into->rel->relpersistence); switch (create_table_as_stmt->objtype) { case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; default: // Not supported here @@ -5868,51 +6466,50 @@ static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_t } if (create_table_as_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - deparseIntoClause(str, create_table_as_stmt->into); - appendStringInfoChar(str, ' '); + deparseIntoClause(state, create_table_as_stmt->into); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "AS "); + deparseAppendStringInfoString(state, "AS "); if (IsA(create_table_as_stmt->query, ExecuteStmt)) - deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + deparseExecuteStmt(state, castNode(ExecuteStmt, create_table_as_stmt->query)); else - deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); - appendStringInfoChar(str, ' '); + deparseSelectStmt(state, castNode(SelectStmt, create_table_as_stmt->query), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (create_table_as_stmt->into->skipData) - appendStringInfoString(str, "WITH NO DATA "); + deparseAppendStringInfoString(state, "WITH NO DATA "); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (view_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); - deparseOptTemp(str, view_stmt->view->relpersistence); + deparseOptTemp(state, view_stmt->view->relpersistence); - appendStringInfoString(str, "VIEW "); - deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "VIEW "); + deparseRangeVar(state, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (list_length(view_stmt->aliases) > 0) { - appendStringInfoChar(str, '('); - deparseColumnList(str, view_stmt->aliases); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, view_stmt->aliases); + deparseAppendStringInfoString(state, ") "); } - deparseOptWith(str, view_stmt->options); + deparseOptWith(state, view_stmt->options); - appendStringInfoString(str, "AS "); - deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "AS "); + deparseSelectStmt(state, castNode(SelectStmt, view_stmt->query), DEPARSE_NODE_CONTEXT_NONE); switch (view_stmt->withCheckOption) { @@ -5920,129 +6517,129 @@ static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) // Default break; case LOCAL_CHECK_OPTION: - appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + deparseAppendStringInfoString(state, "WITH LOCAL CHECK OPTION "); break; case CASCADED_CHECK_OPTION: - appendStringInfoString(str, "WITH CHECK OPTION "); + deparseAppendStringInfoString(state, "WITH CHECK OPTION "); break; } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +static void deparseDropStmt(DeparseState *state, DropStmt *drop_stmt) { ListCell *lc; List *l; - appendStringInfoString(str, "DROP "); + deparseAppendStringInfoString(state, "DROP "); switch (drop_stmt->removeType) { case OBJECT_ACCESS_METHOD: - appendStringInfoString(str, "ACCESS METHOD "); + deparseAppendStringInfoString(state, "ACCESS METHOD "); break; case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); + deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_CAST: - appendStringInfoString(str, "CAST "); + deparseAppendStringInfoString(state, "CAST "); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); + deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); + deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); + deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_EXTENSION: - appendStringInfoString(str, "EXTENSION "); + deparseAppendStringInfoString(state, "EXTENSION "); break; case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); + deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); + deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); + deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); + deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_POLICY: - appendStringInfoString(str, "POLICY "); + deparseAppendStringInfoString(state, "POLICY "); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); + deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); + deparseAppendStringInfoString(state, "PUBLICATION "); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); + deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_RULE: - appendStringInfoString(str, "RULE "); + deparseAppendStringInfoString(state, "RULE "); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); + deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); + deparseAppendStringInfoString(state, "STATISTICS "); break; case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_TRANSFORM: - appendStringInfoString(str, "TRANSFORM "); + deparseAppendStringInfoString(state, "TRANSFORM "); break; case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); + deparseAppendStringInfoString(state, "TRIGGER "); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); break; default: // Other object types are not supported here in the parser @@ -6050,10 +6647,10 @@ static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) } if (drop_stmt->concurrent) - appendStringInfoString(str, "CONCURRENTLY "); + deparseAppendStringInfoString(state, "CONCURRENTLY "); if (drop_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); switch (drop_stmt->removeType) { @@ -6071,8 +6668,8 @@ static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) case OBJECT_TSDICTIONARY: case OBJECT_TSTEMPLATE: case OBJECT_TSCONFIGURATION: - deparseAnyNameList(str, drop_stmt->objects); - appendStringInfoChar(str, ' '); + deparseAnyNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); break; // drop_type_name case OBJECT_ACCESS_METHOD: @@ -6082,8 +6679,8 @@ static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) case OBJECT_PUBLICATION: case OBJECT_SCHEMA: case OBJECT_FOREIGN_SERVER: - deparseNameList(str, drop_stmt->objects); - appendStringInfoChar(str, ' '); + deparseNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); break; // drop_type_name_on_any_name case OBJECT_POLICY: @@ -6091,299 +6688,299 @@ static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) case OBJECT_TRIGGER: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); - deparseColId(str, strVal(llast(l))); - appendStringInfoString(str, " ON "); - deparseAnyNameSkipLast(str, l); - appendStringInfoChar(str, ' '); + deparseColId(state, strVal(llast(l))); + deparseAppendStringInfoString(state, " ON "); + deparseAnyNameSkipLast(state, l); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_CAST: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); Assert(list_length(l) == 2); - appendStringInfoChar(str, '('); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " AS "); - deparseTypeName(str, castNode(TypeName, lsecond(l))); - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_OPFAMILY: case OBJECT_OPCLASS: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); - appendStringInfoChar(str, ' '); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_TRANSFORM: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); - appendStringInfoString(str, "FOR "); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " LANGUAGE "); - deparseColId(str, strVal(lsecond(l))); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseColId(state, strVal(lsecond(l))); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_LANGUAGE: - deparseNameList(str, drop_stmt->objects); - appendStringInfoChar(str, ' '); + deparseNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_TYPE: case OBJECT_DOMAIN: foreach(lc, drop_stmt->objects) { - deparseTypeName(str, castNode(TypeName, lfirst(lc))); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_AGGREGATE: foreach(lc, drop_stmt->objects) { - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: foreach(lc, drop_stmt->objects) { - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_OPERATOR: foreach(lc, drop_stmt->objects) { - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); break; default: Assert(false); } - deparseOptDropBehavior(str, drop_stmt->behavior); + deparseOptDropBehavior(state, drop_stmt->behavior); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set) { switch(grouping_set->kind) { case GROUPING_SET_EMPTY: - appendStringInfoString(str, "()"); + deparseAppendStringInfoString(state, "()"); break; case GROUPING_SET_SIMPLE: // Not present in raw parse trees Assert(false); break; case GROUPING_SET_ROLLUP: - appendStringInfoString(str, "ROLLUP ("); - deparseExprList(str, grouping_set->content); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "ROLLUP ("); + deparseExprList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); break; case GROUPING_SET_CUBE: - appendStringInfoString(str, "CUBE ("); - deparseExprList(str, grouping_set->content); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "CUBE ("); + deparseExprList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); break; case GROUPING_SET_SETS: - appendStringInfoString(str, "GROUPING SETS ("); - deparseGroupByList(str, grouping_set->content); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "GROUPING SETS ("); + deparseGroupByList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); break; } } -static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +static void deparseDropTableSpaceStmt(DeparseState *state, DropTableSpaceStmt *drop_table_space_stmt) { - appendStringInfoString(str, "DROP TABLESPACE "); + deparseAppendStringInfoString(state, "DROP TABLESPACE "); if (drop_table_space_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - appendStringInfoString(str, drop_table_space_stmt->tablespacename); + deparseAppendStringInfoString(state, drop_table_space_stmt->tablespacename); } -static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +static void deparseAlterObjectDependsStmt(DeparseState *state, AlterObjectDependsStmt *alter_object_depends_stmt) { - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); switch (alter_object_depends_stmt->objectType) { case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); break; case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); - deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "TRIGGER "); + deparseColId(state, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "INDEX "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; default: // No other object types supported here Assert(false); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (alter_object_depends_stmt->remove) - appendStringInfoString(str, "NO "); + deparseAppendStringInfoString(state, "NO "); - appendStringInfo(str, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); + deparseAppendStringInfo(state, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); } -static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +static void deparseAlterObjectSchemaStmt(DeparseState *state, AlterObjectSchemaStmt *alter_object_schema_stmt) { List *l = NULL; ListCell *lc = NULL; - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); switch (alter_object_schema_stmt->objectType) { case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "COLLATION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_EXTENSION: - appendStringInfoString(str, "EXTENSION "); - appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + deparseAppendStringInfoString(state, "EXTENSION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(alter_object_schema_stmt->object))); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "OPERATOR "); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_OPCLASS: l = castNode(List, alter_object_schema_stmt->object); - appendStringInfoString(str, "OPERATOR CLASS "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); break; case OBJECT_OPFAMILY: l = castNode(List, alter_object_schema_stmt->object); - appendStringInfoString(str, "OPERATOR FAMILY "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "STATISTICS "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; default: Assert(false); break; } - appendStringInfoString(str, " SET SCHEMA "); - appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); + deparseAppendStringInfoString(state, " SET SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(alter_object_schema_stmt->newschema)); } // "alter_table_cmd" in gram.y -static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +static void deparseAlterTableCmd(DeparseState *state, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) { ListCell *lc = NULL; const char *options = NULL; @@ -6393,16 +6990,16 @@ static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, { case AT_AddColumn: /* add column */ if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "ADD ATTRIBUTE "); + deparseAppendStringInfoString(state, "ADD ATTRIBUTE "); else - appendStringInfoString(str, "ADD COLUMN "); + deparseAppendStringInfoString(state, "ADD COLUMN "); break; case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ // Not present in raw parser output Assert(false); break; case AT_ColumnDefault: /* alter column default */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); if (alter_table_cmd->def != NULL) options = "SET DEFAULT"; else @@ -6413,15 +7010,15 @@ static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, Assert(false); break; case AT_DropNotNull: /* alter column drop not null */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "DROP NOT NULL"; break; case AT_SetNotNull: /* alter column set not null */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET NOT NULL"; break; case AT_DropExpression: /* alter column drop expression */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "DROP EXPRESSION"; trailing_missing_ok = true; break; @@ -6430,39 +7027,39 @@ static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, Assert(false); break; case AT_SetStatistics: /* alter column set statistics */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET STATISTICS"; break; case AT_SetOptions: /* alter column set ( options ) */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET"; break; case AT_ResetOptions: /* alter column reset ( options ) */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "RESET"; break; case AT_SetStorage: /* alter column set storage */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET STORAGE"; break; case AT_SetCompression: /* alter column set compression */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET COMPRESSION"; break; case AT_DropColumn: /* drop column */ if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "DROP ATTRIBUTE "); + deparseAppendStringInfoString(state, "DROP ATTRIBUTE "); else - appendStringInfoString(str, "DROP "); + deparseAppendStringInfoString(state, "DROP "); break; case AT_AddIndex: /* add index */ - appendStringInfoString(str, "ADD INDEX "); + deparseAppendStringInfoString(state, "ADD INDEX "); break; case AT_ReAddIndex: /* internal to commands/tablecmds.c */ Assert(false); break; case AT_AddConstraint: /* add constraint */ - appendStringInfoString(str, "ADD "); + deparseAppendStringInfoString(state, "ADD "); break; case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ Assert(false); @@ -6471,17 +7068,17 @@ static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, Assert(false); break; case AT_AlterConstraint: /* alter constraint */ - appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + deparseAppendStringInfoString(state, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) break; case AT_ValidateConstraint: /* validate constraint */ - appendStringInfoString(str, "VALIDATE CONSTRAINT "); + deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); break; case AT_AddIndexConstraint: /* add constraint using existing index */ // Not present in raw parser output Assert(false); break; case AT_DropConstraint: /* drop constraint */ - appendStringInfoString(str, "DROP CONSTRAINT "); + deparseAppendStringInfoString(state, "DROP CONSTRAINT "); break; case AT_ReAddComment: /* internal to commands/tablecmds.c */ case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ @@ -6489,284 +7086,287 @@ static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, break; case AT_AlterColumnType: /* alter column type */ if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "ALTER ATTRIBUTE "); + deparseAppendStringInfoString(state, "ALTER ATTRIBUTE "); else - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "TYPE"; break; case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); // Handled via special case in def handling break; case AT_ChangeOwner: /* change owner */ - appendStringInfoString(str, "OWNER TO "); - deparseRoleSpec(str, alter_table_cmd->newowner); + deparseAppendStringInfoString(state, "OWNER TO "); + deparseRoleSpec(state, alter_table_cmd->newowner); break; case AT_ClusterOn: /* CLUSTER ON */ - appendStringInfoString(str, "CLUSTER ON "); + deparseAppendStringInfoString(state, "CLUSTER ON "); break; case AT_DropCluster: /* SET WITHOUT CLUSTER */ - appendStringInfoString(str, "SET WITHOUT CLUSTER "); + deparseAppendStringInfoString(state, "SET WITHOUT CLUSTER "); break; case AT_SetLogged: /* SET LOGGED */ - appendStringInfoString(str, "SET LOGGED "); + deparseAppendStringInfoString(state, "SET LOGGED "); break; case AT_SetUnLogged: /* SET UNLOGGED */ - appendStringInfoString(str, "SET UNLOGGED "); + deparseAppendStringInfoString(state, "SET UNLOGGED "); break; case AT_DropOids: /* SET WITHOUT OIDS */ - appendStringInfoString(str, "SET WITHOUT OIDS "); + deparseAppendStringInfoString(state, "SET WITHOUT OIDS "); break; case AT_SetTableSpace: /* SET TABLESPACE */ - appendStringInfoString(str, "SET TABLESPACE "); + deparseAppendStringInfoString(state, "SET TABLESPACE "); break; case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); break; case AT_SetAccessMethod: - appendStringInfo(str, "SET ACCESS METHOD "); + deparseAppendStringInfo(state, "SET ACCESS METHOD "); break; case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ - appendStringInfoString(str, "RESET "); + deparseAppendStringInfoString(state, "RESET "); break; case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ // Not present in raw parser output Assert(false); break; case AT_EnableTrig: /* ENABLE TRIGGER name */ - appendStringInfoString(str, "ENABLE TRIGGER "); + deparseAppendStringInfoString(state, "ENABLE TRIGGER "); break; case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ - appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + deparseAppendStringInfoString(state, "ENABLE ALWAYS TRIGGER "); break; case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ - appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + deparseAppendStringInfoString(state, "ENABLE REPLICA TRIGGER "); break; case AT_DisableTrig: /* DISABLE TRIGGER name */ - appendStringInfoString(str, "DISABLE TRIGGER "); + deparseAppendStringInfoString(state, "DISABLE TRIGGER "); break; case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ - appendStringInfoString(str, "ENABLE TRIGGER ALL "); + deparseAppendStringInfoString(state, "ENABLE TRIGGER ALL "); break; case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ - appendStringInfoString(str, "DISABLE TRIGGER ALL "); + deparseAppendStringInfoString(state, "DISABLE TRIGGER ALL "); break; case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ - appendStringInfoString(str, "ENABLE TRIGGER USER "); + deparseAppendStringInfoString(state, "ENABLE TRIGGER USER "); break; case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ - appendStringInfoString(str, "DISABLE TRIGGER USER "); + deparseAppendStringInfoString(state, "DISABLE TRIGGER USER "); break; case AT_EnableRule: /* ENABLE RULE name */ - appendStringInfoString(str, "ENABLE RULE "); + deparseAppendStringInfoString(state, "ENABLE RULE "); break; case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ - appendStringInfoString(str, "ENABLE ALWAYS RULE "); + deparseAppendStringInfoString(state, "ENABLE ALWAYS RULE "); break; case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ - appendStringInfoString(str, "ENABLE REPLICA RULE "); + deparseAppendStringInfoString(state, "ENABLE REPLICA RULE "); break; case AT_DisableRule: /* DISABLE RULE name */ - appendStringInfoString(str, "DISABLE RULE "); + deparseAppendStringInfoString(state, "DISABLE RULE "); break; case AT_AddInherit: /* INHERIT parent */ - appendStringInfoString(str, "INHERIT "); + deparseAppendStringInfoString(state, "INHERIT "); break; case AT_DropInherit: /* NO INHERIT parent */ - appendStringInfoString(str, "NO INHERIT "); + deparseAppendStringInfoString(state, "NO INHERIT "); break; case AT_AddOf: /* OF */ - appendStringInfoString(str, "OF "); + deparseAppendStringInfoString(state, "OF "); break; case AT_DropOf: /* NOT OF */ - appendStringInfoString(str, "NOT OF "); + deparseAppendStringInfoString(state, "NOT OF "); break; case AT_ReplicaIdentity: /* REPLICA IDENTITY */ - appendStringInfoString(str, "REPLICA IDENTITY "); + deparseAppendStringInfoString(state, "REPLICA IDENTITY "); break; case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ - appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + deparseAppendStringInfoString(state, "ENABLE ROW LEVEL SECURITY "); break; case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ - appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + deparseAppendStringInfoString(state, "DISABLE ROW LEVEL SECURITY "); break; case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ - appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + deparseAppendStringInfoString(state, "FORCE ROW LEVEL SECURITY "); break; case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ - appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + deparseAppendStringInfoString(state, "NO FORCE ROW LEVEL SECURITY "); break; case AT_GenericOptions: /* OPTIONS (...) */ // Handled in def field handling break; case AT_AttachPartition: /* ATTACH PARTITION */ - appendStringInfoString(str, "ATTACH PARTITION "); + deparseAppendStringInfoString(state, "ATTACH PARTITION "); break; case AT_DetachPartition: /* DETACH PARTITION */ - appendStringInfoString(str, "DETACH PARTITION "); + deparseAppendStringInfoString(state, "DETACH PARTITION "); break; case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ - appendStringInfoString(str, "DETACH PARTITION "); + deparseAppendStringInfoString(state, "DETACH PARTITION "); break; case AT_AddIdentity: /* ADD IDENTITY */ - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); options = "ADD"; // Other details are output via the constraint node (in def field) break; case AT_SetIdentity: /* SET identity column options */ - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); break; case AT_DropIdentity: /* DROP IDENTITY */ - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "DROP IDENTITY"; trailing_missing_ok = true; break; case AT_SetExpression: - appendStringInfoString(str, "ALTER COLUMN "); + deparseAppendStringInfoString(state, "ALTER COLUMN "); break; } if (alter_table_cmd->missing_ok && !trailing_missing_ok) { if (alter_table_cmd->subtype == AT_AddColumn) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); else - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); } if (alter_table_cmd->name != NULL) { - appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(alter_table_cmd->name)); + deparseAppendStringInfoChar(state, ' '); } else if (alter_table_cmd->subtype == AT_SetAccessMethod) { - appendStringInfoString(str, " DEFAULT"); + deparseAppendStringInfoString(state, " DEFAULT"); } if (alter_table_cmd->num > 0) - appendStringInfo(str, "%d ", alter_table_cmd->num); + deparseAppendStringInfo(state, "%d ", alter_table_cmd->num); if (options != NULL) { - appendStringInfoString(str, options); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, options); + deparseAppendStringInfoChar(state, ' '); } if (alter_table_cmd->missing_ok && trailing_missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); switch (alter_table_cmd->subtype) { case AT_AttachPartition: case AT_DetachPartition: - deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_DetachPartitionFinalize: - deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); - appendStringInfoString(str, "FINALIZE "); + deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); + deparseAppendStringInfoString(state, "FINALIZE "); break; case AT_AddColumn: case AT_AlterColumnType: - deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseColumnDef(state, castNode(ColumnDef, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_ColumnDefault: if (alter_table_cmd->def != NULL) { - deparseExpr(str, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); } break; case AT_SetStatistics: - deparseSignedIconst(str, alter_table_cmd->def); - appendStringInfoChar(str, ' '); + if (alter_table_cmd->def != NULL) + deparseSignedIconst(state, alter_table_cmd->def); + else + deparseAppendStringInfoString(state, "DEFAULT"); + deparseAppendStringInfoChar(state, ' '); break; case AT_SetOptions: case AT_ResetOptions: case AT_SetRelOptions: case AT_ResetRelOptions: - deparseRelOptions(str, castNode(List, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseRelOptions(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_SetStorage: - deparseColId(str, strVal(alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseColId(state, strVal(alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_SetCompression: if (strcmp(strVal(alter_table_cmd->def), "default") == 0) - appendStringInfoString(str, "DEFAULT"); + deparseAppendStringInfoString(state, "DEFAULT"); else - deparseColId(str, strVal(alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseColId(state, strVal(alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_AddIdentity: case AT_AddConstraint: case AT_AlterConstraint: - deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseConstraint(state, castNode(Constraint, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_SetIdentity: - deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseAlterIdentityColumnOptionList(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_AlterColumnGenericOptions: case AT_GenericOptions: - deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseAlterGenericOptions(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_AddInherit: case AT_DropInherit: - deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); break; case AT_AddOf: - deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseTypeName(state, castNode(TypeName, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_ReplicaIdentity: - deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); + deparseReplicaIdentityStmt(state, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); break; case AT_SetExpression: - appendStringInfoString(str, "SET EXPRESSION AS ("); - deparseExpr(str, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "SET EXPRESSION AS ("); + deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); break; default: Assert(alter_table_cmd->def == NULL); break; } - deparseOptDropBehavior(str, alter_table_cmd->behavior); + deparseOptDropBehavior(state, alter_table_cmd->behavior); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static DeparseNodeContext deparseAlterTableObjType(StringInfo str, ObjectType type) +static DeparseNodeContext deparseAlterTableObjType(DeparseState *state, ObjectType type) { switch (type) { case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); return DEPARSE_NODE_CONTEXT_ALTER_TYPE; break; default: @@ -6777,108 +7377,111 @@ static DeparseNodeContext deparseAlterTableObjType(StringInfo str, ObjectType ty return DEPARSE_NODE_CONTEXT_NONE; } -static void deparseAlterTableMoveAllStmt(StringInfo str, AlterTableMoveAllStmt *move_all_stmt) +static void deparseAlterTableMoveAllStmt(DeparseState *state, AlterTableMoveAllStmt *move_all_stmt) { - appendStringInfoString(str, "ALTER "); - deparseAlterTableObjType(str, move_all_stmt->objtype); + deparseAppendStringInfoString(state, "ALTER "); + deparseAlterTableObjType(state, move_all_stmt->objtype); - appendStringInfoString(str, "ALL IN TABLESPACE "); - appendStringInfoString(str, move_all_stmt->orig_tablespacename); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALL IN TABLESPACE "); + deparseAppendStringInfoString(state, move_all_stmt->orig_tablespacename); + deparseAppendStringInfoChar(state, ' '); if (move_all_stmt->roles) { - appendStringInfoString(str, "OWNED BY "); - deparseRoleList(str, move_all_stmt->roles); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "OWNED BY "); + deparseRoleList(state, move_all_stmt->roles); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "SET TABLESPACE "); - appendStringInfoString(str, move_all_stmt->new_tablespacename); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "SET TABLESPACE "); + deparseAppendStringInfoString(state, move_all_stmt->new_tablespacename); + deparseAppendStringInfoChar(state, ' '); if (move_all_stmt->nowait) { - appendStringInfoString(str, "NOWAIT"); + deparseAppendStringInfoString(state, "NOWAIT"); } } -static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +static void deparseAlterTableStmt(DeparseState *state, AlterTableStmt *alter_table_stmt) { ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; - appendStringInfoString(str, "ALTER "); - DeparseNodeContext context = deparseAlterTableObjType(str, alter_table_stmt->objtype); + deparseAppendStringInfoString(state, "ALTER "); + DeparseNodeContext context = deparseAlterTableObjType(state, alter_table_stmt->objtype); if (alter_table_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - deparseRangeVar(str, alter_table_stmt->relation, context); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, alter_table_stmt->relation, context); + deparseAppendStringInfoChar(state, ' '); + parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, alter_table_stmt->cmds) { - deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + deparseAlterTableCmd(state, castNode(AlterTableCmd, lfirst(lc)), context); if (lnext(alter_table_stmt->cmds, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } + deparseStateDecreaseNestingLevel(state, parent_level); } -static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +static void deparseAlterTableSpaceOptionsStmt(DeparseState *state, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) { - appendStringInfoString(str, "ALTER TABLESPACE "); - deparseColId(str, alter_table_space_options_stmt->tablespacename); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER TABLESPACE "); + deparseColId(state, alter_table_space_options_stmt->tablespacename); + deparseAppendStringInfoChar(state, ' '); if (alter_table_space_options_stmt->isReset) - appendStringInfoString(str, "RESET "); + deparseAppendStringInfoString(state, "RESET "); else - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); - deparseRelOptions(str, alter_table_space_options_stmt->options); + deparseRelOptions(state, alter_table_space_options_stmt->options); } // "AlterDomainStmt" in gram.y -static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +static void deparseAlterDomainStmt(DeparseState *state, AlterDomainStmt *alter_domain_stmt) { - appendStringInfoString(str, "ALTER DOMAIN "); - deparseAnyName(str, alter_domain_stmt->typeName); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER DOMAIN "); + deparseAnyName(state, alter_domain_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); switch (alter_domain_stmt->subtype) { case 'T': if (alter_domain_stmt->def != NULL) { - appendStringInfoString(str, "SET DEFAULT "); - deparseExpr(str, alter_domain_stmt->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, "SET DEFAULT "); + deparseExpr(state, alter_domain_stmt->def, DEPARSE_NODE_CONTEXT_A_EXPR); } else { - appendStringInfoString(str, "DROP DEFAULT"); + deparseAppendStringInfoString(state, "DROP DEFAULT"); } break; case 'N': - appendStringInfoString(str, "DROP NOT NULL"); + deparseAppendStringInfoString(state, "DROP NOT NULL"); break; case 'O': - appendStringInfoString(str, "SET NOT NULL"); + deparseAppendStringInfoString(state, "SET NOT NULL"); break; case 'C': - appendStringInfoString(str, "ADD "); - deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + deparseAppendStringInfoString(state, "ADD "); + deparseConstraint(state, castNode(Constraint, alter_domain_stmt->def)); break; case 'X': - appendStringInfoString(str, "DROP CONSTRAINT "); + deparseAppendStringInfoString(state, "DROP CONSTRAINT "); if (alter_domain_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); if (alter_domain_stmt->behavior == DROP_CASCADE) - appendStringInfoString(str, " CASCADE"); + deparseAppendStringInfoString(state, " CASCADE"); break; case 'V': - appendStringInfoString(str, "VALIDATE CONSTRAINT "); - appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); break; default: // No other subtypes supported by the parser @@ -6886,137 +7489,137 @@ static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain } } -static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +static void deparseRenameStmt(DeparseState *state, RenameStmt *rename_stmt) { List *l = NULL; - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); switch (rename_stmt->renameType) { case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); + deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); + deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); + deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); + deparseAppendStringInfoString(state, "DATABASE "); break; case OBJECT_DOMAIN: case OBJECT_DOMCONSTRAINT: - appendStringInfoString(str, "DOMAIN "); + deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); + deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_ROLE: - appendStringInfoString(str, "ROLE "); + deparseAppendStringInfoString(state, "ROLE "); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); + deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_POLICY: - appendStringInfoString(str, "POLICY "); + deparseAppendStringInfoString(state, "POLICY "); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); + deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); + deparseAppendStringInfoString(state, "PUBLICATION "); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); + deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); + deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); + deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); + deparseAppendStringInfoString(state, "SUBSCRIPTION "); break; case OBJECT_TABLE: case OBJECT_TABCONSTRAINT: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_COLUMN: switch (rename_stmt->relationType) { case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; default: Assert(false); } break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_RULE: - appendStringInfoString(str, "RULE "); + deparseAppendStringInfoString(state, "RULE "); break; case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); + deparseAppendStringInfoString(state, "TRIGGER "); break; case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); + deparseAppendStringInfoString(state, "TABLESPACE "); break; case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); + deparseAppendStringInfoString(state, "STATISTICS "); break; case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_TYPE: case OBJECT_ATTRIBUTE: - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); break; default: Assert(false); @@ -7024,43 +7627,43 @@ static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) } if (rename_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); switch (rename_stmt->renameType) { case OBJECT_AGGREGATE: - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); - appendStringInfoString(str, " RENAME "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_DOMCONSTRAINT: - deparseAnyName(str, castNode(List, rename_stmt->object)); - appendStringInfoString(str, " RENAME CONSTRAINT "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); + deparseAnyName(state, castNode(List, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_OPCLASS: case OBJECT_OPFAMILY: l = castNode(List, rename_stmt->object); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); - appendStringInfoString(str, " RENAME "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_POLICY: - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); - appendStringInfoString(str, " RENAME "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_SUBSCRIPTION: - deparseColId(str, strVal(rename_stmt->object)); - appendStringInfoString(str, " RENAME "); + deparseColId(state, strVal(rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_TABLE: case OBJECT_SEQUENCE: @@ -7068,42 +7671,42 @@ static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) case OBJECT_MATVIEW: case OBJECT_INDEX: case OBJECT_FOREIGN_TABLE: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_COLUMN: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME COLUMN "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME COLUMN "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_TABCONSTRAINT: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME CONSTRAINT "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); break; case OBJECT_RULE: case OBJECT_TRIGGER: - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_FDW: case OBJECT_LANGUAGE: case OBJECT_PUBLICATION: case OBJECT_FOREIGN_SERVER: case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); - appendStringInfoString(str, " RENAME "); + deparseAppendStringInfoString(state, quote_identifier(strVal(rename_stmt->object))); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_DATABASE: case OBJECT_ROLE: case OBJECT_SCHEMA: case OBJECT_TABLESPACE: - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoString(str, " RENAME "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_COLLATION: case OBJECT_CONVERSION: @@ -7114,80 +7717,80 @@ static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) case OBJECT_TSTEMPLATE: case OBJECT_TSCONFIGURATION: case OBJECT_TYPE: - deparseAnyName(str, castNode(List, rename_stmt->object)); - appendStringInfoString(str, " RENAME "); + deparseAnyName(state, castNode(List, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_ATTRIBUTE: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); - appendStringInfoString(str, " RENAME ATTRIBUTE "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + deparseAppendStringInfoString(state, " RENAME ATTRIBUTE "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); break; default: Assert(false); break; } - appendStringInfoString(str, "TO "); - appendStringInfoString(str, quote_identifier(rename_stmt->newname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TO "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->newname)); + deparseAppendStringInfoChar(state, ' '); - deparseOptDropBehavior(str, rename_stmt->behavior); + deparseOptDropBehavior(state, rename_stmt->behavior); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +static void deparseTransactionStmt(DeparseState *state, TransactionStmt *transaction_stmt) { ListCell *lc; switch (transaction_stmt->kind) { case TRANS_STMT_BEGIN: - appendStringInfoString(str, "BEGIN "); - deparseTransactionModeList(str, transaction_stmt->options); + deparseAppendStringInfoString(state, "BEGIN "); + deparseTransactionModeList(state, transaction_stmt->options); break; case TRANS_STMT_START: - appendStringInfoString(str, "START TRANSACTION "); - deparseTransactionModeList(str, transaction_stmt->options); + deparseAppendStringInfoString(state, "START TRANSACTION "); + deparseTransactionModeList(state, transaction_stmt->options); break; case TRANS_STMT_COMMIT: - appendStringInfoString(str, "COMMIT "); + deparseAppendStringInfoString(state, "COMMIT "); if (transaction_stmt->chain) - appendStringInfoString(str, "AND CHAIN "); + deparseAppendStringInfoString(state, "AND CHAIN "); break; case TRANS_STMT_ROLLBACK: - appendStringInfoString(str, "ROLLBACK "); + deparseAppendStringInfoString(state, "ROLLBACK "); if (transaction_stmt->chain) - appendStringInfoString(str, "AND CHAIN "); + deparseAppendStringInfoString(state, "AND CHAIN "); break; case TRANS_STMT_SAVEPOINT: - appendStringInfoString(str, "SAVEPOINT "); - appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + deparseAppendStringInfoString(state, "SAVEPOINT "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); break; case TRANS_STMT_RELEASE: - appendStringInfoString(str, "RELEASE "); - appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + deparseAppendStringInfoString(state, "RELEASE "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); break; case TRANS_STMT_ROLLBACK_TO: - appendStringInfoString(str, "ROLLBACK "); - appendStringInfoString(str, "TO SAVEPOINT "); - appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + deparseAppendStringInfoString(state, "ROLLBACK "); + deparseAppendStringInfoString(state, "TO SAVEPOINT "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); break; case TRANS_STMT_PREPARE: - appendStringInfoString(str, "PREPARE TRANSACTION "); - deparseStringLiteral(str, transaction_stmt->gid); + deparseAppendStringInfoString(state, "PREPARE TRANSACTION "); + deparseStringLiteral(state, transaction_stmt->gid); break; case TRANS_STMT_COMMIT_PREPARED: - appendStringInfoString(str, "COMMIT PREPARED "); - deparseStringLiteral(str, transaction_stmt->gid); + deparseAppendStringInfoString(state, "COMMIT PREPARED "); + deparseStringLiteral(state, transaction_stmt->gid); break; case TRANS_STMT_ROLLBACK_PREPARED: - appendStringInfoString(str, "ROLLBACK PREPARED "); - deparseStringLiteral(str, transaction_stmt->gid); + deparseAppendStringInfoString(state, "ROLLBACK PREPARED "); + deparseStringLiteral(state, transaction_stmt->gid); break; } - removeTrailingSpace(str); + removeTrailingSpace(state); } // Determine if we hit SET TIME ZONE INTERVAL, that has special syntax not @@ -7206,61 +7809,61 @@ static bool isSetTimeZoneInterval(VariableSetStmt* stmt) strcmp(strVal(llast(typeName->names)), "interval") == 0); } -static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt) { ListCell *lc; switch (variable_set_stmt->kind) { case VAR_SET_VALUE: /* SET var = value */ - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); + deparseAppendStringInfoString(state, "LOCAL "); if (isSetTimeZoneInterval(variable_set_stmt)) { - appendStringInfoString(str, "TIME ZONE "); - deparseVarList(str, variable_set_stmt->args); + deparseAppendStringInfoString(state, "TIME ZONE "); + deparseVarList(state, variable_set_stmt->args); } else { - deparseVarName(str, variable_set_stmt->name); - appendStringInfoString(str, " TO "); - deparseVarList(str, variable_set_stmt->args); + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " TO "); + deparseVarList(state, variable_set_stmt->args); } break; case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); - deparseVarName(str, variable_set_stmt->name); - appendStringInfoString(str, " TO DEFAULT"); + deparseAppendStringInfoString(state, "LOCAL "); + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " TO DEFAULT"); break; case VAR_SET_CURRENT: /* SET var FROM CURRENT */ - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); - deparseVarName(str, variable_set_stmt->name); - appendStringInfoString(str, " FROM CURRENT"); + deparseAppendStringInfoString(state, "LOCAL "); + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " FROM CURRENT"); break; case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ Assert(variable_set_stmt->name != NULL); - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); + deparseAppendStringInfoString(state, "LOCAL "); if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) { - appendStringInfoString(str, "TRANSACTION "); - deparseTransactionModeList(str, variable_set_stmt->args); + deparseAppendStringInfoString(state, "TRANSACTION "); + deparseTransactionModeList(state, variable_set_stmt->args); } else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) { - appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); - deparseTransactionModeList(str, variable_set_stmt->args); + deparseAppendStringInfoString(state, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(state, variable_set_stmt->args); } else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) { - appendStringInfoString(str, "TRANSACTION SNAPSHOT "); - deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + deparseAppendStringInfoString(state, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(state, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); } else { @@ -7268,217 +7871,217 @@ static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set } break; case VAR_RESET: /* RESET var */ - appendStringInfoString(str, "RESET "); - deparseVarName(str, variable_set_stmt->name); + deparseAppendStringInfoString(state, "RESET "); + deparseVarName(state, variable_set_stmt->name); break; case VAR_RESET_ALL: /* RESET ALL */ - appendStringInfoString(str, "RESET ALL"); + deparseAppendStringInfoString(state, "RESET ALL"); break; } } -static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +static void deparseDropdbStmt(DeparseState *state, DropdbStmt *dropdb_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "DROP DATABASE "); + deparseAppendStringInfoString(state, "DROP DATABASE "); if (dropdb_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(dropdb_stmt->dbname)); + deparseAppendStringInfoChar(state, ' '); if (list_length(dropdb_stmt->options) > 0) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc, dropdb_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "force") == 0) - appendStringInfoString(str, "FORCE"); + deparseAppendStringInfoString(state, "FORCE"); else Assert(false); // Currently there are other supported values if (lnext(dropdb_stmt->options, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +static void deparseVacuumStmt(DeparseState *state, VacuumStmt *vacuum_stmt) { ListCell *lc = NULL; ListCell *lc2 = NULL; if (vacuum_stmt->is_vacuumcmd) - appendStringInfoString(str, "VACUUM "); + deparseAppendStringInfoString(state, "VACUUM "); else - appendStringInfoString(str, "ANALYZE "); + deparseAppendStringInfoString(state, "ANALYZE "); - deparseUtilityOptionList(str, vacuum_stmt->options); + deparseUtilityOptionList(state, vacuum_stmt->options); foreach(lc, vacuum_stmt->rels) { Assert(IsA(lfirst(lc), VacuumRelation)); VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); - deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, rel->relation, DEPARSE_NODE_CONTEXT_NONE); if (list_length(rel->va_cols) > 0) { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc2, rel->va_cols) { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc2)))); if (lnext(rel->va_cols, lc2)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } if (lnext(vacuum_stmt->rels, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +static void deparseLoadStmt(DeparseState *state, LoadStmt *load_stmt) { - appendStringInfoString(str, "LOAD "); - deparseStringLiteral(str, load_stmt->filename); + deparseAppendStringInfoString(state, "LOAD "); + deparseStringLiteral(state, load_stmt->filename); } -static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +static void deparseLockStmt(DeparseState *state, LockStmt *lock_stmt) { ListCell *lc; - appendStringInfoString(str, "LOCK TABLE "); + deparseAppendStringInfoString(state, "LOCK TABLE "); - deparseRelationExprList(str, lock_stmt->relations); - appendStringInfoChar(str, ' '); + deparseRelationExprList(state, lock_stmt->relations); + deparseAppendStringInfoChar(state, ' '); if (lock_stmt->mode != AccessExclusiveLock) { - appendStringInfoString(str, "IN "); + deparseAppendStringInfoString(state, "IN "); switch (lock_stmt->mode) { case AccessShareLock: - appendStringInfoString(str, "ACCESS SHARE "); + deparseAppendStringInfoString(state, "ACCESS SHARE "); break; case RowShareLock: - appendStringInfoString(str, "ROW SHARE "); + deparseAppendStringInfoString(state, "ROW SHARE "); break; case RowExclusiveLock: - appendStringInfoString(str, "ROW EXCLUSIVE "); + deparseAppendStringInfoString(state, "ROW EXCLUSIVE "); break; case ShareUpdateExclusiveLock: - appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + deparseAppendStringInfoString(state, "SHARE UPDATE EXCLUSIVE "); break; case ShareLock: - appendStringInfoString(str, "SHARE "); + deparseAppendStringInfoString(state, "SHARE "); break; case ShareRowExclusiveLock: - appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + deparseAppendStringInfoString(state, "SHARE ROW EXCLUSIVE "); break; case ExclusiveLock: - appendStringInfoString(str, "EXCLUSIVE "); + deparseAppendStringInfoString(state, "EXCLUSIVE "); break; case AccessExclusiveLock: - appendStringInfoString(str, "ACCESS EXCLUSIVE "); + deparseAppendStringInfoString(state, "ACCESS EXCLUSIVE "); break; default: Assert(false); break; } - appendStringInfoString(str, "MODE "); + deparseAppendStringInfoString(state, "MODE "); } if (lock_stmt->nowait) - appendStringInfoString(str, "NOWAIT "); + deparseAppendStringInfoString(state, "NOWAIT "); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +static void deparseConstraintsSetStmt(DeparseState *state, ConstraintsSetStmt *constraints_set_stmt) { - appendStringInfoString(str, "SET CONSTRAINTS "); + deparseAppendStringInfoString(state, "SET CONSTRAINTS "); if (list_length(constraints_set_stmt->constraints) > 0) { - deparseQualifiedNameList(str, constraints_set_stmt->constraints); - appendStringInfoChar(str, ' '); + deparseQualifiedNameList(state, constraints_set_stmt->constraints); + deparseAppendStringInfoChar(state, ' '); } else { - appendStringInfoString(str, "ALL "); + deparseAppendStringInfoString(state, "ALL "); } if (constraints_set_stmt->deferred) - appendStringInfoString(str, "DEFERRED"); + deparseAppendStringInfoString(state, "DEFERRED"); else - appendStringInfoString(str, "IMMEDIATE"); + deparseAppendStringInfoString(state, "IMMEDIATE"); } -static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +static void deparseExplainStmt(DeparseState *state, ExplainStmt *explain_stmt) { ListCell *lc = NULL; char *defname = NULL; - appendStringInfoString(str, "EXPLAIN "); + deparseAppendPartGroup(state, "EXPLAIN", DEPARSE_PART_NO_INDENT); - deparseUtilityOptionList(str, explain_stmt->options); + deparseUtilityOptionList(state, explain_stmt->options); - deparseExplainableStmt(str, explain_stmt->query); + deparseExplainableStmt(state, explain_stmt->query); } -static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +static void deparseCopyStmt(DeparseState *state, CopyStmt *copy_stmt) { ListCell *lc = NULL; ListCell *lc2 = NULL; - appendStringInfoString(str, "COPY "); + deparseAppendPartGroup(state, "COPY", DEPARSE_PART_INDENT); if (copy_stmt->relation != NULL) { - deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); if (list_length(copy_stmt->attlist) > 0) { - appendStringInfoChar(str, '('); - deparseColumnList(str, copy_stmt->attlist); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, copy_stmt->attlist); + deparseAppendStringInfoChar(state, ')'); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } if (copy_stmt->query != NULL) { - appendStringInfoChar(str, '('); - deparsePreparableStmt(str, copy_stmt->query); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparsePreparableStmt(state, copy_stmt->query); + deparseAppendStringInfoString(state, ") "); } if (copy_stmt->is_from) - appendStringInfoString(str, "FROM "); + deparseAppendStringInfoString(state, "FROM "); else - appendStringInfoString(str, "TO "); + deparseAppendStringInfoString(state, "TO "); if (copy_stmt->is_program) - appendStringInfoString(str, "PROGRAM "); + deparseAppendStringInfoString(state, "PROGRAM "); if (copy_stmt->filename != NULL) { - deparseStringLiteral(str, copy_stmt->filename); - appendStringInfoChar(str, ' '); + deparseStringLiteral(state, copy_stmt->filename); + deparseAppendStringInfoChar(state, ' '); } else { if (copy_stmt->is_from) - appendStringInfoString(str, "STDIN "); + deparseAppendStringInfoString(state, "STDIN "); else - appendStringInfoString(str, "STDOUT "); + deparseAppendStringInfoString(state, "STDOUT "); } if (list_length(copy_stmt->options) > 0) @@ -7526,20 +8129,20 @@ static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) { - appendStringInfoString(str, "FREEZE "); + deparseAppendStringInfoString(state, "FREEZE "); } else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) { - appendStringInfoString(str, "HEADER "); + deparseAppendStringInfoString(state, "HEADER "); } else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) { - appendStringInfoString(str, "CSV "); + deparseAppendStringInfoString(state, "CSV "); } else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) { - appendStringInfoString(str, "FORCE QUOTE "); - deparseColumnList(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "FORCE QUOTE "); + deparseColumnList(state, castNode(List, def_elem->arg)); } else { @@ -7548,67 +8151,67 @@ static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) } } } else { - appendStringInfoString(str, "WITH ("); + deparseAppendStringInfoString(state, "WITH ("); foreach(lc, copy_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "format") == 0) { - appendStringInfoString(str, "FORMAT "); + deparseAppendStringInfoString(state, "FORMAT "); char *format = strVal(def_elem->arg); if (strcmp(format, "binary") == 0) - appendStringInfoString(str, "BINARY"); + deparseAppendStringInfoString(state, "BINARY"); else if (strcmp(format, "csv") == 0) - appendStringInfoString(str, "CSV"); + deparseAppendStringInfoString(state, "CSV"); else if (strcmp(format, "text") == 0) - appendStringInfoString(str, "TEXT"); + deparseAppendStringInfoString(state, "TEXT"); else Assert(false); } else if (strcmp(def_elem->defname, "freeze") == 0) { - appendStringInfoString(str, "FREEZE"); - deparseOptBoolean(str, def_elem->arg); + deparseAppendStringInfoString(state, "FREEZE"); + deparseOptBoolean(state, def_elem->arg); } else if (strcmp(def_elem->defname, "delimiter") == 0) { - appendStringInfoString(str, "DELIMITER "); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "DELIMITER "); + deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "null") == 0) { - appendStringInfoString(str, "NULL "); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "NULL "); + deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "header") == 0) { - appendStringInfoString(str, "HEADER"); - deparseOptBoolean(str, def_elem->arg); + deparseAppendStringInfoString(state, "HEADER"); + deparseOptBoolean(state, def_elem->arg); } else if (strcmp(def_elem->defname, "quote") == 0) { - appendStringInfoString(str, "QUOTE "); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "QUOTE "); + deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "escape") == 0) { - appendStringInfoString(str, "ESCAPE "); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "ESCAPE "); + deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "force_quote") == 0) { - appendStringInfoString(str, "FORCE_QUOTE "); + deparseAppendStringInfoString(state, "FORCE_QUOTE "); if (IsA(def_elem->arg, A_Star)) { - appendStringInfoChar(str, '*'); + deparseAppendStringInfoChar(state, '*'); } else if (IsA(def_elem->arg, List)) { - appendStringInfoChar(str, '('); - deparseColumnList(str, castNode(List, def_elem->arg)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); } else { @@ -7617,40 +8220,40 @@ static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) } else if (strcmp(def_elem->defname, "force_not_null") == 0) { - appendStringInfoString(str, "FORCE_NOT_NULL "); + deparseAppendStringInfoString(state, "FORCE_NOT_NULL "); if (IsA(def_elem->arg, A_Star)) - deparseAStar(str, castNode(A_Star, def_elem->arg)); + deparseAStar(state, castNode(A_Star, def_elem->arg)); else { - appendStringInfoChar(str, '('); - deparseColumnList(str, castNode(List, def_elem->arg)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); } } else if (strcmp(def_elem->defname, "force_null") == 0) { - appendStringInfoString(str, "FORCE_NULL "); + deparseAppendStringInfoString(state, "FORCE_NULL "); if (IsA(def_elem->arg, A_Star)) - deparseAStar(str, castNode(A_Star, def_elem->arg)); + deparseAStar(state, castNode(A_Star, def_elem->arg)); else { - appendStringInfoChar(str, '('); - deparseColumnList(str, castNode(List, def_elem->arg)); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); } } else if (strcmp(def_elem->defname, "encoding") == 0) { - appendStringInfoString(str, "ENCODING "); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "ENCODING "); + deparseStringLiteral(state, strVal(def_elem->arg)); } else { - appendStringInfoString(str, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); if (def_elem->arg != NULL) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (def_elem->arg == NULL) { @@ -7658,56 +8261,56 @@ static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) } else if (IsA(def_elem->arg, String)) { - deparseOptBooleanOrString(str, strVal(def_elem->arg)); + deparseOptBooleanOrString(state, strVal(def_elem->arg)); } else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) { - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (IsA(def_elem->arg, A_Star)) { - deparseAStar(str, castNode(A_Star, def_elem->arg)); + deparseAStar(state, castNode(A_Star, def_elem->arg)); } else if (IsA(def_elem->arg, List)) { List *l = castNode(List, def_elem->arg); - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach(lc2, l) { - deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + deparseOptBooleanOrString(state, strVal(lfirst(lc2))); if (lnext(l, lc2)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } } if (lnext(copy_stmt->options, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } } - deparseWhereClause(str, copy_stmt->whereClause); + deparseWhereClause(state, copy_stmt->whereClause); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +static void deparseDoStmt(DeparseState *state, DoStmt *do_stmt) { ListCell *lc; - appendStringInfoString(str, "DO "); + deparseAppendStringInfoString(state, "DO "); foreach (lc, do_stmt->args) { DefElem *defel = castNode(DefElem, lfirst(lc)); if (strcmp(defel->defname, "language") == 0) { - appendStringInfoString(str, "LANGUAGE "); - appendStringInfoString(str, quote_identifier(strVal(defel->arg))); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(defel->arg))); + deparseAppendStringInfoChar(state, ' '); } else if (strcmp(defel->defname, "as") == 0) { @@ -7715,70 +8318,70 @@ static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) const char *delim = "$$"; if (strstr(strval, "$$") != NULL) delim = "$outer$"; - appendStringInfoString(str, delim); - appendStringInfoString(str, strval); - appendStringInfoString(str, delim); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, delim); + deparseAppendStringInfoString(state, strval); + deparseAppendStringInfoString(state, delim); + deparseAppendStringInfoChar(state, ' '); } } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +static void deparseDiscardStmt(DeparseState *state, DiscardStmt *discard_stmt) { - appendStringInfoString(str, "DISCARD "); + deparseAppendStringInfoString(state, "DISCARD "); switch (discard_stmt->target) { case DISCARD_ALL: - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); break; case DISCARD_PLANS: - appendStringInfoString(str, "PLANS"); + deparseAppendStringInfoString(state, "PLANS"); break; case DISCARD_SEQUENCES: - appendStringInfoString(str, "SEQUENCES"); + deparseAppendStringInfoString(state, "SEQUENCES"); break; case DISCARD_TEMP: - appendStringInfoString(str, "TEMP"); + deparseAppendStringInfoString(state, "TEMP"); break; } } -static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +static void deparseDefineStmt(DeparseState *state, DefineStmt *define_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (define_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); switch (define_stmt->kind) { case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); + deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); + deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); break; case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); + deparseAppendStringInfoString(state, "COLLATION "); break; default: // This shouldn't happen @@ -7787,15 +8390,15 @@ static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) } if (define_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); switch (define_stmt->kind) { case OBJECT_AGGREGATE: - deparseFuncName(str, define_stmt->defnames); + deparseFuncName(state, define_stmt->defnames); break; case OBJECT_OPERATOR: - deparseAnyOperator(str, define_stmt->defnames); + deparseAnyOperator(state, define_stmt->defnames); break; case OBJECT_TYPE: case OBJECT_TSPARSER: @@ -7803,235 +8406,242 @@ static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) case OBJECT_TSTEMPLATE: case OBJECT_TSCONFIGURATION: case OBJECT_COLLATION: - deparseAnyName(str, define_stmt->defnames); + deparseAnyName(state, define_stmt->defnames); break; default: Assert(false); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) { - deparseAggrArgs(str, define_stmt->args); - appendStringInfoChar(str, ' '); + deparseAggrArgs(state, define_stmt->args); + deparseAppendStringInfoChar(state, ' '); } if (define_stmt->kind == OBJECT_COLLATION && list_length(define_stmt->definition) == 1 && strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) { - appendStringInfoString(str, "FROM "); - deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + deparseAppendStringInfoString(state, "FROM "); + deparseAnyName(state, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); } else if (list_length(define_stmt->definition) > 0) { - deparseDefinition(str, define_stmt->definition); + deparseDefinition(state, define_stmt->definition); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +static void deparseCompositeTypeStmt(DeparseState *state, CompositeTypeStmt *composite_type_stmt) { ListCell *lc; RangeVar *typevar; + DeparseStateNestingLevel *parent_level = NULL; - appendStringInfoString(str, "CREATE TYPE "); - deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + deparseAppendStringInfoString(state, "CREATE TYPE "); + deparseRangeVar(state, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); - appendStringInfoString(str, " AS ("); + deparseAppendStringInfoString(state, " AS ("); + parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, composite_type_stmt->coldeflist) { - deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); if (lnext(composite_type_stmt->coldeflist, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } - appendStringInfoChar(str, ')'); + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); } -static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +static void deparseCreateEnumStmt(DeparseState *state, CreateEnumStmt *create_enum_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE TYPE "); + DeparseStateNestingLevel *parent_level = NULL; - deparseAnyName(str, create_enum_stmt->typeName); - appendStringInfoString(str, " AS ENUM ("); + deparseAppendStringInfoString(state, "CREATE TYPE "); + + deparseAnyName(state, create_enum_stmt->typeName); + deparseAppendStringInfoString(state, " AS ENUM ("); + parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, create_enum_stmt->vals) { - deparseStringLiteral(str, strVal(lfirst(lc))); + deparseStringLiteral(state, strVal(lfirst(lc))); if (lnext(create_enum_stmt->vals, lc)) - appendStringInfoString(str, ", "); + deparseAppendCommaAndPart(state); } - appendStringInfoChar(str, ')'); + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); } -static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +static void deparseCreateRangeStmt(DeparseState *state, CreateRangeStmt *create_range_stmt) { - appendStringInfoString(str, "CREATE TYPE "); - deparseAnyName(str, create_range_stmt->typeName); - appendStringInfoString(str, " AS RANGE "); - deparseDefinition(str, create_range_stmt->params); + deparseAppendStringInfoString(state, "CREATE TYPE "); + deparseAnyName(state, create_range_stmt->typeName); + deparseAppendStringInfoString(state, " AS RANGE "); + deparseDefinition(state, create_range_stmt->params); } -static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +static void deparseAlterEnumStmt(DeparseState *state, AlterEnumStmt *alter_enum_stmt) { - appendStringInfoString(str, "ALTER TYPE "); - deparseAnyName(str, alter_enum_stmt->typeName); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER TYPE "); + deparseAnyName(state, alter_enum_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); if (alter_enum_stmt->oldVal == NULL) { - appendStringInfoString(str, "ADD VALUE "); + deparseAppendStringInfoString(state, "ADD VALUE "); if (alter_enum_stmt->skipIfNewValExists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - deparseStringLiteral(str, alter_enum_stmt->newVal); - appendStringInfoChar(str, ' '); + deparseStringLiteral(state, alter_enum_stmt->newVal); + deparseAppendStringInfoChar(state, ' '); if (alter_enum_stmt->newValNeighbor) { if (alter_enum_stmt->newValIsAfter) - appendStringInfoString(str, "AFTER "); + deparseAppendStringInfoString(state, "AFTER "); else - appendStringInfoString(str, "BEFORE "); - deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + deparseAppendStringInfoString(state, "BEFORE "); + deparseStringLiteral(state, alter_enum_stmt->newValNeighbor); } } else { - appendStringInfoString(str, "RENAME VALUE "); - deparseStringLiteral(str, alter_enum_stmt->oldVal); - appendStringInfoString(str, " TO "); - deparseStringLiteral(str, alter_enum_stmt->newVal); + deparseAppendStringInfoString(state, "RENAME VALUE "); + deparseStringLiteral(state, alter_enum_stmt->oldVal); + deparseAppendStringInfoString(state, " TO "); + deparseStringLiteral(state, alter_enum_stmt->newVal); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +static void deparseAlterExtensionStmt(DeparseState *state, AlterExtensionStmt *alter_extension_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "ALTER EXTENSION "); - deparseColId(str, alter_extension_stmt->extname); - appendStringInfoString(str, " UPDATE "); + deparseAppendStringInfoString(state, "ALTER EXTENSION "); + deparseColId(state, alter_extension_stmt->extname); + deparseAppendStringInfoString(state, " UPDATE "); foreach (lc, alter_extension_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "new_version") == 0) { - appendStringInfoString(str, "TO "); - deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "TO "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); } else { Assert(false); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +static void deparseAlterExtensionContentsStmt(DeparseState *state, AlterExtensionContentsStmt *alter_extension_contents_stmt) { List *l = NULL; - appendStringInfoString(str, "ALTER EXTENSION "); - deparseColId(str, alter_extension_contents_stmt->extname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER EXTENSION "); + deparseColId(state, alter_extension_contents_stmt->extname); + deparseAppendStringInfoChar(state, ' '); if (alter_extension_contents_stmt->action == 1) - appendStringInfoString(str, "ADD "); + deparseAppendStringInfoString(state, "ADD "); else if (alter_extension_contents_stmt->action == -1) - appendStringInfoString(str, "DROP "); + deparseAppendStringInfoString(state, "DROP "); else Assert(false); switch (alter_extension_contents_stmt->objtype) { case OBJECT_ACCESS_METHOD: - appendStringInfoString(str, "ACCESS METHOD "); + deparseAppendStringInfoString(state, "ACCESS METHOD "); break; case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); + deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_CAST: - appendStringInfoString(str, "CAST "); + deparseAppendStringInfoString(state, "CAST "); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); + deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); + deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); + deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); + deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); + deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); + deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); + deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); + deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); + deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); + deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_TRANSFORM: - appendStringInfoString(str, "TRANSFORM "); + deparseAppendStringInfoString(state, "TRANSFORM "); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); break; default: // No other object types are supported here in the parser @@ -8053,7 +8663,7 @@ static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionCont case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_FOREIGN_TABLE: - deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + deparseAnyName(state, castNode(List, alter_extension_contents_stmt->object)); break; // name case OBJECT_ACCESS_METHOD: @@ -8062,46 +8672,46 @@ static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionCont case OBJECT_EVENT_TRIGGER: case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: - deparseColId(str, strVal(alter_extension_contents_stmt->object)); + deparseColId(state, strVal(alter_extension_contents_stmt->object)); break; case OBJECT_AGGREGATE: - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); break; case OBJECT_CAST: l = castNode(List, alter_extension_contents_stmt->object); Assert(list_length(l) == 2); - appendStringInfoChar(str, '('); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " AS "); - deparseTypeName(str, castNode(TypeName, lsecond(l))); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); break; case OBJECT_DOMAIN: case OBJECT_TYPE: - deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + deparseTypeName(state, castNode(TypeName, alter_extension_contents_stmt->object)); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); break; case OBJECT_OPERATOR: - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); break; case OBJECT_OPFAMILY: case OBJECT_OPCLASS: l = castNode(List, alter_extension_contents_stmt->object); Assert(list_length(l) == 2); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); break; case OBJECT_TRANSFORM: l = castNode(List, alter_extension_contents_stmt->object); - appendStringInfoString(str, "FOR "); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " LANGUAGE "); - deparseColId(str, strVal(lsecond(l))); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseColId(state, strVal(lsecond(l))); break; default: Assert(false); @@ -8109,334 +8719,334 @@ static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionCont } } -static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +static void deparseAccessPriv(DeparseState *state, AccessPriv *access_priv) { ListCell *lc; if (access_priv->priv_name != NULL) { if (strcmp(access_priv->priv_name, "select") == 0) - appendStringInfoString(str, "select"); + deparseAppendStringInfoString(state, "select"); else if (strcmp(access_priv->priv_name, "references") == 0) - appendStringInfoString(str, "references"); + deparseAppendStringInfoString(state, "references"); else if (strcmp(access_priv->priv_name, "create") == 0) - appendStringInfoString(str, "create"); + deparseAppendStringInfoString(state, "create"); else - appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + deparseAppendStringInfoString(state, quote_identifier(access_priv->priv_name)); } else { - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (list_length(access_priv->cols) > 0) { - appendStringInfoChar(str, '('); - deparseColumnList(str, access_priv->cols); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, access_priv->cols); + deparseAppendStringInfoChar(state, ')'); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +static void deparseGrantStmt(DeparseState *state, GrantStmt *grant_stmt) { ListCell *lc; if (grant_stmt->is_grant) - appendStringInfoString(str, "GRANT "); + deparseAppendStringInfoString(state, "GRANT "); else - appendStringInfoString(str, "REVOKE "); + deparseAppendStringInfoString(state, "REVOKE "); if (!grant_stmt->is_grant && grant_stmt->grant_option) - appendStringInfoString(str, "GRANT OPTION FOR "); + deparseAppendStringInfoString(state, "GRANT OPTION FOR "); if (list_length(grant_stmt->privileges) > 0) { foreach(lc, grant_stmt->privileges) { - deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); if (lnext(grant_stmt->privileges, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } else { - appendStringInfoString(str, "ALL "); + deparseAppendStringInfoString(state, "ALL "); } - appendStringInfoString(str, "ON "); + deparseAppendStringInfoString(state, "ON "); - deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); - appendStringInfoChar(str, ' '); + deparsePrivilegeTarget(state, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + deparseAppendStringInfoChar(state, ' '); if (grant_stmt->is_grant) - appendStringInfoString(str, "TO "); + deparseAppendStringInfoString(state, "TO "); else - appendStringInfoString(str, "FROM "); + deparseAppendStringInfoString(state, "FROM "); foreach(lc, grant_stmt->grantees) { - deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + deparseRoleSpec(state, castNode(RoleSpec, lfirst(lc))); if (lnext(grant_stmt->grantees, lc)) - appendStringInfoChar(str, ','); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ','); + deparseAppendStringInfoChar(state, ' '); } if (grant_stmt->is_grant && grant_stmt->grant_option) - appendStringInfoString(str, "WITH GRANT OPTION "); + deparseAppendStringInfoString(state, "WITH GRANT OPTION "); - deparseOptDropBehavior(str, grant_stmt->behavior); + deparseOptDropBehavior(state, grant_stmt->behavior); if (grant_stmt->grantor) { - appendStringInfoString(str, "GRANTED BY "); - deparseRoleSpec(str, castNode(RoleSpec, grant_stmt->grantor)); + deparseAppendStringInfoString(state, "GRANTED BY "); + deparseRoleSpec(state, castNode(RoleSpec, grant_stmt->grantor)); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +static void deparseGrantRoleStmt(DeparseState *state, GrantRoleStmt *grant_role_stmt) { ListCell *lc; if (grant_role_stmt->is_grant) - appendStringInfoString(str, "GRANT "); + deparseAppendStringInfoString(state, "GRANT "); else - appendStringInfoString(str, "REVOKE "); + deparseAppendStringInfoString(state, "REVOKE "); if (!grant_role_stmt->is_grant && list_length(grant_role_stmt->opt)) { DefElem *defelem = castNode(DefElem, linitial(grant_role_stmt->opt)); Assert(!castNode(Boolean, defelem->arg)->boolval); if (strcmp("admin", defelem->defname) == 0) { - appendStringInfoString(str, "ADMIN "); + deparseAppendStringInfoString(state, "ADMIN "); } else if (strcmp("inherit", defelem->defname) == 0) { - appendStringInfoString(str, "INHERIT "); + deparseAppendStringInfoString(state, "INHERIT "); } else if (strcmp("set", defelem->defname) == 0) { - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); } - appendStringInfoString(str, "OPTION FOR "); + deparseAppendStringInfoString(state, "OPTION FOR "); } foreach(lc, grant_role_stmt->granted_roles) { - deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); if (lnext(grant_role_stmt->granted_roles, lc)) - appendStringInfoChar(str, ','); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ','); + deparseAppendStringInfoChar(state, ' '); } if (grant_role_stmt->is_grant) - appendStringInfoString(str, "TO "); + deparseAppendStringInfoString(state, "TO "); else - appendStringInfoString(str, "FROM "); + deparseAppendStringInfoString(state, "FROM "); - deparseRoleList(str, grant_role_stmt->grantee_roles); - appendStringInfoChar(str, ' '); + deparseRoleList(state, grant_role_stmt->grantee_roles); + deparseAppendStringInfoChar(state, ' '); if (grant_role_stmt->is_grant) { if (list_length(grant_role_stmt->opt) > 0) { - appendStringInfoString(str, "WITH "); + deparseAppendStringInfoString(state, "WITH "); } foreach(lc, grant_role_stmt->opt) { DefElem *defelem = castNode(DefElem, lfirst(lc)); if (strcmp("admin", defelem->defname) == 0) { - appendStringInfoString(str, "ADMIN "); - appendStringInfoString(str, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + deparseAppendStringInfoString(state, "ADMIN "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); } else if (strcmp("inherit", defelem->defname) == 0) { - appendStringInfoString(str, "INHERIT "); - appendStringInfoString(str, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + deparseAppendStringInfoString(state, "INHERIT "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); } else if (strcmp("set", defelem->defname) == 0) { - appendStringInfoString(str, "SET "); - appendStringInfoString(str, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + deparseAppendStringInfoString(state, "SET "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); } if (lnext(grant_role_stmt->opt, lc)) { - appendStringInfoChar(str, ','); + deparseAppendStringInfoChar(state, ','); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } if (grant_role_stmt->grantor) { - appendStringInfoString(str, "GRANTED BY "); - deparseRoleSpec(str, castNode(RoleSpec, grant_role_stmt->grantor)); + deparseAppendStringInfoString(state, "GRANTED BY "); + deparseRoleSpec(state, castNode(RoleSpec, grant_role_stmt->grantor)); } if (grant_role_stmt->behavior == DROP_CASCADE) { - appendStringInfoString(str, "CASCADE "); + deparseAppendStringInfoString(state, "CASCADE "); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +static void deparseDropRoleStmt(DeparseState *state, DropRoleStmt *drop_role_stmt) { ListCell *lc; - appendStringInfoString(str, "DROP ROLE "); + deparseAppendStringInfoString(state, "DROP ROLE "); if (drop_role_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - deparseRoleList(str, drop_role_stmt->roles); + deparseRoleList(state, drop_role_stmt->roles); } -static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +static void deparseIndexStmt(DeparseState *state, IndexStmt *index_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (index_stmt->unique) - appendStringInfoString(str, "UNIQUE "); + deparseAppendStringInfoString(state, "UNIQUE "); - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); if (index_stmt->concurrent) - appendStringInfoString(str, "CONCURRENTLY "); + deparseAppendStringInfoString(state, "CONCURRENTLY "); if (index_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); if (index_stmt->idxname != NULL) { - appendStringInfoString(str, quote_identifier(index_stmt->idxname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->idxname)); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "ON "); - deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendPartGroup(state, "ON", DEPARSE_PART_INDENT); + deparseRangeVar(state, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (index_stmt->accessMethod != NULL) { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->accessMethod)); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach (lc, index_stmt->indexParams) { - deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); if (lnext(index_stmt->indexParams, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); if (list_length(index_stmt->indexIncludingParams) > 0) { - appendStringInfoString(str, "INCLUDE ("); + deparseAppendStringInfoString(state, "INCLUDE ("); foreach (lc, index_stmt->indexIncludingParams) { - deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); if (lnext(index_stmt->indexIncludingParams, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); } if (index_stmt->nulls_not_distinct) { - appendStringInfoString(str, "NULLS NOT DISTINCT "); + deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); } - deparseOptWith(str, index_stmt->options); + deparseOptWith(state, index_stmt->options); if (index_stmt->tableSpace != NULL) { - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->tableSpace)); + deparseAppendStringInfoChar(state, ' '); } - deparseWhereClause(str, index_stmt->whereClause); + deparseWhereClause(state, index_stmt->whereClause); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +static void deparseAlterOpFamilyStmt(DeparseState *state, AlterOpFamilyStmt *alter_op_family_stmt) { - appendStringInfoString(str, "ALTER OPERATOR FAMILY "); - deparseAnyName(str, alter_op_family_stmt->opfamilyname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER OPERATOR FAMILY "); + deparseAnyName(state, alter_op_family_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(alter_op_family_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); if (alter_op_family_stmt->isDrop) - appendStringInfoString(str, "DROP "); + deparseAppendStringInfoString(state, "DROP "); else - appendStringInfoString(str, "ADD "); + deparseAppendStringInfoString(state, "ADD "); - deparseOpclassItemList(str, alter_op_family_stmt->items); + deparseOpclassItemList(state, alter_op_family_stmt->items); } -static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +static void deparsePrepareStmt(DeparseState *state, PrepareStmt *prepare_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "PREPARE "); - deparseColId(str, prepare_stmt->name); + deparseAppendStringInfoString(state, "PREPARE "); + deparseColId(state, prepare_stmt->name); if (list_length(prepare_stmt->argtypes) > 0) { - appendStringInfoChar(str, '('); - deparseTypeList(str, prepare_stmt->argtypes); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, prepare_stmt->argtypes); + deparseAppendStringInfoChar(state, ')'); } - appendStringInfoString(str, " AS "); - deparsePreparableStmt(str, prepare_stmt->query); + deparseAppendStringInfoString(state, " AS "); + deparsePreparableStmt(state, prepare_stmt->query); } -static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt) { ListCell *lc; - appendStringInfoString(str, "EXECUTE "); - appendStringInfoString(str, quote_identifier(execute_stmt->name)); + deparseAppendStringInfoString(state, "EXECUTE "); + deparseAppendStringInfoString(state, quote_identifier(execute_stmt->name)); if (list_length(execute_stmt->params) > 0) { - appendStringInfoChar(str, '('); - deparseExprList(str, execute_stmt->params); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, execute_stmt->params); + deparseAppendStringInfoChar(state, ')'); } } -static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +static void deparseDeallocateStmt(DeparseState *state, DeallocateStmt *deallocate_stmt) { - appendStringInfoString(str, "DEALLOCATE "); + deparseAppendStringInfoString(state, "DEALLOCATE "); if (deallocate_stmt->name != NULL) - appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + deparseAppendStringInfoString(state, quote_identifier(deallocate_stmt->name)); else - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); } // "AlterOptRoleElem" in gram.y -static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +static void deparseAlterRoleElem(DeparseState *state, DefElem *def_elem) { if (strcmp(def_elem->defname, "password") == 0) { - appendStringInfoString(str, "PASSWORD "); + deparseAppendStringInfoString(state, "PASSWORD "); if (def_elem->arg == NULL) { - appendStringInfoString(str, "NULL"); + deparseAppendStringInfoString(state, "NULL"); } else if (IsA(def_elem->arg, ParamRef)) { - deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + deparseParamRef(state, castNode(ParamRef, def_elem->arg)); } else if (IsA(def_elem->arg, String)) { - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseStringLiteral(state, strVal(def_elem->arg)); } else { @@ -8445,68 +9055,68 @@ static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) } else if (strcmp(def_elem->defname, "connectionlimit") == 0) { - appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + deparseAppendStringInfo(state, "CONNECTION LIMIT %d", intVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "validUntil") == 0) { - appendStringInfoString(str, "VALID UNTIL "); - deparseStringLiteral(str, strVal(def_elem->arg)); + deparseAppendStringInfoString(state, "VALID UNTIL "); + deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "SUPERUSER"); + deparseAppendStringInfoString(state, "SUPERUSER"); } else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOSUPERUSER"); + deparseAppendStringInfoString(state, "NOSUPERUSER"); } else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "CREATEROLE"); + deparseAppendStringInfoString(state, "CREATEROLE"); } else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOCREATEROLE"); + deparseAppendStringInfoString(state, "NOCREATEROLE"); } else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "REPLICATION"); + deparseAppendStringInfoString(state, "REPLICATION"); } else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOREPLICATION"); + deparseAppendStringInfoString(state, "NOREPLICATION"); } else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "CREATEDB"); + deparseAppendStringInfoString(state, "CREATEDB"); } else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOCREATEDB"); + deparseAppendStringInfoString(state, "NOCREATEDB"); } else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "LOGIN"); + deparseAppendStringInfoString(state, "LOGIN"); } else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOLOGIN"); + deparseAppendStringInfoString(state, "NOLOGIN"); } else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "BYPASSRLS"); + deparseAppendStringInfoString(state, "BYPASSRLS"); } else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOBYPASSRLS"); + deparseAppendStringInfoString(state, "NOBYPASSRLS"); } else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) { - appendStringInfoString(str, "INHERIT"); + deparseAppendStringInfoString(state, "INHERIT"); } else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) { - appendStringInfoString(str, "NOINHERIT"); + deparseAppendStringInfoString(state, "NOINHERIT"); } else { @@ -8515,181 +9125,181 @@ static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) } // "CreateOptRoleElem" in gram.y -static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +static void deparseCreateRoleElem(DeparseState *state, DefElem *def_elem) { if (strcmp(def_elem->defname, "sysid") == 0) { - appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + deparseAppendStringInfo(state, "SYSID %d", intVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "adminmembers") == 0) { - appendStringInfoString(str, "ADMIN "); - deparseRoleList(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "ADMIN "); + deparseRoleList(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "rolemembers") == 0) { - appendStringInfoString(str, "ROLE "); - deparseRoleList(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "ROLE "); + deparseRoleList(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "addroleto") == 0) { - appendStringInfoString(str, "IN ROLE "); - deparseRoleList(str, castNode(List, def_elem->arg)); + deparseAppendStringInfoString(state, "IN ROLE "); + deparseRoleList(state, castNode(List, def_elem->arg)); } else { - deparseAlterRoleElem(str, def_elem); + deparseAlterRoleElem(state, def_elem); } } -static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +static void deparseCreatePLangStmt(DeparseState *state, CreatePLangStmt *create_p_lang_stmt) { - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (create_p_lang_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); if (create_p_lang_stmt->pltrusted) - appendStringInfoString(str, "TRUSTED "); + deparseAppendStringInfoString(state, "TRUSTED "); - appendStringInfoString(str, "LANGUAGE "); - deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNonReservedWordOrSconst(state, create_p_lang_stmt->plname); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "HANDLER "); - deparseHandlerName(str, create_p_lang_stmt->plhandler); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, create_p_lang_stmt->plhandler); + deparseAppendStringInfoChar(state, ' '); if (create_p_lang_stmt->plinline) { - appendStringInfoString(str, "INLINE "); - deparseHandlerName(str, create_p_lang_stmt->plinline); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "INLINE "); + deparseHandlerName(state, create_p_lang_stmt->plinline); + deparseAppendStringInfoChar(state, ' '); } if (create_p_lang_stmt->plvalidator) { - appendStringInfoString(str, "VALIDATOR "); - deparseHandlerName(str, create_p_lang_stmt->plvalidator); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "VALIDATOR "); + deparseHandlerName(state, create_p_lang_stmt->plvalidator); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +static void deparseCreateRoleStmt(DeparseState *state, CreateRoleStmt *create_role_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); switch (create_role_stmt->stmt_type) { case ROLESTMT_ROLE: - appendStringInfoString(str, "ROLE "); + deparseAppendStringInfoString(state, "ROLE "); break; case ROLESTMT_USER: - appendStringInfoString(str, "USER "); + deparseAppendStringInfoString(state, "USER "); break; case ROLESTMT_GROUP: - appendStringInfoString(str, "GROUP "); + deparseAppendStringInfoString(state, "GROUP "); break; } - appendStringInfoString(str, quote_identifier(create_role_stmt->role)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(create_role_stmt->role)); + deparseAppendStringInfoChar(state, ' '); if (create_role_stmt->options != NULL) { - appendStringInfoString(str, "WITH "); + deparseAppendStringInfoString(state, "WITH "); foreach (lc, create_role_stmt->options) { - deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseCreateRoleElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +static void deparseAlterRoleStmt(DeparseState *state, AlterRoleStmt *alter_role_stmt) { ListCell *lc; - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) { - appendStringInfoString(str, "GROUP "); - deparseRoleSpec(str, alter_role_stmt->role); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "GROUP "); + deparseRoleSpec(state, alter_role_stmt->role); + deparseAppendStringInfoChar(state, ' '); if (alter_role_stmt->action == 1) { - appendStringInfoString(str, "ADD USER "); + deparseAppendStringInfoString(state, "ADD USER "); } else if (alter_role_stmt->action == -1) { - appendStringInfoString(str, "DROP USER "); + deparseAppendStringInfoString(state, "DROP USER "); } else { Assert(false); } - deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + deparseRoleList(state, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); } else { - appendStringInfoString(str, "ROLE "); - deparseRoleSpec(str, alter_role_stmt->role); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ROLE "); + deparseRoleSpec(state, alter_role_stmt->role); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "WITH "); + deparseAppendStringInfoString(state, "WITH "); foreach (lc, alter_role_stmt->options) { - deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseAlterRoleElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +static void deparseDeclareCursorStmt(DeparseState *state, DeclareCursorStmt *declare_cursor_stmt) { - appendStringInfoString(str, "DECLARE "); - appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "DECLARE "); + deparseAppendStringInfoString(state, quote_identifier(declare_cursor_stmt->portalname)); + deparseAppendStringInfoChar(state, ' '); if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) - appendStringInfoString(str, "BINARY "); + deparseAppendStringInfoString(state, "BINARY "); if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) - appendStringInfoString(str, "SCROLL "); + deparseAppendStringInfoString(state, "SCROLL "); if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) - appendStringInfoString(str, "NO SCROLL "); + deparseAppendStringInfoString(state, "NO SCROLL "); if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) - appendStringInfoString(str, "INSENSITIVE "); + deparseAppendStringInfoString(state, "INSENSITIVE "); - appendStringInfoString(str, "CURSOR "); + deparseAppendStringInfoString(state, "CURSOR "); if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) - appendStringInfoString(str, "WITH HOLD "); + deparseAppendStringInfoString(state, "WITH HOLD "); - appendStringInfoString(str, "FOR "); + deparseAppendStringInfoString(state, "FOR "); - deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); + deparseSelectStmt(state, castNode(SelectStmt, declare_cursor_stmt->query), DEPARSE_NODE_CONTEXT_NONE); } -static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +static void deparseFetchStmt(DeparseState *state, FetchStmt *fetch_stmt) { if (fetch_stmt->ismove) - appendStringInfoString(str, "MOVE "); + deparseAppendStringInfoString(state, "MOVE "); else - appendStringInfoString(str, "FETCH "); + deparseAppendStringInfoString(state, "FETCH "); switch (fetch_stmt->direction) { @@ -8700,68 +9310,68 @@ static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) } else if (fetch_stmt->howMany == FETCH_ALL) { - appendStringInfoString(str, "ALL "); + deparseAppendStringInfoString(state, "ALL "); } else { - appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + deparseAppendStringInfo(state, "FORWARD %ld ", fetch_stmt->howMany); } break; case FETCH_BACKWARD: if (fetch_stmt->howMany == 1) { - appendStringInfoString(str, "PRIOR "); + deparseAppendStringInfoString(state, "PRIOR "); } else if (fetch_stmt->howMany == FETCH_ALL) { - appendStringInfoString(str, "BACKWARD ALL "); + deparseAppendStringInfoString(state, "BACKWARD ALL "); } else { - appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + deparseAppendStringInfo(state, "BACKWARD %ld ", fetch_stmt->howMany); } break; case FETCH_ABSOLUTE: if (fetch_stmt->howMany == 1) { - appendStringInfoString(str, "FIRST "); + deparseAppendStringInfoString(state, "FIRST "); } else if (fetch_stmt->howMany == -1) { - appendStringInfoString(str, "LAST "); + deparseAppendStringInfoString(state, "LAST "); } else { - appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + deparseAppendStringInfo(state, "ABSOLUTE %ld ", fetch_stmt->howMany); } break; case FETCH_RELATIVE: - appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + deparseAppendStringInfo(state, "RELATIVE %ld ", fetch_stmt->howMany); } - appendStringInfoString(str, quote_identifier(fetch_stmt->portalname)); + deparseAppendStringInfoString(state, quote_identifier(fetch_stmt->portalname)); } -static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +static void deparseAlterDefaultPrivilegesStmt(DeparseState *state, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) { ListCell *lc; - appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + deparseAppendStringInfoString(state, "ALTER DEFAULT PRIVILEGES "); foreach (lc, alter_default_privileges_stmt->options) { DefElem *defelem = castNode(DefElem, lfirst(lc)); if (strcmp(defelem->defname, "schemas") == 0) { - appendStringInfoString(str, "IN SCHEMA "); - deparseNameList(str, castNode(List, defelem->arg)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "IN SCHEMA "); + deparseNameList(state, castNode(List, defelem->arg)); + deparseAppendStringInfoChar(state, ' '); } else if (strcmp(defelem->defname, "roles") == 0) { - appendStringInfoString(str, "FOR ROLE "); - deparseRoleList(str, castNode(List, defelem->arg)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR ROLE "); + deparseRoleList(state, castNode(List, defelem->arg)); + deparseAppendStringInfoChar(state, ' '); } else { @@ -8770,56 +9380,56 @@ static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivil } } - deparseGrantStmt(str, alter_default_privileges_stmt->action); + deparseGrantStmt(state, alter_default_privileges_stmt->action); } -static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +static void deparseReindexStmt(DeparseState *state, ReindexStmt *reindex_stmt) { - appendStringInfoString(str, "REINDEX "); + deparseAppendStringInfoString(state, "REINDEX "); - deparseUtilityOptionList(str, reindex_stmt->params); + deparseUtilityOptionList(state, reindex_stmt->params); switch (reindex_stmt->kind) { case REINDEX_OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); break; case REINDEX_OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case REINDEX_OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); + deparseAppendStringInfoString(state, "SCHEMA "); break; case REINDEX_OBJECT_SYSTEM: - appendStringInfoString(str, "SYSTEM "); + deparseAppendStringInfoString(state, "SYSTEM "); break; case REINDEX_OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); + deparseAppendStringInfoString(state, "DATABASE "); break; } if (reindex_stmt->relation != NULL) { - deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); } else if (reindex_stmt->name != NULL) { - appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + deparseAppendStringInfoString(state, quote_identifier(reindex_stmt->name)); } } -static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +static void deparseRuleStmt(DeparseState *state, RuleStmt* rule_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (rule_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); - appendStringInfoString(str, "RULE "); - appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); - appendStringInfoString(str, " AS ON "); + deparseAppendStringInfoString(state, "RULE "); + deparseAppendStringInfoString(state, quote_identifier(rule_stmt->rulename)); + deparseAppendStringInfoString(state, " AS ON "); switch (rule_stmt->event) { @@ -8830,118 +9440,118 @@ static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) Assert(false); break; case CMD_SELECT: - appendStringInfoString(str, "SELECT "); + deparseAppendStringInfoString(state, "SELECT "); break; case CMD_UPDATE: - appendStringInfoString(str, "UPDATE "); + deparseAppendStringInfoString(state, "UPDATE "); break; case CMD_INSERT: - appendStringInfoString(str, "INSERT "); + deparseAppendStringInfoString(state, "INSERT "); break; case CMD_DELETE: - appendStringInfoString(str, "DELETE "); + deparseAppendStringInfoString(state, "DELETE "); break; case CMD_MERGE: - appendStringInfoString(str, "MERGE "); + deparseAppendStringInfoString(state, "MERGE "); break; } - appendStringInfoString(str, "TO "); - deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TO "); + deparseRangeVar(state, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); - deparseWhereClause(str, rule_stmt->whereClause); + deparseWhereClause(state, rule_stmt->whereClause); - appendStringInfoString(str, "DO "); + deparseAppendStringInfoString(state, "DO "); if (rule_stmt->instead) - appendStringInfoString(str, "INSTEAD "); + deparseAppendStringInfoString(state, "INSTEAD "); if (list_length(rule_stmt->actions) == 0) { - appendStringInfoString(str, "NOTHING"); + deparseAppendStringInfoString(state, "NOTHING"); } else if (list_length(rule_stmt->actions) == 1) { - deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + deparseRuleActionStmt(state, linitial(rule_stmt->actions)); } else { - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); foreach (lc, rule_stmt->actions) { - deparseRuleActionStmt(str, lfirst(lc)); + deparseRuleActionStmt(state, lfirst(lc)); if (lnext(rule_stmt->actions, lc)) - appendStringInfoString(str, "; "); + deparseAppendStringInfoString(state, "; "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } } -static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +static void deparseNotifyStmt(DeparseState *state, NotifyStmt *notify_stmt) { - appendStringInfoString(str, "NOTIFY "); - appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + deparseAppendStringInfoString(state, "NOTIFY "); + deparseAppendStringInfoString(state, quote_identifier(notify_stmt->conditionname)); if (notify_stmt->payload != NULL) { - appendStringInfoString(str, ", "); - deparseStringLiteral(str, notify_stmt->payload); + deparseAppendStringInfoString(state, ", "); + deparseStringLiteral(state, notify_stmt->payload); } } -static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +static void deparseListenStmt(DeparseState *state, ListenStmt *listen_stmt) { - appendStringInfoString(str, "LISTEN "); - appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); + deparseAppendStringInfoString(state, "LISTEN "); + deparseAppendStringInfoString(state, quote_identifier(listen_stmt->conditionname)); } -static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +static void deparseUnlistenStmt(DeparseState *state, UnlistenStmt *unlisten_stmt) { - appendStringInfoString(str, "UNLISTEN "); + deparseAppendStringInfoString(state, "UNLISTEN "); if (unlisten_stmt->conditionname == NULL) - appendStringInfoString(str, "*"); + deparseAppendStringInfoString(state, "*"); else - appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); + deparseAppendStringInfoString(state, quote_identifier(unlisten_stmt->conditionname)); } -static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +static void deparseCreateSeqStmt(DeparseState *state, CreateSeqStmt *create_seq_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); - deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + deparseOptTemp(state, create_seq_stmt->sequence->relpersistence); - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); if (create_seq_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); - deparseOptSeqOptList(str, create_seq_stmt->options); + deparseOptSeqOptList(state, create_seq_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +static void deparseAlterFunctionStmt(DeparseState *state, AlterFunctionStmt *alter_function_stmt) { ListCell *lc; - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); switch (alter_function_stmt->objtype) { case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); + deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); + deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); + deparseAppendStringInfoString(state, "ROUTINE "); break; default: // Not supported here @@ -8949,325 +9559,325 @@ static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_fu break; } - deparseFunctionWithArgtypes(str, alter_function_stmt->func); - appendStringInfoChar(str, ' '); + deparseFunctionWithArgtypes(state, alter_function_stmt->func); + deparseAppendStringInfoChar(state, ' '); foreach (lc, alter_function_stmt->actions) { - deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + deparseCommonFuncOptItem(state, castNode(DefElem, lfirst(lc))); if (lnext(alter_function_stmt->actions, lc)) - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } } -static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +static void deparseTruncateStmt(DeparseState *state, TruncateStmt *truncate_stmt) { - appendStringInfoString(str, "TRUNCATE "); + deparseAppendStringInfoString(state, "TRUNCATE "); - deparseRelationExprList(str, truncate_stmt->relations); - appendStringInfoChar(str, ' '); + deparseRelationExprList(state, truncate_stmt->relations); + deparseAppendStringInfoChar(state, ' '); if (truncate_stmt->restart_seqs) - appendStringInfoString(str, "RESTART IDENTITY "); + deparseAppendStringInfoString(state, "RESTART IDENTITY "); - deparseOptDropBehavior(str, truncate_stmt->behavior); + deparseOptDropBehavior(state, truncate_stmt->behavior); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +static void deparseCreateEventTrigStmt(DeparseState *state, CreateEventTrigStmt *create_event_trig_stmt) { ListCell *lc = NULL; ListCell *lc2 = NULL; - appendStringInfoString(str, "CREATE EVENT TRIGGER "); - appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CREATE EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "ON "); - appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ON "); + deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->eventname)); + deparseAppendStringInfoChar(state, ' '); if (create_event_trig_stmt->whenclause) { - appendStringInfoString(str, "WHEN "); + deparseAppendStringInfoString(state, "WHEN "); foreach (lc, create_event_trig_stmt->whenclause) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); List *l = castNode(List, def_elem->arg); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoString(str, " IN ("); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, " IN ("); foreach (lc2, l) { - deparseStringLiteral(str, strVal(lfirst(lc2))); + deparseStringLiteral(state, strVal(lfirst(lc2))); if (lnext(l, lc2)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); if (lnext(create_event_trig_stmt->whenclause, lc)) - appendStringInfoString(str, " AND "); + deparseAppendStringInfoString(state, " AND "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "EXECUTE FUNCTION "); - deparseFuncName(str, create_event_trig_stmt->funcname); - appendStringInfoString(str, "()"); + deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); + deparseFuncName(state, create_event_trig_stmt->funcname); + deparseAppendStringInfoString(state, "()"); } -static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +static void deparseAlterEventTrigStmt(DeparseState *state, AlterEventTrigStmt *alter_event_trig_stmt) { - appendStringInfoString(str, "ALTER EVENT TRIGGER "); - appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(alter_event_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); switch (alter_event_trig_stmt->tgenabled) { case TRIGGER_FIRES_ON_ORIGIN: - appendStringInfoString(str, "ENABLE"); + deparseAppendStringInfoString(state, "ENABLE"); break; case TRIGGER_FIRES_ON_REPLICA: - appendStringInfoString(str, "ENABLE REPLICA"); + deparseAppendStringInfoString(state, "ENABLE REPLICA"); break; case TRIGGER_FIRES_ALWAYS: - appendStringInfoString(str, "ENABLE ALWAYS"); + deparseAppendStringInfoString(state, "ENABLE ALWAYS"); break; case TRIGGER_DISABLED: - appendStringInfoString(str, "DISABLE"); + deparseAppendStringInfoString(state, "DISABLE"); break; } } -static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +static void deparseRefreshMatViewStmt(DeparseState *state, RefreshMatViewStmt *refresh_mat_view_stmt) { - appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "REFRESH MATERIALIZED VIEW "); if (refresh_mat_view_stmt->concurrent) - appendStringInfoString(str, "CONCURRENTLY "); + deparseAppendStringInfoString(state, "CONCURRENTLY "); - deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (refresh_mat_view_stmt->skipData) - appendStringInfoString(str, "WITH NO DATA "); + deparseAppendStringInfoString(state, "WITH NO DATA "); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt) { switch (replica_identity_stmt->identity_type) { case REPLICA_IDENTITY_NOTHING: - appendStringInfoString(str, "NOTHING "); + deparseAppendStringInfoString(state, "NOTHING "); break; case REPLICA_IDENTITY_FULL: - appendStringInfoString(str, "FULL "); + deparseAppendStringInfoString(state, "FULL "); break; case REPLICA_IDENTITY_DEFAULT: - appendStringInfoString(str, "DEFAULT "); + deparseAppendStringInfoString(state, "DEFAULT "); break; case REPLICA_IDENTITY_INDEX: Assert(replica_identity_stmt->name != NULL); - appendStringInfoString(str, "USING INDEX "); - appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + deparseAppendStringInfoString(state, "USING INDEX "); + deparseAppendStringInfoString(state, quote_identifier(replica_identity_stmt->name)); break; } } // "CreatePolicyStmt" in gram.y -static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +static void deparseCreatePolicyStmt(DeparseState *state, CreatePolicyStmt *create_policy_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "CREATE POLICY "); - deparseColId(str, create_policy_stmt->policy_name); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CREATE POLICY "); + deparseColId(state, create_policy_stmt->policy_name); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (!create_policy_stmt->permissive) - appendStringInfoString(str, "AS RESTRICTIVE "); + deparseAppendStringInfoString(state, "AS RESTRICTIVE "); if (strcmp(create_policy_stmt->cmd_name, "all") == 0) Assert(true); // Default else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) - appendStringInfoString(str, "FOR SELECT "); + deparseAppendStringInfoString(state, "FOR SELECT "); else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) - appendStringInfoString(str, "FOR INSERT "); + deparseAppendStringInfoString(state, "FOR INSERT "); else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) - appendStringInfoString(str, "FOR UPDATE "); + deparseAppendStringInfoString(state, "FOR UPDATE "); else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) - appendStringInfoString(str, "FOR DELETE "); + deparseAppendStringInfoString(state, "FOR DELETE "); else Assert(false); - appendStringInfoString(str, "TO "); - deparseRoleList(str, create_policy_stmt->roles); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TO "); + deparseRoleList(state, create_policy_stmt->roles); + deparseAppendStringInfoChar(state, ' '); if (create_policy_stmt->qual != NULL) { - appendStringInfoString(str, "USING ("); - deparseExpr(str, create_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "USING ("); + deparseExpr(state, create_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } if (create_policy_stmt->with_check != NULL) { - appendStringInfoString(str, "WITH CHECK ("); - deparseExpr(str, create_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "WITH CHECK ("); + deparseExpr(state, create_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } } // "AlterPolicyStmt" in gram.y -static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +static void deparseAlterPolicyStmt(DeparseState *state, AlterPolicyStmt *alter_policy_stmt) { - appendStringInfoString(str, "ALTER POLICY "); - appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER POLICY "); + deparseAppendStringInfoString(state, quote_identifier(alter_policy_stmt->policy_name)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (list_length(alter_policy_stmt->roles) > 0) { - appendStringInfoString(str, "TO "); - deparseRoleList(str, alter_policy_stmt->roles); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TO "); + deparseRoleList(state, alter_policy_stmt->roles); + deparseAppendStringInfoChar(state, ' '); } if (alter_policy_stmt->qual != NULL) { - appendStringInfoString(str, "USING ("); - deparseExpr(str, alter_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "USING ("); + deparseExpr(state, alter_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } if (alter_policy_stmt->with_check != NULL) { - appendStringInfoString(str, "WITH CHECK ("); - deparseExpr(str, alter_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "WITH CHECK ("); + deparseExpr(state, alter_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } } -static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +static void deparseCreateTableSpaceStmt(DeparseState *state, CreateTableSpaceStmt *create_table_space_stmt) { - appendStringInfoString(str, "CREATE TABLESPACE "); - deparseColId(str, create_table_space_stmt->tablespacename); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CREATE TABLESPACE "); + deparseColId(state, create_table_space_stmt->tablespacename); + deparseAppendStringInfoChar(state, ' '); if (create_table_space_stmt->owner != NULL) { - appendStringInfoString(str, "OWNER "); - deparseRoleSpec(str, create_table_space_stmt->owner); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "OWNER "); + deparseRoleSpec(state, create_table_space_stmt->owner); + deparseAppendStringInfoChar(state, ' '); } - appendStringInfoString(str, "LOCATION "); + deparseAppendStringInfoString(state, "LOCATION "); if (create_table_space_stmt->location != NULL) - deparseStringLiteral(str, create_table_space_stmt->location); + deparseStringLiteral(state, create_table_space_stmt->location); else - appendStringInfoString(str, "''"); + deparseAppendStringInfoString(state, "''"); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); - deparseOptWith(str, create_table_space_stmt->options); + deparseOptWith(state, create_table_space_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +static void deparseCreateTransformStmt(DeparseState *state, CreateTransformStmt *create_transform_stmt) { - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (create_transform_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); - appendStringInfoString(str, "TRANSFORM FOR "); - deparseTypeName(str, create_transform_stmt->type_name); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "TRANSFORM FOR "); + deparseTypeName(state, create_transform_stmt->type_name); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "LANGUAGE "); - appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(create_transform_stmt->lang)); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoChar(str, '('); + deparseAppendStringInfoChar(state, '('); if (create_transform_stmt->fromsql) { - appendStringInfoString(str, "FROM SQL WITH FUNCTION "); - deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + deparseAppendStringInfoString(state, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_transform_stmt->fromsql); } if (create_transform_stmt->fromsql && create_transform_stmt->tosql) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); if (create_transform_stmt->tosql) { - appendStringInfoString(str, "TO SQL WITH FUNCTION "); - deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + deparseAppendStringInfoString(state, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_transform_stmt->tosql); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } -static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +static void deparseCreateAmStmt(DeparseState *state, CreateAmStmt *create_am_stmt) { - appendStringInfoString(str, "CREATE ACCESS METHOD "); - appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CREATE ACCESS METHOD "); + deparseAppendStringInfoString(state, quote_identifier(create_am_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); switch (create_am_stmt->amtype) { case AMTYPE_INDEX: - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); break; case AMTYPE_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; } - appendStringInfoString(str, "HANDLER "); - deparseHandlerName(str, create_am_stmt->handler_name); + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, create_am_stmt->handler_name); } // "pub_obj_list" in gram.y -static void deparsePublicationObjectList(StringInfo str, List *pubobjects) { +static void deparsePublicationObjectList(DeparseState *state, List *pubobjects) { const ListCell *lc; foreach(lc, pubobjects) { PublicationObjSpec *obj = lfirst(lc); switch (obj->pubobjtype) { case PUBLICATIONOBJ_TABLE: - appendStringInfoString(str, "TABLE "); - deparseRangeVar(str, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "TABLE "); + deparseRangeVar(state, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); if (obj->pubtable->columns) { - appendStringInfoChar(str, '('); - deparseColumnList(str, obj->pubtable->columns); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, obj->pubtable->columns); + deparseAppendStringInfoChar(state, ')'); } if (obj->pubtable->whereClause) { - appendStringInfoString(str, " WHERE ("); - deparseExpr(str, obj->pubtable->whereClause, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, " WHERE ("); + deparseExpr(state, obj->pubtable->whereClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ")"); } break; case PUBLICATIONOBJ_TABLES_IN_SCHEMA: - appendStringInfoString(str, "TABLES IN SCHEMA "); - appendStringInfoString(str, quote_identifier(obj->name)); + deparseAppendStringInfoString(state, "TABLES IN SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(obj->name)); break; case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: - appendStringInfoString(str, "TABLES IN SCHEMA CURRENT_SCHEMA"); + deparseAppendStringInfoString(state, "TABLES IN SCHEMA CURRENT_SCHEMA"); break; case PUBLICATIONOBJ_CONTINUATION: // This should be unreachable, the parser merges these before we can even get here. @@ -9276,61 +9886,61 @@ static void deparsePublicationObjectList(StringInfo str, List *pubobjects) { } if (lnext(pubobjects, lc)) { - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } } -static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +static void deparseCreatePublicationStmt(DeparseState *state, CreatePublicationStmt *create_publication_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "CREATE PUBLICATION "); - appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CREATE PUBLICATION "); + deparseAppendStringInfoString(state, quote_identifier(create_publication_stmt->pubname)); + deparseAppendStringInfoChar(state, ' '); if (list_length(create_publication_stmt->pubobjects) > 0) { - appendStringInfoString(str, "FOR "); - deparsePublicationObjectList(str, create_publication_stmt->pubobjects); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FOR "); + deparsePublicationObjectList(state, create_publication_stmt->pubobjects); + deparseAppendStringInfoChar(state, ' '); } else if (create_publication_stmt->for_all_tables) { - appendStringInfoString(str, "FOR ALL TABLES "); + deparseAppendStringInfoString(state, "FOR ALL TABLES "); } - deparseOptDefinition(str, create_publication_stmt->options); - removeTrailingSpace(str); + deparseOptDefinition(state, create_publication_stmt->options); + removeTrailingSpace(state); } -static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +static void deparseAlterPublicationStmt(DeparseState *state, AlterPublicationStmt *alter_publication_stmt) { - appendStringInfoString(str, "ALTER PUBLICATION "); - deparseColId(str, alter_publication_stmt->pubname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER PUBLICATION "); + deparseColId(state, alter_publication_stmt->pubname); + deparseAppendStringInfoChar(state, ' '); if (list_length(alter_publication_stmt->pubobjects) > 0) { switch (alter_publication_stmt->action) { case AP_SetObjects: - appendStringInfoString(str, "SET "); + deparseAppendStringInfoString(state, "SET "); break; case AP_AddObjects: - appendStringInfoString(str, "ADD "); + deparseAppendStringInfoString(state, "ADD "); break; case AP_DropObjects: - appendStringInfoString(str, "DROP "); + deparseAppendStringInfoString(state, "DROP "); break; } - deparsePublicationObjectList(str, alter_publication_stmt->pubobjects); + deparsePublicationObjectList(state, alter_publication_stmt->pubobjects); } else if (list_length(alter_publication_stmt->options) > 0) { - appendStringInfoString(str, "SET "); - deparseDefinition(str, alter_publication_stmt->options); + deparseAppendStringInfoString(state, "SET "); + deparseDefinition(state, alter_publication_stmt->options); } else { @@ -9338,166 +9948,166 @@ static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *al } } -static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +static void deparseAlterSeqStmt(DeparseState *state, AlterSeqStmt *alter_seq_stmt) { ListCell *lc; - appendStringInfoString(str, "ALTER SEQUENCE "); + deparseAppendStringInfoString(state, "ALTER SEQUENCE "); if (alter_seq_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); - deparseSeqOptList(str, alter_seq_stmt->options); + deparseSeqOptList(state, alter_seq_stmt->options); - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +static void deparseAlterSystemStmt(DeparseState *state, AlterSystemStmt *alter_system_stmt) { - appendStringInfoString(str, "ALTER SYSTEM "); - deparseVariableSetStmt(str, alter_system_stmt->setstmt); + deparseAppendStringInfoString(state, "ALTER SYSTEM "); + deparseVariableSetStmt(state, alter_system_stmt->setstmt); } -static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +static void deparseCommentStmt(DeparseState *state, CommentStmt *comment_stmt) { ListCell *lc; List *l; - appendStringInfoString(str, "COMMENT ON "); + deparseAppendStringInfoString(state, "COMMENT ON "); switch (comment_stmt->objtype) { case OBJECT_COLUMN: - appendStringInfoString(str, "COLUMN "); + deparseAppendStringInfoString(state, "COLUMN "); break; case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); + deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); + deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); + deparseAppendStringInfoString(state, "STATISTICS "); break; case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); + deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); + deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); + deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); + deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_ACCESS_METHOD: - appendStringInfoString(str, "ACCESS METHOD "); + deparseAppendStringInfoString(state, "ACCESS METHOD "); break; case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); + deparseAppendStringInfoString(state, "DATABASE "); break; case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_EXTENSION: - appendStringInfoString(str, "EXTENSION "); + deparseAppendStringInfoString(state, "EXTENSION "); break; case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); + deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); + deparseAppendStringInfoString(state, "PUBLICATION "); break; case OBJECT_ROLE: - appendStringInfoString(str, "ROLE "); + deparseAppendStringInfoString(state, "ROLE "); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); + deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); + deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); + deparseAppendStringInfoString(state, "SUBSCRIPTION "); break; case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); + deparseAppendStringInfoString(state, "TABLESPACE "); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); + deparseAppendStringInfoString(state, "TYPE "); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); + deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); + deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); + deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); + deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_TABCONSTRAINT: - appendStringInfoString(str, "CONSTRAINT "); + deparseAppendStringInfoString(state, "CONSTRAINT "); break; case OBJECT_DOMCONSTRAINT: - appendStringInfoString(str, "CONSTRAINT "); + deparseAppendStringInfoString(state, "CONSTRAINT "); break; case OBJECT_POLICY: - appendStringInfoString(str, "POLICY "); + deparseAppendStringInfoString(state, "POLICY "); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); + deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); + deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_RULE: - appendStringInfoString(str, "RULE "); + deparseAppendStringInfoString(state, "RULE "); break; case OBJECT_TRANSFORM: - appendStringInfoString(str, "TRANSFORM "); + deparseAppendStringInfoString(state, "TRANSFORM "); break; case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); + deparseAppendStringInfoString(state, "TRIGGER "); break; case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); + deparseAppendStringInfoString(state, "LARGE OBJECT "); break; case OBJECT_CAST: - appendStringInfoString(str, "CAST "); + deparseAppendStringInfoString(state, "CAST "); break; default: // No other cases are supported in the parser @@ -9521,7 +10131,7 @@ static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) case OBJECT_TSDICTIONARY: case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: - deparseAnyName(str, castNode(List, comment_stmt->object)); + deparseAnyName(state, castNode(List, comment_stmt->object)); break; case OBJECT_ACCESS_METHOD: case OBJECT_DATABASE: @@ -9535,62 +10145,62 @@ static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) case OBJECT_FOREIGN_SERVER: case OBJECT_SUBSCRIPTION: case OBJECT_TABLESPACE: - appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + deparseAppendStringInfoString(state, quote_identifier(strVal(comment_stmt->object))); break; case OBJECT_TYPE: case OBJECT_DOMAIN: - deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + deparseTypeName(state, castNode(TypeName, comment_stmt->object)); break; case OBJECT_AGGREGATE: - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); break; case OBJECT_OPERATOR: - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); break; case OBJECT_TABCONSTRAINT: case OBJECT_POLICY: case OBJECT_RULE: case OBJECT_TRIGGER: l = castNode(List, comment_stmt->object); - appendStringInfoString(str, quote_identifier(strVal(llast(l)))); - appendStringInfoString(str, " ON "); - deparseAnyNameSkipLast(str, l); + deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); + deparseAppendStringInfoString(state, " ON "); + deparseAnyNameSkipLast(state, l); break; case OBJECT_DOMCONSTRAINT: l = castNode(List, comment_stmt->object); - appendStringInfoString(str, quote_identifier(strVal(llast(l)))); - appendStringInfoString(str, " ON DOMAIN "); - deparseTypeName(str, linitial(l)); + deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); + deparseAppendStringInfoString(state, " ON DOMAIN "); + deparseTypeName(state, linitial(l)); break; case OBJECT_TRANSFORM: l = castNode(List, comment_stmt->object); - appendStringInfoString(str, "FOR "); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " LANGUAGE "); - appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(lsecond(l)))); break; case OBJECT_OPCLASS: case OBJECT_OPFAMILY: l = castNode(List, comment_stmt->object); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); break; case OBJECT_LARGEOBJECT: - deparseValue(str, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + deparseValue(state, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_CAST: l = castNode(List, comment_stmt->object); - appendStringInfoChar(str, '('); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " AS "); - deparseTypeName(str, castNode(TypeName, lsecond(l))); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); break; default: // No other cases are supported in the parser @@ -9598,279 +10208,279 @@ static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) break; } - appendStringInfoString(str, " IS "); + deparseAppendStringInfoString(state, " IS "); if (comment_stmt->comment != NULL) - deparseStringLiteral(str, comment_stmt->comment); + deparseStringLiteral(state, comment_stmt->comment); else - appendStringInfoString(str, "NULL"); + deparseAppendStringInfoString(state, "NULL"); } // "stats_param" in gram.y -static void deparseStatsElem(StringInfo str, StatsElem *stats_elem) +static void deparseStatsElem(DeparseState *state, StatsElem *stats_elem) { // only one of stats_elem->name or stats_elem->expr can be non-null if (stats_elem->name) - appendStringInfoString(str, stats_elem->name); + deparseAppendStringInfoString(state, stats_elem->name); else if (stats_elem->expr) { - appendStringInfoChar(str, '('); - deparseExpr(str, stats_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, stats_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); } } -static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +static void deparseCreateStatsStmt(DeparseState *state, CreateStatsStmt *create_stats_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE STATISTICS "); + deparseAppendStringInfoString(state, "CREATE STATISTICS "); if (create_stats_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, "IF NOT EXISTS "); - deparseAnyName(str, create_stats_stmt->defnames); - appendStringInfoChar(str, ' '); + deparseAnyName(state, create_stats_stmt->defnames); + deparseAppendStringInfoChar(state, ' '); if (list_length(create_stats_stmt->stat_types) > 0) { - appendStringInfoChar(str, '('); - deparseNameList(str, create_stats_stmt->stat_types); - appendStringInfoString(str, ") "); + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, create_stats_stmt->stat_types); + deparseAppendStringInfoString(state, ") "); } - appendStringInfoString(str, "ON "); + deparseAppendStringInfoString(state, "ON "); foreach (lc, create_stats_stmt->exprs) { - deparseStatsElem(str, lfirst(lc)); + deparseStatsElem(state, lfirst(lc)); if (lnext(create_stats_stmt->exprs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, " FROM "); - deparseFromList(str, create_stats_stmt->relations); + deparseAppendStringInfoString(state, " FROM "); + deparseFromList(state, create_stats_stmt->relations); } -static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +static void deparseAlterCollationStmt(DeparseState *state, AlterCollationStmt *alter_collation_stmt) { - appendStringInfoString(str, "ALTER COLLATION "); - deparseAnyName(str, alter_collation_stmt->collname); - appendStringInfoString(str, " REFRESH VERSION"); + deparseAppendStringInfoString(state, "ALTER COLLATION "); + deparseAnyName(state, alter_collation_stmt->collname); + deparseAppendStringInfoString(state, " REFRESH VERSION"); } -static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +static void deparseAlterDatabaseStmt(DeparseState *state, AlterDatabaseStmt *alter_database_stmt) { - appendStringInfoString(str, "ALTER DATABASE "); - deparseColId(str, alter_database_stmt->dbname); - appendStringInfoChar(str, ' '); - deparseCreatedbOptList(str, alter_database_stmt->options); - removeTrailingSpace(str); + deparseAppendStringInfoString(state, "ALTER DATABASE "); + deparseColId(state, alter_database_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseCreatedbOptList(state, alter_database_stmt->options); + removeTrailingSpace(state); } -static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +static void deparseAlterDatabaseSetStmt(DeparseState *state, AlterDatabaseSetStmt *alter_database_set_stmt) { - appendStringInfoString(str, "ALTER DATABASE "); - deparseColId(str, alter_database_set_stmt->dbname); - appendStringInfoChar(str, ' '); - deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); + deparseAppendStringInfoString(state, "ALTER DATABASE "); + deparseColId(state, alter_database_set_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseVariableSetStmt(state, alter_database_set_stmt->setstmt); } -static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) +static void deparseAlterStatsStmt(DeparseState *state, AlterStatsStmt *alter_stats_stmt) { - appendStringInfoString(str, "ALTER STATISTICS "); + deparseAppendStringInfoString(state, "ALTER STATISTICS "); if (alter_stats_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - deparseAnyName(str, alter_stats_stmt->defnames); - appendStringInfoChar(str, ' '); + deparseAnyName(state, alter_stats_stmt->defnames); + deparseAppendStringInfoChar(state, ' '); if (alter_stats_stmt->stxstattarget) - appendStringInfo(str, "SET STATISTICS %d", castNode(Integer, alter_stats_stmt->stxstattarget)->ival); + deparseAppendStringInfo(state, "SET STATISTICS %d", castNode(Integer, alter_stats_stmt->stxstattarget)->ival); else - appendStringInfo(str, "SET STATISTICS DEFAULT"); + deparseAppendStringInfo(state, "SET STATISTICS DEFAULT"); } -static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +static void deparseAlterTSDictionaryStmt(DeparseState *state, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) { - appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + deparseAppendStringInfoString(state, "ALTER TEXT SEARCH DICTIONARY "); - deparseAnyName(str, alter_ts_dictionary_stmt->dictname); - appendStringInfoChar(str, ' '); + deparseAnyName(state, alter_ts_dictionary_stmt->dictname); + deparseAppendStringInfoChar(state, ' '); - deparseDefinition(str, alter_ts_dictionary_stmt->options); + deparseDefinition(state, alter_ts_dictionary_stmt->options); } -static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +static void deparseAlterTSConfigurationStmt(DeparseState *state, AlterTSConfigurationStmt *alter_ts_configuration_stmt) { ListCell *lc = NULL; - appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); - deparseAnyName(str, alter_ts_configuration_stmt->cfgname); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, alter_ts_configuration_stmt->cfgname); + deparseAppendStringInfoChar(state, ' '); switch (alter_ts_configuration_stmt->kind) { case ALTER_TSCONFIG_ADD_MAPPING: - appendStringInfoString(str, "ADD MAPPING FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - appendStringInfoString(str, " WITH "); - deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + deparseAppendStringInfoString(state, "ADD MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); break; case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: - appendStringInfoString(str, "ALTER MAPPING FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - appendStringInfoString(str, " WITH "); - deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); break; case ALTER_TSCONFIG_REPLACE_DICT: - appendStringInfoString(str, "ALTER MAPPING REPLACE "); - deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); - appendStringInfoString(str, " WITH "); - deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, "ALTER MAPPING REPLACE "); + deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); break; case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: - appendStringInfoString(str, "ALTER MAPPING FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - appendStringInfoString(str, " REPLACE "); - deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); - appendStringInfoString(str, " WITH "); - deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " REPLACE "); + deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); break; case ALTER_TSCONFIG_DROP_MAPPING: - appendStringInfoString(str, "DROP MAPPING "); + deparseAppendStringInfoString(state, "DROP MAPPING "); if (alter_ts_configuration_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - appendStringInfoString(str, "FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseAppendStringInfoString(state, "FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); break; } } -static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +static void deparseVariableShowStmt(DeparseState *state, VariableShowStmt *variable_show_stmt) { - appendStringInfoString(str, "SHOW "); + deparseAppendStringInfoString(state, "SHOW "); if (strcmp(variable_show_stmt->name, "timezone") == 0) - appendStringInfoString(str, "TIME ZONE"); + deparseAppendStringInfoString(state, "TIME ZONE"); else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) - appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + deparseAppendStringInfoString(state, "TRANSACTION ISOLATION LEVEL"); else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) - appendStringInfoString(str, "SESSION AUTHORIZATION"); + deparseAppendStringInfoString(state, "SESSION AUTHORIZATION"); else if (strcmp(variable_show_stmt->name, "all") == 0) - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); else - appendStringInfoString(str, quote_identifier(variable_show_stmt->name)); + deparseAppendStringInfoString(state, quote_identifier(variable_show_stmt->name)); } // "tablesample_clause" in gram.y -static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample) { - deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + deparseRangeVar(state, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " TABLESAMPLE "); + deparseAppendStringInfoString(state, " TABLESAMPLE "); - deparseFuncName(str, range_table_sample->method); - appendStringInfoChar(str, '('); - deparseExprList(str, range_table_sample->args); - appendStringInfoString(str, ") "); + deparseFuncName(state, range_table_sample->method); + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, range_table_sample->args); + deparseAppendStringInfoString(state, ") "); if (range_table_sample->repeatable != NULL) { - appendStringInfoString(str, "REPEATABLE ("); - deparseExpr(str, range_table_sample->repeatable, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "REPEATABLE ("); + deparseExpr(state, range_table_sample->repeatable, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +static void deparseCreateSubscriptionStmt(DeparseState *state, CreateSubscriptionStmt *create_subscription_stmt) { ListCell *lc; - appendStringInfoString(str, "CREATE SUBSCRIPTION "); - appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + deparseAppendStringInfoString(state, "CREATE SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(create_subscription_stmt->subname)); - appendStringInfoString(str, " CONNECTION "); + deparseAppendStringInfoString(state, " CONNECTION "); if (create_subscription_stmt->conninfo != NULL) - deparseStringLiteral(str, create_subscription_stmt->conninfo); + deparseStringLiteral(state, create_subscription_stmt->conninfo); else - appendStringInfoString(str, "''"); + deparseAppendStringInfoString(state, "''"); - appendStringInfoString(str, " PUBLICATION "); + deparseAppendStringInfoString(state, " PUBLICATION "); foreach(lc, create_subscription_stmt->publication) { - deparseColLabel(str, strVal(lfirst(lc))); + deparseColLabel(state, strVal(lfirst(lc))); if (lnext(create_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); - deparseOptDefinition(str, create_subscription_stmt->options); - removeTrailingSpace(str); + deparseOptDefinition(state, create_subscription_stmt->options); + removeTrailingSpace(state); } -static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +static void deparseAlterSubscriptionStmt(DeparseState *state, AlterSubscriptionStmt *alter_subscription_stmt) { ListCell *lc; - appendStringInfoString(str, "ALTER SUBSCRIPTION "); - appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ALTER SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(alter_subscription_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); switch (alter_subscription_stmt->kind) { case ALTER_SUBSCRIPTION_OPTIONS: - appendStringInfoString(str, "SET "); - deparseDefinition(str, alter_subscription_stmt->options); + deparseAppendStringInfoString(state, "SET "); + deparseDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_SKIP: - appendStringInfoString(str, "SKIP "); - deparseDefinition(str, alter_subscription_stmt->options); + deparseAppendStringInfoString(state, "SKIP "); + deparseDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_CONNECTION: - appendStringInfoString(str, "CONNECTION "); - deparseStringLiteral(str, alter_subscription_stmt->conninfo); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "CONNECTION "); + deparseStringLiteral(state, alter_subscription_stmt->conninfo); + deparseAppendStringInfoChar(state, ' '); break; case ALTER_SUBSCRIPTION_REFRESH: - appendStringInfoString(str, "REFRESH PUBLICATION "); - deparseOptDefinition(str, alter_subscription_stmt->options); + deparseAppendStringInfoString(state, "REFRESH PUBLICATION "); + deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_ADD_PUBLICATION: - appendStringInfoString(str, "ADD PUBLICATION "); + deparseAppendStringInfoString(state, "ADD PUBLICATION "); foreach(lc, alter_subscription_stmt->publication) { - deparseColLabel(str, strVal(lfirst(lc))); + deparseColLabel(state, strVal(lfirst(lc))); if (lnext(alter_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); - deparseOptDefinition(str, alter_subscription_stmt->options); + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_DROP_PUBLICATION: - appendStringInfoString(str, "DROP PUBLICATION "); + deparseAppendStringInfoString(state, "DROP PUBLICATION "); foreach(lc, alter_subscription_stmt->publication) { - deparseColLabel(str, strVal(lfirst(lc))); + deparseColLabel(state, strVal(lfirst(lc))); if (lnext(alter_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); - deparseOptDefinition(str, alter_subscription_stmt->options); + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_SET_PUBLICATION: - appendStringInfoString(str, "SET PUBLICATION "); + deparseAppendStringInfoString(state, "SET PUBLICATION "); foreach(lc, alter_subscription_stmt->publication) { - deparseColLabel(str, strVal(lfirst(lc))); + deparseColLabel(state, strVal(lfirst(lc))); if (lnext(alter_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); - deparseOptDefinition(str, alter_subscription_stmt->options); + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_ENABLED: Assert(list_length(alter_subscription_stmt->options) == 1); @@ -9878,249 +10488,249 @@ static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt * Assert(strcmp(defelem->defname, "enabled") == 0); if (optBooleanValue(defelem->arg)) { - appendStringInfoString(str, " ENABLE "); + deparseAppendStringInfoString(state, " ENABLE "); } else { - appendStringInfoString(str, " DISABLE "); + deparseAppendStringInfoString(state, " DISABLE "); } break; } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +static void deparseDropSubscriptionStmt(DeparseState *state, DropSubscriptionStmt *drop_subscription_stmt) { - appendStringInfoString(str, "DROP SUBSCRIPTION "); + deparseAppendStringInfoString(state, "DROP SUBSCRIPTION "); if (drop_subscription_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); + deparseAppendStringInfoString(state, "IF EXISTS "); - appendStringInfoString(str, drop_subscription_stmt->subname); + deparseAppendStringInfoString(state, drop_subscription_stmt->subname); } -static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +static void deparseCallStmt(DeparseState *state, CallStmt *call_stmt) { - appendStringInfoString(str, "CALL "); - deparseFuncCall(str, call_stmt->funccall, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, "CALL "); + deparseFuncCall(state, call_stmt->funccall, DEPARSE_NODE_CONTEXT_NONE); } -static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +static void deparseAlterOwnerStmt(DeparseState *state, AlterOwnerStmt *alter_owner_stmt) { List *l = NULL; - appendStringInfoString(str, "ALTER "); + deparseAppendStringInfoString(state, "ALTER "); switch (alter_owner_stmt->objectType) { case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "COLLATION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "DATABASE "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - deparseNumericOnly(str, (union ValUnion *) alter_owner_stmt->object); + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseNumericOnly(state, (union ValUnion *) alter_owner_stmt->object); break; case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "OPERATOR "); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_OPCLASS: l = castNode(List, alter_owner_stmt->object); - appendStringInfoString(str, "OPERATOR CLASS "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); break; case OBJECT_OPFAMILY: l = castNode(List, alter_owner_stmt->object); - appendStringInfoString(str, "OPERATOR FAMILY "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); break; case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "SCHEMA "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "STATISTICS "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "SERVER "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "PUBLICATION "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); - deparseColId(str, strVal(alter_owner_stmt->object)); + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + deparseColId(state, strVal(alter_owner_stmt->object)); break; default: Assert(false); } - appendStringInfoString(str, " OWNER TO "); - deparseRoleSpec(str, alter_owner_stmt->newowner); + deparseAppendStringInfoString(state, " OWNER TO "); + deparseRoleSpec(state, alter_owner_stmt->newowner); } // "operator_def_list" in gram.y -static void deparseOperatorDefList(StringInfo str, List *defs) +static void deparseOperatorDefList(DeparseState *state, List *defs) { ListCell *lc = NULL; foreach (lc, defs) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoString(str, " = "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, " = "); if (def_elem->arg != NULL) - deparseDefArg(str, def_elem->arg, true); + deparseDefArg(state, def_elem->arg, true); else - appendStringInfoString(str, "NONE"); + deparseAppendStringInfoString(state, "NONE"); if (lnext(defs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } } -static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +static void deparseAlterOperatorStmt(DeparseState *state, AlterOperatorStmt *alter_operator_stmt) { - appendStringInfoString(str, "ALTER OPERATOR "); - deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); - appendStringInfoString(str, " SET ("); - deparseOperatorDefList(str, alter_operator_stmt->options); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(state, alter_operator_stmt->opername); + deparseAppendStringInfoString(state, " SET ("); + deparseOperatorDefList(state, alter_operator_stmt->options); + deparseAppendStringInfoChar(state, ')'); } -static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) +static void deparseAlterTypeStmt(DeparseState *state, AlterTypeStmt *alter_type_stmt) { - appendStringInfoString(str, "ALTER TYPE "); - deparseAnyName(str, alter_type_stmt->typeName); - appendStringInfoString(str, " SET ("); - deparseOperatorDefList(str, alter_type_stmt->options); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "ALTER TYPE "); + deparseAnyName(state, alter_type_stmt->typeName); + deparseAppendStringInfoString(state, " SET ("); + deparseOperatorDefList(state, alter_type_stmt->options); + deparseAppendStringInfoChar(state, ')'); } -static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +static void deparseDropOwnedStmt(DeparseState *state, DropOwnedStmt *drop_owned_stmt) { - appendStringInfoString(str, "DROP OWNED BY "); - deparseRoleList(str, drop_owned_stmt->roles); - appendStringInfoChar(str, ' '); - deparseOptDropBehavior(str, drop_owned_stmt->behavior); - removeTrailingSpace(str); + deparseAppendStringInfoString(state, "DROP OWNED BY "); + deparseRoleList(state, drop_owned_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + deparseOptDropBehavior(state, drop_owned_stmt->behavior); + removeTrailingSpace(state); } -static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +static void deparseReassignOwnedStmt(DeparseState *state, ReassignOwnedStmt *reassigned_owned_stmt) { - appendStringInfoString(str, "REASSIGN OWNED BY "); + deparseAppendStringInfoString(state, "REASSIGN OWNED BY "); - deparseRoleList(str, reassigned_owned_stmt->roles); - appendStringInfoChar(str, ' '); + deparseRoleList(state, reassigned_owned_stmt->roles); + deparseAppendStringInfoChar(state, ' '); - appendStringInfoString(str, "TO "); - deparseRoleSpec(str, reassigned_owned_stmt->newrole); + deparseAppendStringInfoString(state, "TO "); + deparseRoleSpec(state, reassigned_owned_stmt->newrole); } -static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +static void deparseClosePortalStmt(DeparseState *state, ClosePortalStmt *close_portal_stmt) { - appendStringInfoString(str, "CLOSE "); + deparseAppendStringInfoString(state, "CLOSE "); if (close_portal_stmt->portalname != NULL) { - appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + deparseAppendStringInfoString(state, quote_identifier(close_portal_stmt->portalname)); } else { - appendStringInfoString(str, "ALL"); + deparseAppendStringInfoString(state, "ALL"); } } // "CreateTrigStmt" in gram.y -static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +static void deparseCreateTrigStmt(DeparseState *state, CreateTrigStmt *create_trig_stmt) { ListCell *lc; bool skip_events_or = true; - appendStringInfoString(str, "CREATE "); + deparseAppendStringInfoString(state, "CREATE "); if (create_trig_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); + deparseAppendStringInfoString(state, "OR REPLACE "); if (create_trig_stmt->isconstraint) - appendStringInfoString(str, "CONSTRAINT "); - appendStringInfoString(str, "TRIGGER "); + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, "TRIGGER "); - appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(create_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); switch (create_trig_stmt->timing) { case TRIGGER_TYPE_BEFORE: - appendStringInfoString(str, "BEFORE "); + deparseAppendStringInfoString(state, "BEFORE "); break; case TRIGGER_TYPE_AFTER: - appendStringInfoString(str, "AFTER "); + deparseAppendStringInfoString(state, "AFTER "); break; case TRIGGER_TYPE_INSTEAD: - appendStringInfoString(str, "INSTEAD OF "); + deparseAppendStringInfoString(state, "INSTEAD OF "); break; default: Assert(false); @@ -10128,172 +10738,172 @@ static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_st if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) { - appendStringInfoString(str, "INSERT "); + deparseAppendStringInfoString(state, "INSERT "); skip_events_or = false; } if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) { if (!skip_events_or) - appendStringInfoString(str, "OR "); - appendStringInfoString(str, "DELETE "); + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "DELETE "); skip_events_or = false; } if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) { if (!skip_events_or) - appendStringInfoString(str, "OR "); - appendStringInfoString(str, "UPDATE "); + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "UPDATE "); if (list_length(create_trig_stmt->columns) > 0) { - appendStringInfoString(str, "OF "); - deparseColumnList(str, create_trig_stmt->columns); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "OF "); + deparseColumnList(state, create_trig_stmt->columns); + deparseAppendStringInfoChar(state, ' '); } skip_events_or = false; } if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) { if (!skip_events_or) - appendStringInfoString(str, "OR "); - appendStringInfoString(str, "TRUNCATE "); + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "TRUNCATE "); } - appendStringInfoString(str, "ON "); - deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "ON "); + deparseRangeVar(state, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); if (create_trig_stmt->transitionRels != NULL) { - appendStringInfoString(str, "REFERENCING "); + deparseAppendStringInfoString(state, "REFERENCING "); foreach(lc, create_trig_stmt->transitionRels) { - deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); - appendStringInfoChar(str, ' '); + deparseTriggerTransition(state, castNode(TriggerTransition, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); } } if (create_trig_stmt->constrrel != NULL) { - appendStringInfoString(str, "FROM "); - deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "FROM "); + deparseRangeVar(state, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); } if (create_trig_stmt->deferrable) - appendStringInfoString(str, "DEFERRABLE "); + deparseAppendStringInfoString(state, "DEFERRABLE "); if (create_trig_stmt->initdeferred) - appendStringInfoString(str, "INITIALLY DEFERRED "); + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); if (create_trig_stmt->row) - appendStringInfoString(str, "FOR EACH ROW "); + deparseAppendStringInfoString(state, "FOR EACH ROW "); if (create_trig_stmt->whenClause) { - appendStringInfoString(str, "WHEN ("); - deparseExpr(str, create_trig_stmt->whenClause, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "WHEN ("); + deparseExpr(state, create_trig_stmt->whenClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } - appendStringInfoString(str, "EXECUTE FUNCTION "); - deparseFuncName(str, create_trig_stmt->funcname); - appendStringInfoChar(str, '('); + deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); + deparseFuncName(state, create_trig_stmt->funcname); + deparseAppendStringInfoChar(state, '('); foreach(lc, create_trig_stmt->args) { - deparseStringLiteral(str, strVal(lfirst(lc))); + deparseStringLiteral(state, strVal(lfirst(lc))); if (lnext(create_trig_stmt->args, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } -static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition) { if (trigger_transition->isNew) - appendStringInfoString(str, "NEW "); + deparseAppendStringInfoString(state, "NEW "); else - appendStringInfoString(str, "OLD "); + deparseAppendStringInfoString(state, "OLD "); if (trigger_transition->isTable) - appendStringInfoString(str, "TABLE "); + deparseAppendStringInfoString(state, "TABLE "); else - appendStringInfoString(str, "ROW "); + deparseAppendStringInfoString(state, "ROW "); - appendStringInfoString(str, quote_identifier(trigger_transition->name)); + deparseAppendStringInfoString(state, quote_identifier(trigger_transition->name)); } -static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr, DeparseNodeContext context) +static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context) { switch (xml_expr->op) { case IS_XMLCONCAT: /* XMLCONCAT(args) */ - appendStringInfoString(str, "xmlconcat("); - deparseExprList(str, xml_expr->args); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "xmlconcat("); + deparseExprList(state, xml_expr->args); + deparseAppendStringInfoChar(state, ')'); break; case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ - appendStringInfoString(str, "xmlelement(name "); - appendStringInfoString(str, quote_identifier(xml_expr->name)); + deparseAppendStringInfoString(state, "xmlelement(name "); + deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); if (xml_expr->named_args != NULL) { - appendStringInfoString(str, ", xmlattributes("); - deparseXmlAttributeList(str, xml_expr->named_args); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ", xmlattributes("); + deparseXmlAttributeList(state, xml_expr->named_args); + deparseAppendStringInfoString(state, ")"); } if (xml_expr->args != NULL) { - appendStringInfoString(str, ", "); - deparseExprList(str, xml_expr->args); + deparseAppendStringInfoString(state, ", "); + deparseExprList(state, xml_expr->args); } - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ")"); break; case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ - appendStringInfoString(str, "xmlforest("); - deparseXmlAttributeList(str, xml_expr->named_args); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "xmlforest("); + deparseXmlAttributeList(state, xml_expr->named_args); + deparseAppendStringInfoChar(state, ')'); break; case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ Assert(list_length(xml_expr->args) == 2); - appendStringInfoString(str, "xmlparse("); + deparseAppendStringInfoString(state, "xmlparse("); switch (xml_expr->xmloption) { case XMLOPTION_DOCUMENT: - appendStringInfoString(str, "document "); + deparseAppendStringInfoString(state, "document "); break; case XMLOPTION_CONTENT: - appendStringInfoString(str, "content "); + deparseAppendStringInfoString(state, "content "); break; default: Assert(false); } - deparseExpr(str, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ')'); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); break; case IS_XMLPI: /* XMLPI(name [, args]) */ - appendStringInfoString(str, "xmlpi(name "); - appendStringInfoString(str, quote_identifier(xml_expr->name)); + deparseAppendStringInfoString(state, "xmlpi(name "); + deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); if (xml_expr->args != NULL) { - appendStringInfoString(str, ", "); - deparseExpr(str, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); break; case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ - appendStringInfoString(str, "xmlroot("); - deparseExpr(str, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ", version "); + deparseAppendStringInfoString(state, "xmlroot("); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", version "); if (castNode(A_Const, lsecond(xml_expr->args))->isnull) - appendStringInfoString(str, "NO VALUE"); + deparseAppendStringInfoString(state, "no value"); else - deparseExpr(str, lsecond(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseExpr(state, lsecond(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) - appendStringInfoString(str, ", STANDALONE YES"); + deparseAppendStringInfoString(state, ", standalone yes"); else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) - appendStringInfoString(str, ", STANDALONE NO"); + deparseAppendStringInfoString(state, ", standalone no"); else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) - appendStringInfoString(str, ", STANDALONE NO VALUE"); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, ", standalone no value"); + deparseAppendStringInfoChar(state, ')'); break; case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ // These are represented as XmlSerialize in raw parse trees @@ -10301,132 +10911,132 @@ static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr, DeparseNodeContext break; case IS_DOCUMENT: /* xmlval IS DOCUMENT */ Assert(list_length(xml_expr->args) == 1); - deparseExpr(str, linitial(xml_expr->args), context); - appendStringInfoString(str, " IS DOCUMENT"); + deparseExpr(state, linitial(xml_expr->args), context); + deparseAppendStringInfoString(state, " IS DOCUMENT"); break; } } // "xmltable_column_el" in gram.y -static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +static void deparseRangeTableFuncCol(DeparseState *state, RangeTableFuncCol* range_table_func_col) { - appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, quote_identifier(range_table_func_col->colname)); + deparseAppendStringInfoChar(state, ' '); if (range_table_func_col->for_ordinality) { - appendStringInfoString(str, "FOR ORDINALITY "); + deparseAppendStringInfoString(state, "FOR ORDINALITY "); } else { - deparseTypeName(str, range_table_func_col->typeName); - appendStringInfoChar(str, ' '); + deparseTypeName(state, range_table_func_col->typeName); + deparseAppendStringInfoChar(state, ' '); if (range_table_func_col->colexpr) { - appendStringInfoString(str, "PATH "); - deparseExpr(str, range_table_func_col->colexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "PATH "); + deparseExpr(state, range_table_func_col->colexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseAppendStringInfoChar(state, ' '); } if (range_table_func_col->coldefexpr) { - appendStringInfoString(str, "DEFAULT "); - deparseExpr(str, range_table_func_col->coldefexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "DEFAULT "); + deparseExpr(state, range_table_func_col->coldefexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseAppendStringInfoChar(state, ' '); } if (range_table_func_col->is_not_null) - appendStringInfoString(str, "NOT NULL "); + deparseAppendStringInfoString(state, "NOT NULL "); } - removeTrailingSpace(str); + removeTrailingSpace(state); } // "table_ref" and "xmltable" in gram.y -static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func) { ListCell *lc; if (range_table_func->lateral) - appendStringInfoString(str, "LATERAL "); + deparseAppendStringInfoString(state, "LATERAL "); - appendStringInfoString(str, "xmltable("); + deparseAppendStringInfoString(state, "xmltable("); if (range_table_func->namespaces) { - appendStringInfoString(str, "xmlnamespaces("); - deparseXmlNamespaceList(str, range_table_func->namespaces); - appendStringInfoString(str, "), "); + deparseAppendStringInfoString(state, "xmlnamespaces("); + deparseXmlNamespaceList(state, range_table_func->namespaces); + deparseAppendStringInfoString(state, "), "); } - appendStringInfoChar(str, '('); - deparseExpr(str, range_table_func->rowexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, range_table_func->rowexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoChar(state, ')'); - appendStringInfoString(str, " PASSING "); - deparseExpr(str, range_table_func->docexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoString(state, " PASSING "); + deparseExpr(state, range_table_func->docexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); - appendStringInfoString(str, " COLUMNS "); + deparseAppendStringInfoString(state, " COLUMNS "); foreach(lc, range_table_func->columns) { - deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + deparseRangeTableFuncCol(state, castNode(RangeTableFuncCol, lfirst(lc))); if (lnext(range_table_func->columns, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, ") "); if (range_table_func->alias) { - appendStringInfoString(str, "AS "); - deparseAlias(str, range_table_func->alias); + deparseAppendStringInfoString(state, "AS "); + deparseAlias(state, range_table_func->alias); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize) { - appendStringInfoString(str, "xmlserialize("); + deparseAppendStringInfoString(state, "xmlserialize("); switch (xml_serialize->xmloption) { case XMLOPTION_DOCUMENT: - appendStringInfoString(str, "document "); + deparseAppendStringInfoString(state, "document "); break; case XMLOPTION_CONTENT: - appendStringInfoString(str, "content "); + deparseAppendStringInfoString(state, "content "); break; default: Assert(false); } - deparseExpr(str, xml_serialize->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, " AS "); - deparseTypeName(str, xml_serialize->typeName); + deparseExpr(state, xml_serialize->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, xml_serialize->typeName); if (xml_serialize->indent) { - appendStringInfoString(str, " INDENT"); + deparseAppendStringInfoString(state, " INDENT"); } - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ")"); } -static void deparseJsonFormat(StringInfo str, JsonFormat *json_format) +static void deparseJsonFormat(DeparseState *state, JsonFormat *json_format) { if (json_format == NULL || json_format->format_type == JS_FORMAT_DEFAULT) return; - appendStringInfoString(str, "FORMAT JSON "); + deparseAppendStringInfoString(state, "FORMAT JSON "); switch (json_format->encoding) { case JS_ENC_UTF8: - appendStringInfoString(str, "ENCODING utf8 "); + deparseAppendStringInfoString(state, "ENCODING utf8 "); break; case JS_ENC_UTF16: - appendStringInfoString(str, "ENCODING utf16 "); + deparseAppendStringInfoString(state, "ENCODING utf16 "); break; case JS_ENC_UTF32: - appendStringInfoString(str, "ENCODING utf32 "); + deparseAppendStringInfoString(state, "ENCODING utf32 "); break; case JS_ENC_DEFAULT: // no encoding specified @@ -10434,320 +11044,320 @@ static void deparseJsonFormat(StringInfo str, JsonFormat *json_format) } } -static void deparseJsonIsPredicate(StringInfo str, JsonIsPredicate *j) +static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *j) { - deparseExpr(str, j->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); + deparseExpr(state, j->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); - deparseJsonFormat(str, castNode(JsonFormat, j->format)); + deparseJsonFormat(state, castNode(JsonFormat, j->format)); - appendStringInfoString(str, "IS "); + deparseAppendStringInfoString(state, "IS "); switch (j->item_type) { case JS_TYPE_ANY: - appendStringInfoString(str, "JSON "); + deparseAppendStringInfoString(state, "JSON "); break; case JS_TYPE_ARRAY: - appendStringInfoString(str, "JSON ARRAY "); + deparseAppendStringInfoString(state, "JSON ARRAY "); break; case JS_TYPE_OBJECT: - appendStringInfoString(str, "JSON OBJECT "); + deparseAppendStringInfoString(state, "JSON OBJECT "); break; case JS_TYPE_SCALAR: - appendStringInfoString(str, "JSON SCALAR "); + deparseAppendStringInfoString(state, "JSON SCALAR "); break; } if (j->unique_keys) - appendStringInfoString(str, "WITH UNIQUE "); + deparseAppendStringInfoString(state, "WITH UNIQUE "); - removeTrailingSpace(str); + removeTrailingSpace(state); } // "json_value_expr" in gram.y -static void deparseJsonValueExpr(StringInfo str, JsonValueExpr *json_value_expr) +static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr) { - deparseExpr(str, (Node *) json_value_expr->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoChar(str, ' '); - deparseJsonFormat(str, json_value_expr->format); + deparseExpr(state, (Node *) json_value_expr->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + deparseJsonFormat(state, json_value_expr->format); } // "json_value_expr_list" in gram.y -static void deparseJsonValueExprList(StringInfo str, List *exprs) +static void deparseJsonValueExprList(DeparseState *state, List *exprs) { ListCell *lc; foreach(lc, exprs) { - deparseJsonValueExpr(str, lfirst(lc)); - removeTrailingSpace(str); + deparseJsonValueExpr(state, lfirst(lc)); + removeTrailingSpace(state); if (lnext(exprs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } // "json_name_and_value" in gram.y -static void deparseJsonKeyValue(StringInfo str, JsonKeyValue *json_key_value) +static void deparseJsonKeyValue(DeparseState *state, JsonKeyValue *json_key_value) { - deparseExpr(str, (Node *) json_key_value->key, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ": "); - deparseJsonValueExpr(str, json_key_value->value); + deparseExpr(state, (Node *) json_key_value->key, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ": "); + deparseJsonValueExpr(state, json_key_value->value); } // "json_name_and_value_list" in gram.y -static void deparseJsonKeyValueList(StringInfo str, List *exprs) +static void deparseJsonKeyValueList(DeparseState *state, List *exprs) { ListCell *lc; foreach(lc, exprs) { - deparseJsonKeyValue(str, lfirst(lc)); - removeTrailingSpace(str); + deparseJsonKeyValue(state, lfirst(lc)); + removeTrailingSpace(state); if (lnext(exprs, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); } -static void deparseJsonOutput(StringInfo str, JsonOutput *json_output) +static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output) { if (json_output == NULL) return; Assert(json_output->returning != NULL); - appendStringInfoString(str, "RETURNING "); - deparseTypeName(str, json_output->typeName); - appendStringInfoChar(str, ' '); - deparseJsonFormat(str, json_output->returning->format); + deparseAppendStringInfoString(state, "RETURNING "); + deparseTypeName(state, json_output->typeName); + deparseAppendStringInfoChar(state, ' '); + deparseJsonFormat(state, json_output->returning->format); } // "json_aggregate_func" and "func_expr" in gram.y -static void deparseJsonObjectAgg(StringInfo str, JsonObjectAgg *json_object_agg) +static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg) { Assert(json_object_agg->constructor != NULL); - appendStringInfoString(str, "JSON_OBJECTAGG("); - deparseJsonKeyValue(str, json_object_agg->arg); + deparseAppendStringInfoString(state, "JSON_OBJECTAGG("); + deparseJsonKeyValue(state, json_object_agg->arg); if (json_object_agg->absent_on_null) - appendStringInfoString(str, "ABSENT ON NULL "); + deparseAppendStringInfoString(state, "ABSENT ON NULL "); if (json_object_agg->unique) - appendStringInfoString(str, "WITH UNIQUE "); + deparseAppendStringInfoString(state, "WITH UNIQUE "); - deparseJsonOutput(str, json_object_agg->constructor->output); + deparseJsonOutput(state, json_object_agg->constructor->output); - removeTrailingSpace(str); - appendStringInfoString(str, ") "); + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); if (json_object_agg->constructor->agg_filter) { - appendStringInfoString(str, "FILTER (WHERE "); - deparseExpr(str, json_object_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, json_object_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } if (json_object_agg->constructor->over) { struct WindowDef *over = json_object_agg->constructor->over; - appendStringInfoString(str, "OVER "); + deparseAppendStringInfoString(state, "OVER "); if (over->name) - appendStringInfoString(str, over->name); + deparseAppendStringInfoString(state, over->name); else - deparseWindowDef(str, over); + deparseWindowDef(state, over); } - removeTrailingSpace(str); + removeTrailingSpace(state); } // "json_aggregate_func" and "func_expr" in gram.y -static void deparseJsonArrayAgg(StringInfo str, JsonArrayAgg *json_array_agg) +static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg) { Assert(json_array_agg->constructor != NULL); - appendStringInfoString(str, "JSON_ARRAYAGG("); - deparseJsonValueExpr(str, json_array_agg->arg); - deparseOptSortClause(str, json_array_agg->constructor->agg_order); + deparseAppendStringInfoString(state, "JSON_ARRAYAGG("); + deparseJsonValueExpr(state, json_array_agg->arg); + deparseOptSortClause(state, json_array_agg->constructor->agg_order, DEPARSE_NODE_CONTEXT_NONE); if (!json_array_agg->absent_on_null) - appendStringInfoString(str, "NULL ON NULL "); + deparseAppendStringInfoString(state, "NULL ON NULL "); - deparseJsonOutput(str, json_array_agg->constructor->output); + deparseJsonOutput(state, json_array_agg->constructor->output); - removeTrailingSpace(str); - appendStringInfoString(str, ") "); + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); if (json_array_agg->constructor->agg_filter) { - appendStringInfoString(str, "FILTER (WHERE "); - deparseExpr(str, json_array_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ") "); + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, json_array_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); } if (json_array_agg->constructor->over) { struct WindowDef *over = json_array_agg->constructor->over; - appendStringInfoString(str, "OVER "); + deparseAppendStringInfoString(state, "OVER "); if (over->name) - appendStringInfoString(str, over->name); + deparseAppendStringInfoString(state, over->name); else - deparseWindowDef(str, over); + deparseWindowDef(state, over); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseJsonObjectConstructor(StringInfo str, JsonObjectConstructor *json_object_constructor) +static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor) { - appendStringInfoString(str, "JSON_OBJECT("); - deparseJsonKeyValueList(str, json_object_constructor->exprs); + deparseAppendStringInfoString(state, "JSON_OBJECT("); + deparseJsonKeyValueList(state, json_object_constructor->exprs); if (json_object_constructor->absent_on_null) - appendStringInfoString(str, "ABSENT ON NULL "); + deparseAppendStringInfoString(state, "ABSENT ON NULL "); if (json_object_constructor->unique) - appendStringInfoString(str, "WITH UNIQUE "); + deparseAppendStringInfoString(state, "WITH UNIQUE "); - deparseJsonOutput(str, json_object_constructor->output); + deparseJsonOutput(state, json_object_constructor->output); - removeTrailingSpace(str); - appendStringInfoChar(str, ')'); + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); } -static void deparseJsonArrayConstructor(StringInfo str, JsonArrayConstructor *json_array_constructor) +static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor) { - appendStringInfoString(str, "JSON_ARRAY("); - deparseJsonValueExprList(str, json_array_constructor->exprs); + deparseAppendStringInfoString(state, "JSON_ARRAY("); + deparseJsonValueExprList(state, json_array_constructor->exprs); if (!json_array_constructor->absent_on_null) - appendStringInfoString(str, "NULL ON NULL "); + deparseAppendStringInfoString(state, "NULL ON NULL "); - deparseJsonOutput(str, json_array_constructor->output); + deparseJsonOutput(state, json_array_constructor->output); - removeTrailingSpace(str); - appendStringInfoChar(str, ')'); + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); } -static void deparseJsonArrayQueryConstructor(StringInfo str, JsonArrayQueryConstructor *json_array_query_constructor) +static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor) { - appendStringInfoString(str, "JSON_ARRAY("); + deparseAppendStringInfoString(state, "JSON_ARRAY("); - deparseSelectStmt(str, castNode(SelectStmt, json_array_query_constructor->query)); - deparseJsonFormat(str, json_array_query_constructor->format); - deparseJsonOutput(str, json_array_query_constructor->output); + deparseSelectStmt(state, castNode(SelectStmt, json_array_query_constructor->query), DEPARSE_NODE_CONTEXT_NONE); + deparseJsonFormat(state, json_array_query_constructor->format); + deparseJsonOutput(state, json_array_query_constructor->output); - removeTrailingSpace(str); - appendStringInfoChar(str, ')'); + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); } -static void deparseJsonParseExpr(StringInfo str, JsonParseExpr *json_parse_expr) +static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr) { - appendStringInfoString(str, "JSON("); + deparseAppendStringInfoString(state, "JSON("); - deparseJsonValueExpr(str, json_parse_expr->expr); + deparseJsonValueExpr(state, json_parse_expr->expr); if (json_parse_expr->unique_keys) - appendStringInfoString(str, " WITH UNIQUE KEYS"); + deparseAppendStringInfoString(state, " WITH UNIQUE KEYS"); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ")"); } -static void deparseJsonScalarExpr(StringInfo str, JsonScalarExpr *json_scalar_expr) +static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr) { - appendStringInfoString(str, "JSON_SCALAR("); - deparseExpr(str, (Node*) json_scalar_expr->expr, DEPARSE_NODE_CONTEXT_A_EXPR); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, "JSON_SCALAR("); + deparseExpr(state, (Node*) json_scalar_expr->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ")"); } -static void deparseJsonSerializeExpr(StringInfo str, JsonSerializeExpr *json_serialize_expr) +static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr) { - appendStringInfoString(str, "JSON_SERIALIZE("); + deparseAppendStringInfoString(state, "JSON_SERIALIZE("); - deparseJsonValueExpr(str, json_serialize_expr->expr); + deparseJsonValueExpr(state, json_serialize_expr->expr); if (json_serialize_expr->output) - deparseJsonOutput(str, json_serialize_expr->output); + deparseJsonOutput(state, json_serialize_expr->output); - appendStringInfoString(str, ")"); + deparseAppendStringInfoString(state, ")"); } -static void deparseJsonQuotesClauseOpt(StringInfo str, JsonQuotes quotes) +static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes) { switch (quotes) { case JS_QUOTES_UNSPEC: break; case JS_QUOTES_KEEP: - appendStringInfoString(str, " KEEP QUOTES"); + deparseAppendStringInfoString(state, " KEEP QUOTES"); break; case JS_QUOTES_OMIT: - appendStringInfoString(str, " OMIT QUOTES"); + deparseAppendStringInfoString(state, " OMIT QUOTES"); break; } } -static void deparseJsonOnErrorClauseOpt(StringInfo str, JsonBehavior *behavior) +static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior) { if (!behavior) return; - appendStringInfoChar(str, ' '); - deparseJsonBehavior(str, behavior); - appendStringInfoString(str, " ON ERROR"); + deparseAppendStringInfoChar(state, ' '); + deparseJsonBehavior(state, behavior); + deparseAppendStringInfoString(state, " ON ERROR"); } -static void deparseJsonOnEmptyClauseOpt(StringInfo str, JsonBehavior *behavior) +static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior) { if (behavior) { - appendStringInfoChar(str, ' '); - deparseJsonBehavior(str, behavior); - appendStringInfoString(str, " ON EMPTY"); + deparseAppendStringInfoChar(state, ' '); + deparseJsonBehavior(state, behavior); + deparseAppendStringInfoString(state, " ON EMPTY"); } } -static void deparseJsonFuncExpr(StringInfo str, JsonFuncExpr *json_func_expr) +static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr) { switch (json_func_expr->op) { case JSON_EXISTS_OP: - appendStringInfoString(str, "JSON_EXISTS("); + deparseAppendStringInfoString(state, "JSON_EXISTS("); break; case JSON_QUERY_OP: - appendStringInfoString(str, "JSON_QUERY("); + deparseAppendStringInfoString(state, "JSON_QUERY("); break; case JSON_VALUE_OP: - appendStringInfoString(str, "JSON_VALUE("); + deparseAppendStringInfoString(state, "JSON_VALUE("); break; case JSON_TABLE_OP: - appendStringInfoString(str, "JSON_TABLE("); + deparseAppendStringInfoString(state, "JSON_TABLE("); break; } - deparseJsonValueExpr(str, json_func_expr->context_item); - appendStringInfoString(str, ", "); - deparseExpr(str, json_func_expr->pathspec, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseJsonValueExpr(state, json_func_expr->context_item); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, json_func_expr->pathspec, DEPARSE_NODE_CONTEXT_A_EXPR); if (json_func_expr->passing) - appendStringInfoString(str, " PASSING "); + deparseAppendStringInfoString(state, " PASSING "); ListCell *lc = NULL; foreach (lc, json_func_expr->passing) { JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); - deparseJsonValueExpr(str, json_argument->val); - appendStringInfoString(str, " AS "); - deparseColLabel(str, json_argument->name); + deparseJsonValueExpr(state, json_argument->val); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_argument->name); if (lnext(json_func_expr->passing, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } if (json_func_expr->output) { - appendStringInfoChar(str, ' '); - deparseJsonOutput(str, json_func_expr->output); + deparseAppendStringInfoChar(state, ' '); + deparseJsonOutput(state, json_func_expr->output); } switch (json_func_expr->wrapper) @@ -10755,105 +11365,105 @@ static void deparseJsonFuncExpr(StringInfo str, JsonFuncExpr *json_func_expr) case JSW_UNSPEC: break; case JSW_NONE: - appendStringInfoString(str, " WITHOUT WRAPPER"); + deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); break; case JSW_CONDITIONAL: - appendStringInfoString(str, " WITH CONDITIONAL WRAPPER"); + deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); break; case JSW_UNCONDITIONAL: - appendStringInfoString(str, " WITH UNCONDITIONAL WRAPPER"); + deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); break; } - deparseJsonQuotesClauseOpt(str, json_func_expr->quotes); - deparseJsonOnEmptyClauseOpt(str, json_func_expr->on_empty); - deparseJsonOnErrorClauseOpt(str, json_func_expr->on_error); + deparseJsonQuotesClauseOpt(state, json_func_expr->quotes); + deparseJsonOnEmptyClauseOpt(state, json_func_expr->on_empty); + deparseJsonOnErrorClauseOpt(state, json_func_expr->on_error); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } -static void deparseJsonTablePathSpec(StringInfo str, JsonTablePathSpec *json_table_path_spec) +static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec) { - deparseStringLiteral(str, castNode(A_Const, json_table_path_spec->string)->val.sval.sval); + deparseStringLiteral(state, castNode(A_Const, json_table_path_spec->string)->val.sval.sval); if (json_table_path_spec->name) { - appendStringInfoString(str, " AS "); - deparseColLabel(str, json_table_path_spec->name); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_table_path_spec->name); } } // "json_behavior" in gram.y -static void deparseJsonBehavior(StringInfo str, JsonBehavior *json_behavior) +static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior) { switch (json_behavior->btype) { case JSON_BEHAVIOR_NULL: - appendStringInfoString(str, "NULL"); + deparseAppendStringInfoString(state, "NULL"); break; case JSON_BEHAVIOR_ERROR: - appendStringInfoString(str, "ERROR"); + deparseAppendStringInfoString(state, "ERROR"); break; case JSON_BEHAVIOR_EMPTY: - appendStringInfoString(str, "EMPTY"); + deparseAppendStringInfoString(state, "EMPTY"); break; case JSON_BEHAVIOR_TRUE: - appendStringInfoString(str, "TRUE"); + deparseAppendStringInfoString(state, "TRUE"); break; case JSON_BEHAVIOR_FALSE: - appendStringInfoString(str, "FALSE"); + deparseAppendStringInfoString(state, "FALSE"); break; case JSON_BEHAVIOR_EMPTY_ARRAY: - appendStringInfoString(str, "EMPTY ARRAY"); + deparseAppendStringInfoString(state, "EMPTY ARRAY"); break; case JSON_BEHAVIOR_EMPTY_OBJECT: - appendStringInfoString(str, "EMPTY OBJECT"); + deparseAppendStringInfoString(state, "EMPTY OBJECT"); break; case JSON_BEHAVIOR_DEFAULT: - appendStringInfoString(str, "DEFAULT "); - deparseExpr(str, (Node*) json_behavior->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, "DEFAULT "); + deparseExpr(state, (Node*) json_behavior->expr, DEPARSE_NODE_CONTEXT_A_EXPR); break; case JSON_BEHAVIOR_UNKNOWN: - appendStringInfoString(str, "UNKNOWN"); + deparseAppendStringInfoString(state, "UNKNOWN"); break; } } -static void deparseJsonTableColumn(StringInfo str, JsonTableColumn *json_table_column) +static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column) { if (json_table_column->coltype == JTC_NESTED) { - appendStringInfoString(str, "NESTED PATH "); - deparseJsonTablePathSpec(str, json_table_column->pathspec); - deparseJsonTableColumns(str, json_table_column->columns); + deparseAppendStringInfoString(state, "NESTED PATH "); + deparseJsonTablePathSpec(state, json_table_column->pathspec); + deparseJsonTableColumns(state, json_table_column->columns); return; } - deparseColLabel(str, json_table_column->name); - appendStringInfoChar(str, ' '); + deparseColLabel(state, json_table_column->name); + deparseAppendStringInfoChar(state, ' '); switch (json_table_column->coltype) { case JTC_FOR_ORDINALITY: - appendStringInfoString(str, " FOR ORDINALITY"); + deparseAppendStringInfoString(state, " FOR ORDINALITY"); break; case JTC_EXISTS: case JTC_FORMATTED: case JTC_REGULAR: - deparseTypeName(str, json_table_column->typeName); + deparseTypeName(state, json_table_column->typeName); if (json_table_column->coltype == JTC_EXISTS) - appendStringInfoString(str, " EXISTS "); + deparseAppendStringInfoString(state, " EXISTS "); else - appendStringInfoChar(str, ' '); + deparseAppendStringInfoChar(state, ' '); if (json_table_column->format) - deparseJsonFormat(str, json_table_column->format); + deparseJsonFormat(state, json_table_column->format); if (json_table_column->pathspec) { - appendStringInfoString(str, "PATH "); - deparseJsonTablePathSpec(str, json_table_column->pathspec); + deparseAppendStringInfoString(state, "PATH "); + deparseJsonTablePathSpec(state, json_table_column->pathspec); } break; case JTC_NESTED: @@ -10866,110 +11476,110 @@ static void deparseJsonTableColumn(StringInfo str, JsonTableColumn *json_table_c break; case JSW_NONE: if (json_table_column->coltype == JTC_REGULAR || json_table_column->coltype == JTC_FORMATTED) - appendStringInfoString(str, " WITHOUT WRAPPER"); + deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); break; case JSW_CONDITIONAL: - appendStringInfoString(str, " WITH CONDITIONAL WRAPPER"); + deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); break; case JSW_UNCONDITIONAL: - appendStringInfoString(str, " WITH UNCONDITIONAL WRAPPER"); + deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); break; } - deparseJsonQuotesClauseOpt(str, json_table_column->quotes); - deparseJsonOnEmptyClauseOpt(str, json_table_column->on_empty); - deparseJsonOnErrorClauseOpt(str, json_table_column->on_error); + deparseJsonQuotesClauseOpt(state, json_table_column->quotes); + deparseJsonOnEmptyClauseOpt(state, json_table_column->on_empty); + deparseJsonOnErrorClauseOpt(state, json_table_column->on_error); } -static void deparseJsonTableColumns(StringInfo str, List *json_table_columns) +static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns) { - appendStringInfoString(str, " COLUMNS ("); + deparseAppendStringInfoString(state, " COLUMNS ("); ListCell *lc = NULL; foreach(lc, json_table_columns) { - deparseJsonTableColumn(str, castNode(JsonTableColumn, lfirst(lc))); + deparseJsonTableColumn(state, castNode(JsonTableColumn, lfirst(lc))); if (lnext(json_table_columns, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); } -static void deparseJsonTable(StringInfo str, JsonTable *json_table) +static void deparseJsonTable(DeparseState *state, JsonTable *json_table) { - appendStringInfoString(str, "JSON_TABLE("); + deparseAppendStringInfoString(state, "JSON_TABLE("); - deparseJsonValueExpr(str, json_table->context_item); - appendStringInfoString(str, ", "); - deparseJsonTablePathSpec(str, json_table->pathspec); + deparseJsonValueExpr(state, json_table->context_item); + deparseAppendStringInfoString(state, ", "); + deparseJsonTablePathSpec(state, json_table->pathspec); if (json_table->passing) - appendStringInfoString(str, " PASSING "); + deparseAppendStringInfoString(state, " PASSING "); ListCell *lc = NULL; foreach (lc, json_table->passing) { JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); - deparseJsonValueExpr(str, json_argument->val); - appendStringInfoString(str, " AS "); - deparseColLabel(str, json_argument->name); + deparseJsonValueExpr(state, json_argument->val); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_argument->name); if (lnext(json_table->passing, lc)) - appendStringInfoString(str, ", "); + deparseAppendStringInfoString(state, ", "); } - deparseJsonTableColumns(str, json_table->columns); + deparseJsonTableColumns(state, json_table->columns); if (json_table->on_error) { - deparseJsonBehavior(str, json_table->on_error); - appendStringInfoString(str, " ON ERROR"); + deparseJsonBehavior(state, json_table->on_error); + deparseAppendStringInfoString(state, " ON ERROR"); } - appendStringInfoChar(str, ')'); + deparseAppendStringInfoChar(state, ')'); if (json_table->alias) { - appendStringInfoChar(str, ' '); - deparseAlias(str, json_table->alias); + deparseAppendStringInfoChar(state, ' '); + deparseAlias(state, json_table->alias); } } -static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func) { - appendStringInfoString(str, "GROUPING("); - deparseExprList(str, grouping_func->args); - appendStringInfoChar(str, ')'); + deparseAppendStringInfoString(state, "GROUPING("); + deparseExprList(state, grouping_func->args); + deparseAppendStringInfoChar(state, ')'); } -static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +static void deparseClusterStmt(DeparseState *state, ClusterStmt *cluster_stmt) { - appendStringInfoString(str, "CLUSTER "); + deparseAppendStringInfoString(state, "CLUSTER "); - deparseUtilityOptionList(str, cluster_stmt->params); + deparseUtilityOptionList(state, cluster_stmt->params); if (cluster_stmt->relation != NULL) { - deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); + deparseRangeVar(state, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); } if (cluster_stmt->indexname != NULL) { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); - appendStringInfoChar(str, ' '); + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(cluster_stmt->indexname)); + deparseAppendStringInfoChar(state, ' '); } - removeTrailingSpace(str); + removeTrailingSpace(state); } -static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context) +static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context) { if (!value) { - appendStringInfoString(str, "NULL"); + deparseAppendStringInfoString(state, "NULL"); return; } @@ -10977,30 +11587,30 @@ static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeConte { case T_Integer: case T_Float: - deparseNumericOnly(str, value); + deparseNumericOnly(state, value); break; case T_Boolean: - appendStringInfoString(str, value->boolval.boolval ? "true" : "false"); + deparseAppendStringInfoString(state, value->boolval.boolval ? "true" : "false"); break; case T_String: if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { - appendStringInfoString(str, quote_identifier(value->sval.sval)); + deparseAppendStringInfoString(state, quote_identifier(value->sval.sval)); } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { - deparseStringLiteral(str, value->sval.sval); + deparseStringLiteral(state, value->sval.sval); } else { - appendStringInfoString(str, value->sval.sval); + deparseAppendStringInfoString(state, value->sval.sval); } break; case T_BitString: if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') { - appendStringInfoChar(str, 'x'); - deparseStringLiteral(str, value->sval.sval + 1); + deparseAppendStringInfoChar(state, 'x'); + deparseStringLiteral(state, value->sval.sval + 1); } else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') { - appendStringInfoChar(str, 'b'); - deparseStringLiteral(str, value->sval.sval + 1); + deparseAppendStringInfoChar(state, 'b'); + deparseStringLiteral(state, value->sval.sval + 1); } else { @@ -11015,24 +11625,24 @@ static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeConte } // "PrepareableStmt" in gram.y -static void deparsePreparableStmt(StringInfo str, Node *node) +static void deparsePreparableStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); + deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); + deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); + deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_MergeStmt: - deparseMergeStmt(str, castNode(MergeStmt, node)); + deparseMergeStmt(state, castNode(MergeStmt, node)); break; default: Assert(false); @@ -11040,24 +11650,24 @@ static void deparsePreparableStmt(StringInfo str, Node *node) } // "RuleActionStmt" in gram.y -static void deparseRuleActionStmt(StringInfo str, Node *node) +static void deparseRuleActionStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); + deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); + deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); + deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_NotifyStmt: - deparseNotifyStmt(str, castNode(NotifyStmt, node)); + deparseNotifyStmt(state, castNode(NotifyStmt, node)); break; default: Assert(false); @@ -11065,36 +11675,36 @@ static void deparseRuleActionStmt(StringInfo str, Node *node) } // "ExplainableStmt" in gram.y -static void deparseExplainableStmt(StringInfo str, Node *node) +static void deparseExplainableStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); + deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); + deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); + deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_DeclareCursorStmt: - deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); break; case T_CreateTableAsStmt: - deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); break; case T_RefreshMatViewStmt: - deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); break; case T_ExecuteStmt: - deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + deparseExecuteStmt(state, castNode(ExecuteStmt, node)); break; case T_MergeStmt: - deparseMergeStmt(str, castNode(MergeStmt, node)); + deparseMergeStmt(state, castNode(MergeStmt, node)); break; default: Assert(false); @@ -11102,27 +11712,27 @@ static void deparseExplainableStmt(StringInfo str, Node *node) } // "schema_stmt" in gram.y -static void deparseSchemaStmt(StringInfo str, Node *node) +static void deparseSchemaStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_CreateStmt: - deparseCreateStmt(str, castNode(CreateStmt, node), false); + deparseCreateStmt(state, castNode(CreateStmt, node), false); break; case T_IndexStmt: - deparseIndexStmt(str, castNode(IndexStmt, node)); + deparseIndexStmt(state, castNode(IndexStmt, node)); break; case T_CreateSeqStmt: - deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); break; case T_CreateTrigStmt: - deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); break; case T_GrantStmt: - deparseGrantStmt(str, castNode(GrantStmt, node)); + deparseGrantStmt(state, castNode(GrantStmt, node)); break; case T_ViewStmt: - deparseViewStmt(str, castNode(ViewStmt, node)); + deparseViewStmt(state, castNode(ViewStmt, node)); break; default: Assert(false); @@ -11130,8 +11740,21 @@ static void deparseSchemaStmt(StringInfo str, Node *node) } // "stmt" in gram.y -static void deparseStmt(StringInfo str, Node *node) +static void deparseStmt(DeparseState *state, Node *node) { + DeparseStateNestingLevel *parent_level = NULL; + + // For statements that can be nested, push/pop is handled directly in the + // respective deparse...Stmt methods + bool skip_push_pop = IsA(node, SelectStmt) || + IsA(node, InsertStmt) || + IsA(node, UpdateStmt) || + IsA(node, DeleteStmt) || + IsA(node, MergeStmt); + + if (!skip_push_pop) + parent_level = deparseStateIncreaseNestingLevel(state); + // Note the following grammar names are missing in the list, because they // get mapped to other node types: // @@ -11159,340 +11782,343 @@ static void deparseStmt(StringInfo str, Node *node) switch (nodeTag(node)) { case T_AlterEventTrigStmt: - deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + deparseAlterEventTrigStmt(state, castNode(AlterEventTrigStmt, node)); break; case T_AlterCollationStmt: - deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + deparseAlterCollationStmt(state, castNode(AlterCollationStmt, node)); break; case T_AlterDatabaseStmt: - deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + deparseAlterDatabaseStmt(state, castNode(AlterDatabaseStmt, node)); break; case T_AlterDatabaseSetStmt: - deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + deparseAlterDatabaseSetStmt(state, castNode(AlterDatabaseSetStmt, node)); break; case T_AlterDefaultPrivilegesStmt: - deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + deparseAlterDefaultPrivilegesStmt(state, castNode(AlterDefaultPrivilegesStmt, node)); break; case T_AlterDomainStmt: - deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + deparseAlterDomainStmt(state, castNode(AlterDomainStmt, node)); break; case T_AlterEnumStmt: - deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + deparseAlterEnumStmt(state, castNode(AlterEnumStmt, node)); break; case T_AlterExtensionStmt: - deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + deparseAlterExtensionStmt(state, castNode(AlterExtensionStmt, node)); break; case T_AlterExtensionContentsStmt: - deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + deparseAlterExtensionContentsStmt(state, castNode(AlterExtensionContentsStmt, node)); break; case T_AlterFdwStmt: - deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + deparseAlterFdwStmt(state, castNode(AlterFdwStmt, node)); break; case T_AlterForeignServerStmt: - deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + deparseAlterForeignServerStmt(state, castNode(AlterForeignServerStmt, node)); break; case T_AlterFunctionStmt: - deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + deparseAlterFunctionStmt(state, castNode(AlterFunctionStmt, node)); break; case T_AlterObjectDependsStmt: - deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + deparseAlterObjectDependsStmt(state, castNode(AlterObjectDependsStmt, node)); break; case T_AlterObjectSchemaStmt: - deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + deparseAlterObjectSchemaStmt(state, castNode(AlterObjectSchemaStmt, node)); break; case T_AlterOwnerStmt: - deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + deparseAlterOwnerStmt(state, castNode(AlterOwnerStmt, node)); break; case T_AlterOperatorStmt: - deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + deparseAlterOperatorStmt(state, castNode(AlterOperatorStmt, node)); break; case T_AlterTypeStmt: - deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); + deparseAlterTypeStmt(state, castNode(AlterTypeStmt, node)); break; case T_AlterPolicyStmt: - deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + deparseAlterPolicyStmt(state, castNode(AlterPolicyStmt, node)); break; case T_AlterSeqStmt: - deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + deparseAlterSeqStmt(state, castNode(AlterSeqStmt, node)); break; case T_AlterSystemStmt: - deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + deparseAlterSystemStmt(state, castNode(AlterSystemStmt, node)); break; case T_AlterTableMoveAllStmt: - deparseAlterTableMoveAllStmt(str, castNode(AlterTableMoveAllStmt, node)); + deparseAlterTableMoveAllStmt(state, castNode(AlterTableMoveAllStmt, node)); break; case T_AlterTableStmt: - deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + deparseAlterTableStmt(state, castNode(AlterTableStmt, node)); break; case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y - deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + deparseAlterTableSpaceOptionsStmt(state, castNode(AlterTableSpaceOptionsStmt, node)); break; case T_AlterPublicationStmt: - deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + deparseAlterPublicationStmt(state, castNode(AlterPublicationStmt, node)); break; case T_AlterRoleSetStmt: - deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + deparseAlterRoleSetStmt(state, castNode(AlterRoleSetStmt, node)); break; case T_AlterRoleStmt: - deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + deparseAlterRoleStmt(state, castNode(AlterRoleStmt, node)); break; case T_AlterSubscriptionStmt: - deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + deparseAlterSubscriptionStmt(state, castNode(AlterSubscriptionStmt, node)); break; case T_AlterStatsStmt: - deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); + deparseAlterStatsStmt(state, castNode(AlterStatsStmt, node)); break; case T_AlterTSConfigurationStmt: - deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + deparseAlterTSConfigurationStmt(state, castNode(AlterTSConfigurationStmt, node)); break; case T_AlterTSDictionaryStmt: - deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + deparseAlterTSDictionaryStmt(state, castNode(AlterTSDictionaryStmt, node)); break; case T_AlterUserMappingStmt: - deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + deparseAlterUserMappingStmt(state, castNode(AlterUserMappingStmt, node)); break; case T_CallStmt: - deparseCallStmt(str, castNode(CallStmt, node)); + deparseCallStmt(state, castNode(CallStmt, node)); break; case T_CheckPointStmt: - deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + deparseCheckPointStmt(state, castNode(CheckPointStmt, node)); break; case T_ClosePortalStmt: - deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + deparseClosePortalStmt(state, castNode(ClosePortalStmt, node)); break; case T_ClusterStmt: - deparseClusterStmt(str, castNode(ClusterStmt, node)); + deparseClusterStmt(state, castNode(ClusterStmt, node)); break; case T_CommentStmt: - deparseCommentStmt(str, castNode(CommentStmt, node)); + deparseCommentStmt(state, castNode(CommentStmt, node)); break; case T_ConstraintsSetStmt: - deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + deparseConstraintsSetStmt(state, castNode(ConstraintsSetStmt, node)); break; case T_CopyStmt: - deparseCopyStmt(str, castNode(CopyStmt, node)); + deparseCopyStmt(state, castNode(CopyStmt, node)); break; case T_CreateAmStmt: - deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + deparseCreateAmStmt(state, castNode(CreateAmStmt, node)); break; case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y - deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); break; case T_CreateCastStmt: - deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + deparseCreateCastStmt(state, castNode(CreateCastStmt, node)); break; case T_CreateConversionStmt: - deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + deparseCreateConversionStmt(state, castNode(CreateConversionStmt, node)); break; case T_CreateDomainStmt: - deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + deparseCreateDomainStmt(state, castNode(CreateDomainStmt, node)); break; case T_CreateExtensionStmt: - deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + deparseCreateExtensionStmt(state, castNode(CreateExtensionStmt, node)); break; case T_CreateFdwStmt: - deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + deparseCreateFdwStmt(state, castNode(CreateFdwStmt, node)); break; case T_CreateForeignServerStmt: - deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + deparseCreateForeignServerStmt(state, castNode(CreateForeignServerStmt, node)); break; case T_CreateForeignTableStmt: - deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + deparseCreateForeignTableStmt(state, castNode(CreateForeignTableStmt, node)); break; case T_CreateFunctionStmt: - deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + deparseCreateFunctionStmt(state, castNode(CreateFunctionStmt, node)); break; case T_CreateOpClassStmt: - deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + deparseCreateOpClassStmt(state, castNode(CreateOpClassStmt, node)); break; case T_CreateOpFamilyStmt: - deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + deparseCreateOpFamilyStmt(state, castNode(CreateOpFamilyStmt, node)); break; case T_CreatePublicationStmt: - deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + deparseCreatePublicationStmt(state, castNode(CreatePublicationStmt, node)); break; case T_AlterOpFamilyStmt: - deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + deparseAlterOpFamilyStmt(state, castNode(AlterOpFamilyStmt, node)); break; case T_CreatePolicyStmt: - deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + deparseCreatePolicyStmt(state, castNode(CreatePolicyStmt, node)); break; case T_CreatePLangStmt: - deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + deparseCreatePLangStmt(state, castNode(CreatePLangStmt, node)); break; case T_CreateSchemaStmt: - deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + deparseCreateSchemaStmt(state, castNode(CreateSchemaStmt, node)); break; case T_CreateSeqStmt: - deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); break; case T_CreateStmt: - deparseCreateStmt(str, castNode(CreateStmt, node), false); + deparseCreateStmt(state, castNode(CreateStmt, node), false); break; case T_CreateSubscriptionStmt: - deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + deparseCreateSubscriptionStmt(state, castNode(CreateSubscriptionStmt, node)); break; case T_CreateStatsStmt: - deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + deparseCreateStatsStmt(state, castNode(CreateStatsStmt, node)); break; case T_CreateTableSpaceStmt: - deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + deparseCreateTableSpaceStmt(state, castNode(CreateTableSpaceStmt, node)); break; case T_CreateTransformStmt: - deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + deparseCreateTransformStmt(state, castNode(CreateTransformStmt, node)); break; case T_CreateTrigStmt: - deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); break; case T_CreateEventTrigStmt: - deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + deparseCreateEventTrigStmt(state, castNode(CreateEventTrigStmt, node)); break; case T_CreateRoleStmt: - deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + deparseCreateRoleStmt(state, castNode(CreateRoleStmt, node)); break; case T_CreateUserMappingStmt: - deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + deparseCreateUserMappingStmt(state, castNode(CreateUserMappingStmt, node)); break; case T_CreatedbStmt: - deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + deparseCreatedbStmt(state, castNode(CreatedbStmt, node)); break; case T_DeallocateStmt: - deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + deparseDeallocateStmt(state, castNode(DeallocateStmt, node)); break; case T_DeclareCursorStmt: - deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); break; case T_DefineStmt: - deparseDefineStmt(str, castNode(DefineStmt, node)); + deparseDefineStmt(state, castNode(DefineStmt, node)); break; case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); + deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_DiscardStmt: - deparseDiscardStmt(str, castNode(DiscardStmt, node)); + deparseDiscardStmt(state, castNode(DiscardStmt, node)); break; case T_DoStmt: - deparseDoStmt(str, castNode(DoStmt, node)); + deparseDoStmt(state, castNode(DoStmt, node)); break; case T_DropOwnedStmt: - deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + deparseDropOwnedStmt(state, castNode(DropOwnedStmt, node)); break; case T_DropStmt: - deparseDropStmt(str, castNode(DropStmt, node)); + deparseDropStmt(state, castNode(DropStmt, node)); break; case T_DropSubscriptionStmt: - deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + deparseDropSubscriptionStmt(state, castNode(DropSubscriptionStmt, node)); break; case T_DropTableSpaceStmt: - deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + deparseDropTableSpaceStmt(state, castNode(DropTableSpaceStmt, node)); break; case T_DropRoleStmt: - deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + deparseDropRoleStmt(state, castNode(DropRoleStmt, node)); break; case T_DropUserMappingStmt: - deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + deparseDropUserMappingStmt(state, castNode(DropUserMappingStmt, node)); break; case T_DropdbStmt: - deparseDropdbStmt(str, castNode(DropdbStmt, node)); + deparseDropdbStmt(state, castNode(DropdbStmt, node)); break; case T_ExecuteStmt: - deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + deparseExecuteStmt(state, castNode(ExecuteStmt, node)); break; case T_ExplainStmt: - deparseExplainStmt(str, castNode(ExplainStmt, node)); + deparseExplainStmt(state, castNode(ExplainStmt, node)); break; case T_FetchStmt: - deparseFetchStmt(str, castNode(FetchStmt, node)); + deparseFetchStmt(state, castNode(FetchStmt, node)); break; case T_GrantStmt: - deparseGrantStmt(str, castNode(GrantStmt, node)); + deparseGrantStmt(state, castNode(GrantStmt, node)); break; case T_GrantRoleStmt: - deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + deparseGrantRoleStmt(state, castNode(GrantRoleStmt, node)); break; case T_ImportForeignSchemaStmt: - deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + deparseImportForeignSchemaStmt(state, castNode(ImportForeignSchemaStmt, node)); break; case T_IndexStmt: - deparseIndexStmt(str, castNode(IndexStmt, node)); + deparseIndexStmt(state, castNode(IndexStmt, node)); break; case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); + deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_ListenStmt: - deparseListenStmt(str, castNode(ListenStmt, node)); + deparseListenStmt(state, castNode(ListenStmt, node)); break; case T_RefreshMatViewStmt: - deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); break; case T_LoadStmt: - deparseLoadStmt(str, castNode(LoadStmt, node)); + deparseLoadStmt(state, castNode(LoadStmt, node)); break; case T_LockStmt: - deparseLockStmt(str, castNode(LockStmt, node)); + deparseLockStmt(state, castNode(LockStmt, node)); break; case T_MergeStmt: - deparseMergeStmt(str, castNode(MergeStmt, node)); + deparseMergeStmt(state, castNode(MergeStmt, node)); break; case T_NotifyStmt: - deparseNotifyStmt(str, castNode(NotifyStmt, node)); + deparseNotifyStmt(state, castNode(NotifyStmt, node)); break; case T_PrepareStmt: - deparsePrepareStmt(str, castNode(PrepareStmt, node)); + deparsePrepareStmt(state, castNode(PrepareStmt, node)); break; case T_ReassignOwnedStmt: - deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + deparseReassignOwnedStmt(state, castNode(ReassignOwnedStmt, node)); break; case T_ReindexStmt: - deparseReindexStmt(str, castNode(ReindexStmt, node)); + deparseReindexStmt(state, castNode(ReindexStmt, node)); break; case T_RenameStmt: - deparseRenameStmt(str, castNode(RenameStmt, node)); + deparseRenameStmt(state, castNode(RenameStmt, node)); break; case T_RuleStmt: - deparseRuleStmt(str, castNode(RuleStmt, node)); + deparseRuleStmt(state, castNode(RuleStmt, node)); break; case T_SecLabelStmt: - deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + deparseSecLabelStmt(state, castNode(SecLabelStmt, node)); break; case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_TransactionStmt: - deparseTransactionStmt(str, castNode(TransactionStmt, node)); + deparseTransactionStmt(state, castNode(TransactionStmt, node)); break; case T_TruncateStmt: - deparseTruncateStmt(str, castNode(TruncateStmt, node)); + deparseTruncateStmt(state, castNode(TruncateStmt, node)); break; case T_UnlistenStmt: - deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + deparseUnlistenStmt(state, castNode(UnlistenStmt, node)); break; case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); + deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_VacuumStmt: - deparseVacuumStmt(str, castNode(VacuumStmt, node)); + deparseVacuumStmt(state, castNode(VacuumStmt, node)); break; case T_VariableSetStmt: - deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + deparseVariableSetStmt(state, castNode(VariableSetStmt, node)); break; case T_VariableShowStmt: - deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + deparseVariableShowStmt(state, castNode(VariableShowStmt, node)); break; case T_ViewStmt: - deparseViewStmt(str, castNode(ViewStmt, node)); + deparseViewStmt(state, castNode(ViewStmt, node)); break; // These node types are created by DefineStmt grammar for CREATE TYPE in some cases case T_CompositeTypeStmt: - deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + deparseCompositeTypeStmt(state, castNode(CompositeTypeStmt, node)); break; case T_CreateEnumStmt: - deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + deparseCreateEnumStmt(state, castNode(CreateEnumStmt, node)); break; case T_CreateRangeStmt: - deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + deparseCreateRangeStmt(state, castNode(CreateRangeStmt, node)); break; default: elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); } + + if (!skip_push_pop) + deparseStateDecreaseNestingLevel(state, parent_level); } diff --git a/c_src/libpg_query/src/postgres_deparse.h b/c_src/libpg_query/src/postgres_deparse.h deleted file mode 100644 index 76a6e70e..00000000 --- a/c_src/libpg_query/src/postgres_deparse.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef POSTGRES_DEPARSE_H -#define POSTGRES_DEPARSE_H - -#include "lib/stringinfo.h" -#include "nodes/parsenodes.h" - -extern void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); - -#endif diff --git a/c_src/libpg_query/test/deparse.c b/c_src/libpg_query/test/deparse.c index 31679d4f..5ffb1db3 100644 --- a/c_src/libpg_query/test/deparse.c +++ b/c_src/libpg_query/test/deparse.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -9,6 +10,7 @@ #include #include "deparse_tests.c" +#include "protobuf/pg_query.pb-c.h" void remove_numeric_key(char *parse_tree_json, char* key) { @@ -46,7 +48,7 @@ void remove_node_locations(char *parse_tree_json) remove_numeric_key(parse_tree_json, "name_location"); } -int run_test(const char *query, bool compare_query_text) { +int run_test(const char *query, bool compare_query_text, bool pretty_print) { PgQueryProtobufParseResult parse_result = pg_query_parse_protobuf(query); if (parse_result.error) { if (!compare_query_text) { // Silently fail for regression tests which can contain intentional syntax errors @@ -59,7 +61,13 @@ int run_test(const char *query, bool compare_query_text) { } PgQueryParseResult parse_result_original = pg_query_parse(query); - PgQueryDeparseResult deparse_result = pg_query_deparse_protobuf(parse_result.parse_tree); + PgQueryDeparseCommentsResult comments_result = pg_query_deparse_comments_for_query(query); + PostgresDeparseOpts deparse_opts = {0}; + deparse_opts.pretty_print = pretty_print; + deparse_opts.trailing_newline = true; + deparse_opts.comments = comments_result.comments; + deparse_opts.comment_count = comments_result.comment_count; + PgQueryDeparseResult deparse_result = pg_query_deparse_protobuf_opts(parse_result.parse_tree, deparse_opts); if (deparse_result.error) { printf("\nERROR for \"%s\"\n %s\n parsetree: %s\n", query, @@ -70,7 +78,7 @@ int run_test(const char *query, bool compare_query_text) { pg_query_free_parse_result(parse_result_original); return EXIT_FAILURE; } else if (compare_query_text && strcmp(deparse_result.query, query) != 0) { - printf("\nQUERY TEXT MISMATCH for \"%s\"\n actual: \"%s\"\n original parsetree: %s\n", + printf("\nQUERY TEXT MISMATCH - expected:\n%s\n\nactual:\n%s\n\noriginal parsetree: %s\n", query, deparse_result.query, parse_result_original.parse_tree); @@ -110,6 +118,7 @@ int run_test(const char *query, bool compare_query_text) { } } + pg_query_free_deparse_comments_result(comments_result); pg_query_free_protobuf_parse_result(parse_result); pg_query_free_parse_result(parse_result_original); pg_query_free_parse_result(parse_result_deparse); @@ -118,7 +127,7 @@ int run_test(const char *query, bool compare_query_text) { return ret_code; } -int run_tests_from_file(const char * filename) { +int run_tests_from_file(const char * filename, bool compare_query_text, bool pretty_print) { char *sample_buffer; struct stat sample_stat; int fd; @@ -170,7 +179,7 @@ int run_tests_from_file(const char * filename) { memcpy(query, sample_buffer_p + split_result.stmts[i]->stmt_location, split_result.stmts[i]->stmt_len); query[split_result.stmts[i]->stmt_len] = 0; - test_ret_code = run_test(query, false); + test_ret_code = run_test(query, compare_query_text, pretty_print); if (test_ret_code != EXIT_SUCCESS) ret_code = test_ret_code; @@ -185,6 +194,172 @@ int run_tests_from_file(const char * filename) { return ret_code; } +const char* deparseFilenames[] = +{ + "simple.sql", + "case.sql", + "nested_cte.sql", + "union.sql", + "union_2.sql", + "comment_multiline.sql", + "complex_depesz.sql", + "complex_gitlab.sql", + "complex_mattm.sql", + "ddl_alter_table_add_constraint.sql", + "ddl_create_index.sql", + "ddl_create_table.sql", + "ddl_create_trigger.sql", + "ddl_create_type.sql", + "insert_long.sql", +}; +size_t deparseFilenameCount = sizeof(deparseFilenames) / sizeof(deparseFilenames[0]); + +const char* deparseDepeszFilenames[] = +{ + "08-selects.d/01-numbers.psql", + "08-selects.d/02-string.psql", + "08-selects.d/03-sql-functions.psql", + "08-selects.d/04-functions.psql", + "08-selects.d/06-column-aliases.psql", + "08-selects.d/07-casts.psql", + "08-selects.d/08-fields-in-table.psql", + "08-selects.d/09-operators.psql", + "08-selects.d/10-operators.psql", + "08-selects.d/11-weird-operator.psql", + "08-selects.d/12-boolean-operation.psql", + "08-selects.d/13-joins.psql", + "08-selects.d/14-star.psql", + "08-selects.d/15-where.psql", + "08-selects.d/16-groupby.psql", + "08-selects.d/17-orderby.psql", + "08-selects.d/18-limitoffset.psql", + "08-selects.d/19-having.psql", + "08-selects.d/20-case.psql", + "08-selects.d/21-in.psql", // TODO + "08-selects.d/22-subselect.psql", + "08-selects.d/23-null.psql", + "08-selects.d/24-range-function.psql", + "08-selects.d/25-coalesce.psql", + "08-selects.d/26-range-subselect.psql", + "08-selects.d/27-distinct.psql", + "08-selects.d/28-distinct-on.psql", + "08-selects.d/29-param-ref.psql", + "08-selects.d/30-array.psql", + "08-selects.d/31-indirection.psql", + "08-selects.d/32-collate.psql", + "08-selects.d/33-window-functions.psql", + "08-selects.d/34-framed-functions.psql", + "08-selects.d/35-setops.psql", // TODO + "08-selects.d/36-values.psql", + "08-selects.d/37-cte.psql", + "08-selects.d/38-rcte.psql", + "08-selects.d/39-any.psql", + "08-selects.d/40-all.psql", + "08-selects.d/41-special-a-expr.psql", + "08-selects.d/42-minimax.psql", + "08-selects.d/43-rowexpr.psql", + "08-selects.d/44-bitstring.psql", + "08-selects.d/45-grouping-sets.psql", + "08-selects.d/46-cube.psql", + "08-selects.d/47-rollup.psql", + "08-selects.d/48-sublink-any-all.psql", + "08-selects.d/49-variadic-func-call.psql", + "09-inserts.d/01-basic.psql", + "09-inserts.d/02-with-columns.psql", + "09-inserts.d/03-many-columns.psql", // TODO + "09-inserts.d/04-with-schema.psql", + "09-inserts.d/05-multirow.psql", + "09-inserts.d/06-returning-all.psql", + "09-inserts.d/07-returning-some.psql", + "09-inserts.d/08-default.psql", + "09-inserts.d/09-cte.psql", + "10-updates.d/01-single-column-no-where.psql", + "10-updates.d/02-many-columns-and-where.psql", + "10-updates.d/03-with.psql", + "10-updates.d/04-returning-all.psql", + "10-updates.d/05-returning-some.psql", + "10-updates.d/06-multi-assign-simple.psql", + "10-updates.d/07-multi-assign-long.psql", + "10-updates.d/08-multi-assign-mix.psql", + "10-updates.d/09-cte.psql", + "10-updates.d/10-complex-where.psql", + "11-deletes.d/01-simple.psql", + "11-deletes.d/02-where.psql", + "11-deletes.d/03-using.psql", + "11-deletes.d/04-returning-all.psql", + "11-deletes.d/05-returning-some.psql", + "11-deletes.d/06-cte.psql", + "11-deletes.d/07-complex-where.psql", + "12-explains.d/01-base.psql", // TODO + "12-explains.d/02-analyze.psql", + "12-explains.d/03-verbose.psql", + "12-explains.d/04-analyze-verbose.psql", + "12-explains.d/05-other.psql", + "13-tablesample.d/01-system.psql", + "13-tablesample.d/02-bernoulli.psql", + "13-tablesample.d/03-repeatable.psql", + "14-xml.d/01-simple.psql", + "14-xml.d/02-concat.psql", + "14-xml.d/03-forest.psql", + "14-xml.d/04-parse.psql", + "14-xml.d/05-pi.psql", + "14-xml.d/06-root.psql", + "14-xml.d/07-serialize.psql", + "14-xml.d/08-is-document.psql", + "16-bugs.d/01-lateral.psql", + "16-bugs.d/02-current-row.psql", + "16-bugs.d/03-filtered-aggregates.psql", + "16-bugs.d/04-cast-of-expression.psql", + "16-bugs.d/05-literal-new-line.psql", + "16-bugs.d/06-aggregate-filter-inside-case.psql", + "16-bugs.d/07-missing-ordinality-and-order-by.psql", + "16-bugs.d/08-missing-dot-before-start.psql", + "16-bugs.d/09-missing-dot-before-column.psql", + "16-bugs.d/10-missing-not.psql", + "16-bugs.d/11-distinct-aggregate.psql", + "17-locking-selects.d/01-for-update.psql", + "17-locking-selects.d/02-for-no-key-update.psql", + "17-locking-selects.d/03-for-share.psql", + "17-locking-selects.d/04-for-key-share.psql", + "17-locking-selects.d/05-of-table.psql", + "17-locking-selects.d/06-of-tables.psql", + "17-locking-selects.d/07-nowait.psql", + "17-locking-selects.d/08-skip-locked.psql", + "17-locking-selects.d/09-multi.psql", + "18-conflicts.d/01-basic-nothing.psql", + "18-conflicts.d/02-constraint-nothing.psql", + "18-conflicts.d/03-columns-nothing.psql", + "18-conflicts.d/04-expr-complex.psql", + "18-conflicts.d/05-simple-update.psql", + "18-conflicts.d/06-update-multicolumn.psql", + "18-conflicts.d/07-update-complex.psql", + "19-transactions.d/01-rollback.sql", + "19-transactions.d/02-rollback_and_chain.sql", + "19-transactions.d/03-commit.sql", + "19-transactions.d/04-commit_and_chain.sql", + "19-transactions.d/05-start_transaction.sql", + "19-transactions.d/06-start_transaction_isolation_level_serializable.sql", + "19-transactions.d/07-start_transaction_isolation_level_repeatable_read.sql", + "19-transactions.d/08-start_transaction_isolation_level_read_committed.sql", + "19-transactions.d/09-start_transaction_isolation_level_read_uncommitted.sql", + "19-transactions.d/10-start_transaction_read_write.sql", + "19-transactions.d/11-start_transaction_read_only.sql", + "19-transactions.d/12-start_transaction_deferrable.sql", + "19-transactions.d/13-start_transaction_not_deferrable.sql", + "19-transactions.d/14-start_transaction_isolation_level_serializable,_deferrable.sql", + "19-transactions.d/15-begin.sql", + "19-transactions.d/16-begin_isolation_level_serializable.sql", + "19-transactions.d/17-begin_isolation_level_repeatable_read.sql", + "19-transactions.d/18-begin_isolation_level_read_committed.sql", + "19-transactions.d/19-begin_isolation_level_read_uncommitted.sql", + "19-transactions.d/20-begin_read_write.sql", + "19-transactions.d/21-begin_read_only.sql", + "19-transactions.d/22-begin_deferrable.sql", + "19-transactions.d/23-begin_not_deferrable.sql", + "19-transactions.d/24-begin_isolation_level_serializable,_deferrable.sql" +}; +size_t deparseDepeszFilenameCount = sizeof(deparseDepeszFilenames) / sizeof(deparseDepeszFilenames[0]); + const char* regressFilenames[] = { "advisory_lock.sql", "aggregates.sql", @@ -435,7 +610,29 @@ int main() { int test_ret_code; for (i = 0; i < testsLength; i += 1) { - test_ret_code = run_test(tests[i], true); + test_ret_code = run_test(tests[i], true, false); + if (test_ret_code != EXIT_SUCCESS) + ret_code = test_ret_code; + } + + for (i = 0; i < deparseFilenameCount; i += 1) { + printf("\n%s\n", deparseFilenames[i]); + char *filename = malloc(sizeof(char) * strlen("test/sql/deparse/") + strlen(deparseFilenames[i]) + 1); + strcpy(filename, "test/sql/deparse/"); + strcat(filename, deparseFilenames[i]); + test_ret_code = run_tests_from_file(filename, true, true); + free(filename); + if (test_ret_code != EXIT_SUCCESS) + ret_code = test_ret_code; + } + + for (i = 0; i < deparseDepeszFilenameCount; i += 1) { + printf("\n%s\n", deparseDepeszFilenames[i]); + char *filename = malloc(sizeof(char) * strlen("test/sql/deparse-depesz/") + strlen(deparseDepeszFilenames[i]) + 1); + strcpy(filename, "test/sql/deparse-depesz/"); + strcat(filename, deparseDepeszFilenames[i]); + test_ret_code = run_tests_from_file(filename, true, true); + free(filename); if (test_ret_code != EXIT_SUCCESS) ret_code = test_ret_code; } @@ -445,7 +642,7 @@ int main() { char *filename = malloc(sizeof(char) * strlen("test/sql/postgres_regress/") + strlen(regressFilenames[i]) + 1); strcpy(filename, "test/sql/postgres_regress/"); strcat(filename, regressFilenames[i]); - test_ret_code = run_tests_from_file(filename); + test_ret_code = run_tests_from_file(filename, false, false); free(filename); if (test_ret_code != EXIT_SUCCESS) ret_code = test_ret_code; @@ -456,7 +653,7 @@ int main() { char *filename = malloc(sizeof(char) * strlen("test/sql/postgres_regress/") + strlen(plpgsqlRegressFilenames[i]) + 1); strcpy(filename, "test/sql/plpgsql_regress/"); strcat(filename, plpgsqlRegressFilenames[i]); - test_ret_code = run_tests_from_file(filename); + test_ret_code = run_tests_from_file(filename, false, false); free(filename); if (test_ret_code != EXIT_SUCCESS) ret_code = test_ret_code; diff --git a/c_src/libpg_query/test/deparse_tests.c b/c_src/libpg_query/test/deparse_tests.c index 69cac931..25dd812c 100644 --- a/c_src/libpg_query/test/deparse_tests.c +++ b/c_src/libpg_query/test/deparse_tests.c @@ -88,7 +88,7 @@ const char* tests[] = { "SELECT * FROM crosstab('SELECT department, role, COUNT(id) FROM users GROUP BY department, role ORDER BY department, role', 'VALUES (''admin''::text), (''ordinary''::text)') ctab (department varchar, admin int, ordinary int)", "SELECT row_cols[0] AS dept, row_cols[1] AS sub, admin, ordinary FROM crosstab('SELECT ARRAY[department, sub] AS row_cols, role, COUNT(id) FROM users GROUP BY department, role ORDER BY department, role', 'VALUES (''admin''::text), (''ordinary''::text)') AS (row_cols varchar[], admin int, ordinary int)", "SELECT 1::int8", - "SELECT CAST(1 + 3 AS int8)", + "SELECT (1 + 3)::int8", "SELECT x::regclass", "SELECT table_field::bool, table_field::boolean FROM t", "SELECT true, false", @@ -320,6 +320,7 @@ const char* tests[] = { "SELECT ROW(1 + 2)", "ALTER TABLE a ALTER COLUMN b SET DEFAULT 1", "ALTER TABLE a ALTER COLUMN b DROP DEFAULT", + "ALTER TABLE a ALTER COLUMN b SET STATISTICS DEFAULT", "SELECT (3 + 3) OPERATOR(pg_catalog.*) 2", "SELECT 3 + (3 * 2)", "SELECT LIMIT ALL", @@ -414,7 +415,8 @@ const char* tests[] = { "CREATE TABLE my_table (created_at timestamptz NOT NULL DEFAULT (now() AT LOCAL))", "CREATE TABLE my_table (created_at timestamptz NOT NULL DEFAULT '1 hour'::interval + (current_timestamp AT TIME ZONE 'UTC'))", "ALTER TABLE my_table ADD COLUMN created_at timestamptz NOT NULL DEFAULT '1 hour'::interval + (current_timestamp AT TIME ZONE 'UTC')", - "CREATE TABLE my_table (created_at int NOT NULL DEFAULT 1 + 2)" + "CREATE TABLE my_table (created_at int NOT NULL DEFAULT 1 + 2)", + "/* Comment 1 */ SELECT 1; /* Comment 2 */ SELECT 2" }; size_t testsLength = __LINE__ - 4; diff --git a/c_src/libpg_query/test/framework/main.c b/c_src/libpg_query/test/framework/main.c new file mode 100644 index 00000000..a2941cca --- /dev/null +++ b/c_src/libpg_query/test/framework/main.c @@ -0,0 +1,260 @@ +#include +#include "src/pg_query_internal.h" +#include "test/framework/main.h" +#include + +/* + * ARBITRARY_LENGTH_LIMIT is purely arbitrary to avoid unbounded strcmp() usage. + * Using strcmp() means bugs an cause infinite loops, which is hard to debug. + * If it causes a problem, make the number bigger. + * -@duckinator + */ +const size_t ARBITRARY_LENGTH_LIMIT = 500; + +int +TEST_INIT_impl(TestState * test_state, const char *func, size_t line) +{ + if ((test_state->wanted_test != NULL) && (strcmp(test_state->wanted_test, func) != 0)) + return 1; + + printf("%s (line %li)\n", func, line); + return 0; +} + +int +TEST_BOUNDED_STRCMP(char *s1, char *s2) +{ + /* + * strncmp() can not handle being given NULL. so, if either are NULL, we + * test whether they're *both* NULL. + */ + if (s1 == NULL || s2 == NULL) + return (s1 == s2) ? 0 : -1; + + return strncmp(s1, s2, ARBITRARY_LENGTH_LIMIT); +} + +/* + * Assert that `actual` is NULL. + */ +void +TEST_ASSERT_NULL_impl(TestState * test_state, char *actual_str, void *actual) +{ + if (actual == NULL) + TEST_PASS(); + else + TEST_FAIL(" FAIL: expected %s to be NULL\n", actual_str); +} + +/* + * Assert that `actual` is a string containing the same text as `expected`. + * (This is wrapped by the TEST_ASSERT_STR_EQUAL macro.) + */ +void +TEST_ASSERT_STR_EQUAL_impl(TestState * test_state, char *actual_str, char *actual, char *expected) +{ + if (TEST_BOUNDED_STRCMP(actual, expected) == 0) + test_state->passed++; + else + { + printf(" FAIL: Expected `actual` (%s) and `expected` to be equivalent.\n", actual_str); + printf(" actual: %s\n", actual); + printf(" expected: %s\n\n", expected); + test_state->failed++; + } +} + +/* + * Assert that `lst` contains `expected_len` items. + * (This is wrapped by the TEST_ASSERT_LIST_LENGTH macro.) + */ +void +TEST_ASSERT_LIST_LENGTH_impl(TestState * test_state, char *lst_str, List *lst, size_t expected_len) +{ + size_t actual_len = list_length(lst); + + if (actual_len == expected_len) + { + test_state->passed++; + } + else + { + printf(" FAIL: expected %s to have length %li\n", lst_str, expected_len); + printf(" actual length is %li\n\n", actual_len); + test_state->failed++; + } +} + +/* + * Given an array of char*, and the length of the array, return a string representation. + * Please remember to free the returned pointer when you're done. + */ +static char * +str_list_to_buf(char **list, size_t list_len) +{ + size_t len = 3; + + /* leading and trailing brackets, and null terminator */ + len += 2 * list_len; + /* quotes around each item */ + len += 2 * (list_len - 1); + /* commas and spaces between items */ + + for (int i = 0; i < list_len; i++) + len += strlen(list[i]); + + char *buf = malloc(sizeof(char) * len); + size_t offset = snprintf(buf, len, "["); + + for (int i = 0; i < list_len; i++) + { + offset += snprintf(buf + offset, len - offset, "\"%s\"", list[i]); + if (i < (list_len - 1)) + offset += snprintf(buf + offset, len - offset, ", "); + } + offset += snprintf(buf + offset, len - offset, "]"); + return buf; +} + +/* + * Assert that `actual` and `expected` should contain the same items, but may be in a different order. + * (This is wrapped by the TEST_ASSERT_LIST_EQUAL macro.) + */ +void +TEST_ASSERT_LIST_EQUAL_impl(TestState * test_state, char *actual_str, List *actual, List *expected) +{ + size_t actual_len = list_length(actual); + size_t expected_len = list_length(expected); + + char **act_ary = malloc(sizeof(char *) * actual_len); + char **exp_ary = malloc(sizeof(char *) * expected_len); + + ListCell *lc = NULL; + + foreach(lc, actual) + { + size_t i = foreach_current_index(lc); + + act_ary[i] = lfirst(lc); + } + foreach(lc, expected) + { + size_t i = foreach_current_index(lc); + + exp_ary[i] = lfirst(lc); + } + + qsort(act_ary, actual_len, sizeof(char *), pg_qsort_strcmp); + qsort(exp_ary, expected_len, sizeof(char *), pg_qsort_strcmp); + + int failed = 0; + + if (actual_len != expected_len) + { + failed = 1; + } + + if (failed == 0) + { + for (size_t i = 0; i < actual_len; i++) + { + if (strcmp(act_ary[i], exp_ary[i]) != 0) + { + failed = 1; + break; + } + } + } + + if (failed) + { + test_state->failed++; + printf(" FAIL: Expected `actual` and `expected` to be equivalent.\n"); + + char *act_str = str_list_to_buf(act_ary, actual_len); + + printf(" actual: %s\n", act_str); + free(act_str); + + char *exp_str = str_list_to_buf(exp_ary, expected_len); + + printf(" expected: %s\n\n", exp_str); + free(exp_str); + } + else + test_state->passed++; + + free(act_ary); + free(exp_ary); +} + +// Given a list of tests, cleanup function, and use_mctx, +// run tests and return the results. +// +// If `use_mctx` is true, a Postgres MemoryContext is entered before the test is run, +// and exited after the cleanup function is called. +// +// This function exists so test_run() and test_run_with_mctx() can share an +// implementation. +static +int +test_run_impl(int argc, char *argv[], TestFn * tests[], TestCleanupFn * test_cleanup, bool use_mctx) +{ + TestState test_state = {0}; + + bool fail_fast = false; + + for (size_t i = 1; i < argc; i++) + { + // This loop only runs if an argument was passed. + // That argument will be -ff or a test name, and in both + // cases we want to fail fast. + fail_fast = true; + + // If the argument isn't -ff, we assume it's a test name. + if (strncmp(argv[i], "-ff", 4) != 0) { + test_state.wanted_test = argv[i]; + break; + } + } + + + pg_query_init(); + + for (size_t i = 0; tests[i] != NULL; i++) + { + MemoryContext ctx; + if (use_mctx) + ctx = pg_query_enter_memory_context(); + + tests[i] (&test_state); + if (test_cleanup != NULL) + test_cleanup(); + + if (use_mctx) + pg_query_exit_memory_context(ctx); + + if (fail_fast && test_state.failed > 0) + break; + } + + bool failed = (test_state.failed > 0); + + printf("\ntest result: %s. %li passed; %li failed; %li skipped\n", failed ? "FAILED" : "ok", test_state.passed, test_state.failed, test_state.skipped); + + pg_query_exit(); + + return failed ? EXIT_FAILURE : EXIT_SUCCESS; +} + +int +test_run(int argc, char *argv[], TestFn * tests[], TestCleanupFn * test_cleanup) +{ + return test_run_impl(argc, argv, tests, test_cleanup, false); +} + +int +test_run_with_mcxt(int argc, char *argv[], TestFn * tests[], TestCleanupFn * test_cleanup) +{ + return test_run_impl(argc, argv, tests, test_cleanup, true); +} diff --git a/c_src/libpg_query/test/framework/main.h b/c_src/libpg_query/test/framework/main.h new file mode 100644 index 00000000..94df37e9 --- /dev/null +++ b/c_src/libpg_query/test/framework/main.h @@ -0,0 +1,93 @@ +#ifndef PG_QUERY_TEST_FRAMEWORK_H +#define PG_QUERY_TEST_FRAMEWORK_H + +/* + * This is a test framework that is specialized for pg_query. + * There is some macro magic, but the API can be treated as: + * + * TEST_INIT() + * TEST_ASSERT_EQUAL_STR(char* actual, char* expected) + * TEST_ASSERT_EQUAL_LIST(List* actual, List* expected) + * TEST_ASSERT_LIST_LENGTH(List* lst, size_t len) + * TEST_PASS() + * TEST_FAIL(...) // Args are passed directly to printf. + * test_run(TestFn* tests[], TestCleanupFn* test_cleanup) + * + * Basic usage: + * + * static void it_goes_moo(TestState* test_state) { + * TEST_INIT(); + * TEST_ASSERT_EQUAL_STR(cow_noises(), "moo"); + * } + * + * void test_cleanup(void) { + * // Do any between-test cleanup here. + * } + * + * int main(int argc, char* argv[]) { + * TestFn* tests[] = {&it_goes_moo, NULL}; + * return test_run(tests, &test_cleanup); + * } + */ + + +#include +#include + +#include "postgres.h" /* Needed for `nodes/pg_list.h` to not cause + * compile errors. */ +#include "nodes/pg_list.h" /* For `List` type. */ + +typedef struct +{ + char *wanted_test; + size_t passed; + size_t failed; + size_t skipped; +} TestState; + +typedef void (TestFn) (TestState * test_state); + +typedef void (TestCleanupFn) (void); + +/* Functions defined in framework/main.c */ +int TEST_INIT_impl(TestState * test_state, const char *func, size_t line); +int TEST_BOUNDED_STRCMP(char *s1, char *s2); +void TEST_ASSERT_NULL_impl(TestState * test_state, char *actual_str, void *actual); +void TEST_ASSERT_LIST_EQUAL_impl(TestState * test_state, char *actual_str, List *actual, List *expected); +void TEST_ASSERT_LIST_LENGTH_impl(TestState * test_state, char *lst_str, List *lst, size_t expected_len); +void TEST_ASSERT_STR_EQUAL_impl(TestState * test_state, char *actual_str, char *actual, char *expected); + +/* Everything below here is the actual user-facing API. */ + +#define TEST_PASS() (test_state->passed++) +#define TEST_FAIL(...) (printf(__VA_ARGS__), test_state->failed++) +#define TEST_SKIP(...) (printf(" SKIP: " __VA_ARGS__), test_state->skipped++) + +/* Prints the name of the test and the line number. */ +#define TEST_INIT() do { if (TEST_INIT_impl(test_state, __func__, __LINE__) != 0) return; } while(0) + +/* Assert that `actual` is NULL. */ +#define TEST_ASSERT_NULL(actual) TEST_ASSERT_NULL_impl(test_state, #actual, actual) + +/* Assert that `actual` and `expected` should contain the same items, but may be in a different order. */ +#define TEST_ASSERT_LIST_EQUAL(actual, expected) TEST_ASSERT_LIST_EQUAL_impl(test_state, #actual, actual, expected) + +/* Assert that `lst` contains `len` items. */ +#define TEST_ASSERT_LIST_LENGTH(lst, len) TEST_ASSERT_LIST_LENGTH_impl(test_state, #lst, lst, len) + +/* Assert that `actual` is a string containing the same text as `expected`. */ +#define TEST_ASSERT_STR_EQUAL(actual, expected) TEST_ASSERT_STR_EQUAL_impl(test_state, #actual, actual, expected) + +/* Run each test in order, passing the same TestState object. */ +/* `test_cleanup()` is run between each test if it is not NULL. */ +/* If argc is >1, the first argument is treated as a filter for tests. */ +int test_run(int argc, char *argv[], TestFn * tests[], TestCleanupFn * test_cleanup); +int test_run_with_mcxt(int argc, char *argv[], TestFn * tests[], TestCleanupFn * test_cleanup); + +#define TEST_LIST_MAKE6(a,b,c,d,e,f) lappend(list_make5(a,b,c,d,e), f) +#define TEST_LIST_MAKE7(a,b,c,d,e,f,g) lappend(TEST_LIST_MAKE6(a,b,c,d,e,f), g) +#define TEST_LIST_MAKE8(a,b,c,d,e,f,g,h) lappend(TEST_LIST_MAKE7(a,b,c,d,e,f,g), h) +#define TEST_LIST_MAKE9(a,b,c,d,e,f,g,h,i) lappend(TEST_LIST_MAKE8(a,b,c,d,e,f,g,h), i) + +#endif diff --git a/c_src/libpg_query/test/is_utility_stmt.c b/c_src/libpg_query/test/is_utility_stmt.c new file mode 100644 index 00000000..11bf7f15 --- /dev/null +++ b/c_src/libpg_query/test/is_utility_stmt.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include + +#include "test/framework/main.h" + +struct LastResult { + bool has_result; + PgQueryIsUtilityResult result; +}; +static struct LastResult last_result = {false, {0}}; + +static PgQueryIsUtilityResult +is_utility_stmt(const char *msg) +{ + last_result.has_result = true; + last_result.result = pg_query_is_utility_stmt(msg); + + return last_result.result; +} + +void cleanup() +{ + if (!last_result.has_result) + return; + + last_result.has_result = false; + pg_query_free_is_utility_result(last_result.result); +} + +#define assert_result_equal(actual, expected_len, expected) assert_result_equal_impl(test_state, #actual, actual, expected_len, expected) +static void +assert_result_equal_impl(TestState * test_state, char *actual_str, PgQueryIsUtilityResult actual, size_t expected_len, bool expected[]) +{ + bool all_match = (actual.length == expected_len); + + for (size_t i = 0; (i < expected_len) && (i < actual.length) && all_match; i++) { + if (actual.items[i] != expected[i]) + all_match = false; + } + + if (all_match) + TEST_PASS(); + else { + TEST_FAIL("Expected `actual` to equal `expected`, where\n"); + printf(" actual: "); + for (size_t i = 0; i < actual.length; i++) + printf("%s ", actual.items[i] ? "true " : "false"); + + printf("\n expected: "); + for (size_t i = 0; i < expected_len; i++) + printf("%s ", expected[i] ? "true " : "false"); + + puts("\n"); + } +} + +static void select_test(TestState* test_state) +{ + TEST_INIT(); + + assert_result_equal(is_utility_stmt("SELECT 1"), 1, (bool[]){false}); +} + +static void insert_test(TestState* test_state) +{ + TEST_INIT(); + + assert_result_equal(is_utility_stmt("INSERT INTO my_table VALUES(123)"), 1, (bool[]){false}); +} + +static void update_test(TestState* test_state) +{ + TEST_INIT(); + assert_result_equal(is_utility_stmt("UPDATE my_table SET foo = 123"), 1, (bool[]){false}); +} + +static void delete_test(TestState* test_state) +{ + TEST_INIT(); + assert_result_equal(is_utility_stmt("DELETE FROM my_table"), 1, (bool[]){false}); +} + +static void show_test(TestState* test_state) +{ + TEST_INIT(); + assert_result_equal(is_utility_stmt("SHOW fsync"), 1, (bool[]){true}); +} + +static void set_test(TestState* test_state) +{ + TEST_INIT(); + assert_result_equal(is_utility_stmt("SET fsync = off"), 1, (bool[]){true}); +} + +static void select2_test(TestState* test_state) +{ + TEST_INIT(); + assert_result_equal(is_utility_stmt("SELECT 1; SELECT 2;"), 2, ((bool[]){false, false})); +} + +static void select_show_test(TestState* test_state) +{ + TEST_INIT(); + assert_result_equal(is_utility_stmt("SELECT 1; SHOW fsync;"), 2, ((bool[]){false, true})); +} + +int +main(int argc, char *argv[]) +{ + TestFn *tests[] = { + &select_test, + &insert_test, + &update_test, + &delete_test, + &show_test, + &set_test, + &select2_test, + &select_show_test, + NULL + }; + + return test_run(argc, argv, tests, &cleanup); +} diff --git a/c_src/libpg_query/test/normalize_tests.c b/c_src/libpg_query/test/normalize_tests.c index 8f49bb14..53d85cb3 100644 --- a/c_src/libpg_query/test/normalize_tests.c +++ b/c_src/libpg_query/test/normalize_tests.c @@ -20,6 +20,8 @@ const char* tests[] = { "select count($1), date_trunc($2, created_at at time zone $3), $4, $5 from users group by date_trunc($2, created_at at time zone $3), date_trunc($6, created_at), $4, $5", "SELECT CAST('abc' as varchar(50))", "SELECT CAST($1 as varchar(50))", + "CALL fn(1)", + "CALL fn($1)", "CREATE OR REPLACE FUNCTION pg_temp.testfunc(OUT response \"mytable\", OUT sequelize_caught_exception text) RETURNS RECORD AS $func_12345$ BEGIN INSERT INTO \"mytable\" (\"mycolumn\") VALUES ('myvalue') RETURNING * INTO response; EXCEPTION WHEN unique_violation THEN GET STACKED DIAGNOSTICS sequelize_caught_exception = PG_EXCEPTION_DETAIL; END $func_12345$ LANGUAGE plpgsql; SELECT (testfunc.response).\"mycolumn\", testfunc.sequelize_caught_exception FROM pg_temp.testfunc(); DROP FUNCTION IF EXISTS pg_temp.testfunc();", "CREATE OR REPLACE FUNCTION pg_temp.testfunc(OUT response \"mytable\", OUT sequelize_caught_exception text) RETURNS RECORD AS $1 LANGUAGE plpgsql; SELECT (testfunc.response).\"mycolumn\", testfunc.sequelize_caught_exception FROM pg_temp.testfunc(); DROP FUNCTION IF EXISTS pg_temp.testfunc();", "CREATE PROCEDURE insert_data(a integer, b integer) LANGUAGE SQL AS $$ INSERT INTO tbl VALUES (a); INSERT INTO tbl VALUES (b); $$", @@ -38,6 +40,8 @@ const char* tests[] = { "ALTER USER MAPPING FOR bob SERVER foo OPTIONS (SET password $1)", "MERGE into measurement m USING new_measurement nm ON (m.city_id = nm.city_id and m.logdate=nm.logdate) WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE WHEN MATCHED THEN UPDATE SET peaktemp = greatest(m.peaktemp, nm.peaktemp), unitsales = m.unitsales + coalesce(nm.unitsales, 0) WHEN NOT MATCHED THEN INSERT (city_id, logdate, peaktemp, unitsales) VALUES (city_id, logdate, peaktemp, unitsales)", "MERGE into measurement m USING new_measurement nm ON (m.city_id = nm.city_id and m.logdate=nm.logdate) WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE WHEN MATCHED THEN UPDATE SET peaktemp = greatest(m.peaktemp, nm.peaktemp), unitsales = m.unitsales + coalesce(nm.unitsales, $1) WHEN NOT MATCHED THEN INSERT (city_id, logdate, peaktemp, unitsales) VALUES (city_id, logdate, peaktemp, unitsales)", + "DO language E'plpgsql' 'BEGIN PERFORM 1; END'", + "DO language $1 $2", // These below are as expected, though questionable if upstream shouldn't be // fixed as this could bloat pg_stat_statements "DECLARE cursor_b CURSOR FOR SELECT * FROM x WHERE id = 123", diff --git a/c_src/libpg_query/test/normalize_utility_tests.c b/c_src/libpg_query/test/normalize_utility_tests.c index a16287a4..af562e45 100644 --- a/c_src/libpg_query/test/normalize_utility_tests.c +++ b/c_src/libpg_query/test/normalize_utility_tests.c @@ -21,6 +21,8 @@ const char* tests[] = { "select count(1), date_trunc('day', created_at at time zone 'US/Pacific'), 'something', 'somethingelse' from users group by date_trunc('day', created_at at time zone 'US/Pacific'), date_trunc('day', created_at), 'foobar', 'abcdef'", "SELECT CAST('abc' as varchar(50))", "SELECT CAST('abc' as varchar(50))", + "CALL fn(1)", + "CALL fn(1)", "CREATE OR REPLACE FUNCTION pg_temp.testfunc(OUT response \"mytable\", OUT sequelize_caught_exception text) RETURNS RECORD AS $func_12345$ BEGIN INSERT INTO \"mytable\" (\"mycolumn\") VALUES ('myvalue') RETURNING * INTO response; EXCEPTION WHEN unique_violation THEN GET STACKED DIAGNOSTICS sequelize_caught_exception = PG_EXCEPTION_DETAIL; END $func_12345$ LANGUAGE plpgsql; SELECT (testfunc.response).\"mycolumn\", testfunc.sequelize_caught_exception FROM pg_temp.testfunc(); DROP FUNCTION IF EXISTS pg_temp.testfunc();", "CREATE OR REPLACE FUNCTION pg_temp.testfunc(OUT response \"mytable\", OUT sequelize_caught_exception text) RETURNS RECORD AS $func_12345$ BEGIN INSERT INTO \"mytable\" (\"mycolumn\") VALUES ('myvalue') RETURNING * INTO response; EXCEPTION WHEN unique_violation THEN GET STACKED DIAGNOSTICS sequelize_caught_exception = PG_EXCEPTION_DETAIL; END $func_12345$ LANGUAGE plpgsql; SELECT (testfunc.response).\"mycolumn\", testfunc.sequelize_caught_exception FROM pg_temp.testfunc(); DROP FUNCTION IF EXISTS pg_temp.testfunc();", "CREATE PROCEDURE insert_data(a integer, b integer) LANGUAGE SQL AS $$ INSERT INTO tbl VALUES (a); INSERT INTO tbl VALUES (b); $$", @@ -39,6 +41,8 @@ const char* tests[] = { "ALTER USER MAPPING FOR bob SERVER foo OPTIONS (SET password $1)", "MERGE into measurement m USING new_measurement nm ON (m.city_id = nm.city_id and m.logdate=nm.logdate) WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE WHEN MATCHED THEN UPDATE SET peaktemp = greatest(m.peaktemp, nm.peaktemp), unitsales = m.unitsales + coalesce(nm.unitsales, 0) WHEN NOT MATCHED THEN INSERT (city_id, logdate, peaktemp, unitsales) VALUES (city_id, logdate, peaktemp, unitsales)", "MERGE into measurement m USING new_measurement nm ON (m.city_id = nm.city_id and m.logdate=nm.logdate) WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE WHEN MATCHED THEN UPDATE SET peaktemp = greatest(m.peaktemp, nm.peaktemp), unitsales = m.unitsales + coalesce(nm.unitsales, 0) WHEN NOT MATCHED THEN INSERT (city_id, logdate, peaktemp, unitsales) VALUES (city_id, logdate, peaktemp, unitsales)", + "DO language E'plpgsql' 'BEGIN PERFORM 1; END'", + "DO language E'plpgsql' 'BEGIN PERFORM 1; END'", // These below are as expected, though questionable if upstream shouldn't be // fixed as this could bloat pg_stat_statements "DECLARE cursor_b CURSOR FOR SELECT * FROM x WHERE id = 123", diff --git a/c_src/libpg_query/test/parse_opts_tests.c b/c_src/libpg_query/test/parse_opts_tests.c index 73bbc6ce..9ee08eda 100644 --- a/c_src/libpg_query/test/parse_opts_tests.c +++ b/c_src/libpg_query/test/parse_opts_tests.c @@ -1,40 +1,40 @@ const char* tests[] = { "SELECT 1", "0", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "integer", "1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"List\":{\"items\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"int4\"}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"List\":{\"items\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"int4\"}}]}}}]}", "character varying(32)", "1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"List\":{\"items\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"varchar\"}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"List\":{\"items\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"varchar\"}}]}}}]}", "EXISTS(SELECT 1)", "2", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"SubLink\":{\"subLinkType\":\"EXISTS_SUBLINK\",\"subselect\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":14}},\"location\":14}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"SubLink\":{\"subLinkType\":\"EXISTS_SUBLINK\",\"subselect\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":14}},\"location\":14}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "v_version IS NULL", "2", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"NullTest\":{\"arg\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"v_version\"}}]}},\"nulltesttype\":\"IS_NULL\",\"location\":10}}}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"NullTest\":{\"arg\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"v_version\"}}]}},\"nulltesttype\":\"IS_NULL\",\"location\":10}}}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "pos:= instr($1, $2, 1)", "3", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"pos\",\"nnames\":1,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"instr\"}}],\"args\":[{\"ParamRef\":{\"number\":1,\"location\":12}},{\"ParamRef\":{\"number\":2,\"location\":16}},{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":20}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":6}},\"location\":6}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"pos\",\"nnames\":1,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"instr\"}}],\"args\":[{\"ParamRef\":{\"number\":1,\"location\":12}},{\"ParamRef\":{\"number\":2,\"location\":16}},{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":20}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":6}},\"location\":6}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", "temp_str := substring(string FROM beg_index)", "3", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"temp_str\",\"nnames\":1,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"substring\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"string\"}}],\"location\":22}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"beg_index\"}}],\"location\":34}}],\"funcformat\":\"COERCE_SQL_SYNTAX\",\"location\":12}},\"location\":12}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"temp_str\",\"nnames\":1,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"substring\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"string\"}}],\"location\":22}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"beg_index\"}}],\"location\":34}}],\"funcformat\":\"COERCE_SQL_SYNTAX\",\"location\":12}},\"location\":12}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", "v3.c1 := 4", "4", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"v3\",\"indirection\":[{\"String\":{\"sval\":\"c1\"}}],\"nnames\":2,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":4},\"location\":9}},\"location\":9}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"v3\",\"indirection\":[{\"String\":{\"sval\":\"c1\"}}],\"nnames\":2,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":4},\"location\":9}},\"location\":9}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", "NEW.name = upper(cleanString(NEW.name))", "4", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"new\",\"indirection\":[{\"String\":{\"sval\":\"name\"}}],\"nnames\":2,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"upper\"}}],\"args\":[{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"cleanstring\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"new\"}},{\"String\":{\"sval\":\"name\"}}],\"location\":29}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":17}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":11}},\"location\":11}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"new\",\"indirection\":[{\"String\":{\"sval\":\"name\"}}],\"nnames\":2,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"upper\"}}],\"args\":[{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"cleanstring\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"new\"}},{\"String\":{\"sval\":\"name\"}}],\"location\":29}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":17}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":11}},\"location\":11}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", "NEW.author.first_name = upper(cleanString(NEW.author.first_name))", "5", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"new\",\"indirection\":[{\"String\":{\"sval\":\"author\"}},{\"String\":{\"sval\":\"first_name\"}}],\"nnames\":3,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"upper\"}}],\"args\":[{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"cleanstring\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"new\"}},{\"String\":{\"sval\":\"author\"}},{\"String\":{\"sval\":\"first_name\"}}],\"location\":42}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":30}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":24}},\"location\":24}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"new\",\"indirection\":[{\"String\":{\"sval\":\"author\"}},{\"String\":{\"sval\":\"first_name\"}}],\"nnames\":3,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"upper\"}}],\"args\":[{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"cleanstring\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"new\"}},{\"String\":{\"sval\":\"author\"}},{\"String\":{\"sval\":\"first_name\"}}],\"location\":42}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":30}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":24}},\"location\":24}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", "SELECT '\\''", "96", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"sval\":{\"sval\":\"'\"},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"sval\":{\"sval\":\"'\"},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "v3.c1 := '\\''", "100", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"v3\",\"indirection\":[{\"String\":{\"sval\":\"c1\"}}],\"nnames\":2,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"sval\":{\"sval\":\"'\"},\"location\":9}},\"location\":9}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"PLAssignStmt\":{\"name\":\"v3\",\"indirection\":[{\"String\":{\"sval\":\"c1\"}}],\"nnames\":2,\"val\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"sval\":{\"sval\":\"'\"},\"location\":9}},\"location\":9}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}}]}", }; size_t testsLength = __LINE__ - 4; diff --git a/c_src/libpg_query/test/parse_tests.c b/c_src/libpg_query/test/parse_tests.c index e977d714..82d36d27 100644 --- a/c_src/libpg_query/test/parse_tests.c +++ b/c_src/libpg_query/test/parse_tests.c @@ -1,76 +1,76 @@ const char* tests[] = { "SELECT FALSE", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"boolval\":{},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"boolval\":{},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT NULL", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"isnull\":true,\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"isnull\":true,\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT 0", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT 1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT -1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":-1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":-1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT 1; SELECT 2", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"stmt_len\":8},{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":2},\"location\":17}},\"location\":17}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"stmt_location\":9}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"stmt_len\":8},{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Const\":{\"ival\":{\"ival\":2},\"location\":17}},\"location\":17}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"stmt_location\":9}]}", "select sum(unique1) FILTER (WHERE unique1 IN (SELECT unique1 FROM onek where unique1 < 100)) FROM tenk1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"sum\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":11}}],\"agg_filter\":{\"SubLink\":{\"subLinkType\":\"ANY_SUBLINK\",\"testexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":34}},\"subselect\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":53}},\"location\":53}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"onek\",\"inh\":true,\"relpersistence\":\"p\",\"location\":66}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"\\u003c\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":77}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":100},\"location\":87}},\"location\":85}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":42}},\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"tenk1\",\"inh\":true,\"relpersistence\":\"p\",\"location\":98}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"sum\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":11}}],\"agg_filter\":{\"SubLink\":{\"subLinkType\":\"ANY_SUBLINK\",\"testexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":34}},\"subselect\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":53}},\"location\":53}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"onek\",\"inh\":true,\"relpersistence\":\"p\",\"location\":66}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"\\u003c\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":77}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":100},\"location\":87}},\"location\":85}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":42}},\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"tenk1\",\"inh\":true,\"relpersistence\":\"p\",\"location\":98}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "select sum(unique1) FILTER (WHERE unique1 = ANY (SELECT unique1 FROM onek where unique1 < 100)) FROM tenk1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"sum\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":11}}],\"agg_filter\":{\"SubLink\":{\"subLinkType\":\"ANY_SUBLINK\",\"testexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":34}},\"operName\":[{\"String\":{\"sval\":\"=\"}}],\"subselect\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":56}},\"location\":56}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"onek\",\"inh\":true,\"relpersistence\":\"p\",\"location\":69}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"\\u003c\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":80}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":100},\"location\":90}},\"location\":88}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":42}},\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"tenk1\",\"inh\":true,\"relpersistence\":\"p\",\"location\":101}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"sum\"}}],\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":11}}],\"agg_filter\":{\"SubLink\":{\"subLinkType\":\"ANY_SUBLINK\",\"testexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":34}},\"operName\":[{\"String\":{\"sval\":\"=\"}}],\"subselect\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":56}},\"location\":56}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"onek\",\"inh\":true,\"relpersistence\":\"p\",\"location\":69}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"\\u003c\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unique1\"}}],\"location\":80}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":100},\"location\":90}},\"location\":88}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":42}},\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"tenk1\",\"inh\":true,\"relpersistence\":\"p\",\"location\":101}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "CREATE FOREIGN TABLE films (code char(5) NOT NULL, title varchar(40) NOT NULL, did integer NOT NULL, date_prod date, kind varchar(10), len interval hour to minute) SERVER film_server;", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"CreateForeignTableStmt\":{\"base\":{\"relation\":{\"relname\":\"films\",\"inh\":true,\"relpersistence\":\"p\",\"location\":21},\"tableElts\":[{\"ColumnDef\":{\"colname\":\"code\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"bpchar\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":5},\"location\":38}}],\"typemod\":-1,\"location\":33},\"is_local\":true,\"constraints\":[{\"Constraint\":{\"contype\":\"CONSTR_NOTNULL\",\"location\":41}}],\"location\":28}},{\"ColumnDef\":{\"colname\":\"title\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"varchar\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":40},\"location\":65}}],\"typemod\":-1,\"location\":57},\"is_local\":true,\"constraints\":[{\"Constraint\":{\"contype\":\"CONSTR_NOTNULL\",\"location\":69}}],\"location\":51}},{\"ColumnDef\":{\"colname\":\"did\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"int4\"}}],\"typemod\":-1,\"location\":83},\"is_local\":true,\"constraints\":[{\"Constraint\":{\"contype\":\"CONSTR_NOTNULL\",\"location\":91}}],\"location\":79}},{\"ColumnDef\":{\"colname\":\"date_prod\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"date\"}}],\"typemod\":-1,\"location\":111},\"is_local\":true,\"location\":101}},{\"ColumnDef\":{\"colname\":\"kind\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"varchar\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":10},\"location\":130}}],\"typemod\":-1,\"location\":122},\"is_local\":true,\"location\":117}},{\"ColumnDef\":{\"colname\":\"len\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":3072},\"location\":148}}],\"typemod\":-1,\"location\":139},\"is_local\":true,\"location\":135}}],\"oncommit\":\"ONCOMMIT_NOOP\"},\"servername\":\"film_server\"}},\"stmt_len\":182}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"CreateForeignTableStmt\":{\"base\":{\"relation\":{\"relname\":\"films\",\"inh\":true,\"relpersistence\":\"p\",\"location\":21},\"tableElts\":[{\"ColumnDef\":{\"colname\":\"code\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"bpchar\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":5},\"location\":38}}],\"typemod\":-1,\"location\":33},\"is_local\":true,\"constraints\":[{\"Constraint\":{\"contype\":\"CONSTR_NOTNULL\",\"location\":41}}],\"location\":28}},{\"ColumnDef\":{\"colname\":\"title\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"varchar\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":40},\"location\":65}}],\"typemod\":-1,\"location\":57},\"is_local\":true,\"constraints\":[{\"Constraint\":{\"contype\":\"CONSTR_NOTNULL\",\"location\":69}}],\"location\":51}},{\"ColumnDef\":{\"colname\":\"did\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"int4\"}}],\"typemod\":-1,\"location\":83},\"is_local\":true,\"constraints\":[{\"Constraint\":{\"contype\":\"CONSTR_NOTNULL\",\"location\":91}}],\"location\":79}},{\"ColumnDef\":{\"colname\":\"date_prod\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"date\"}}],\"typemod\":-1,\"location\":111},\"is_local\":true,\"location\":101}},{\"ColumnDef\":{\"colname\":\"kind\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"varchar\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":10},\"location\":130}}],\"typemod\":-1,\"location\":122},\"is_local\":true,\"location\":117}},{\"ColumnDef\":{\"colname\":\"len\",\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":3072},\"location\":148}}],\"typemod\":-1,\"location\":139},\"is_local\":true,\"location\":135}}],\"oncommit\":\"ONCOMMIT_NOOP\"},\"servername\":\"film_server\"}},\"stmt_len\":182}]}", "CREATE FOREIGN TABLE ft1 () SERVER no_server", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"CreateForeignTableStmt\":{\"base\":{\"relation\":{\"relname\":\"ft1\",\"inh\":true,\"relpersistence\":\"p\",\"location\":21},\"oncommit\":\"ONCOMMIT_NOOP\"},\"servername\":\"no_server\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"CreateForeignTableStmt\":{\"base\":{\"relation\":{\"relname\":\"ft1\",\"inh\":true,\"relpersistence\":\"p\",\"location\":21},\"oncommit\":\"ONCOMMIT_NOOP\"},\"servername\":\"no_server\"}}}]}", "SELECT parse_ident(E'\"c\".X XXXX\002XXXXXX')", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"parse_ident\"}}],\"args\":[{\"A_Const\":{\"sval\":{\"sval\":\"\\\"c\\\".X XXXX\\u0002XXXXXX\"},\"location\":19}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"parse_ident\"}}],\"args\":[{\"A_Const\":{\"sval\":{\"sval\":\"\\\"c\\\".X XXXX\\u0002XXXXXX\"},\"location\":19}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "ALTER ROLE postgres LOGIN SUPERUSER PASSWORD 'xyz'", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"AlterRoleStmt\":{\"role\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"postgres\",\"location\":11},\"options\":[{\"DefElem\":{\"defname\":\"canlogin\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":20}},{\"DefElem\":{\"defname\":\"superuser\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":26}},{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"String\":{\"sval\":\"xyz\"}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":36}}],\"action\":1}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"AlterRoleStmt\":{\"role\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"postgres\",\"location\":11},\"options\":[{\"DefElem\":{\"defname\":\"canlogin\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":20}},{\"DefElem\":{\"defname\":\"superuser\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":26}},{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"String\":{\"sval\":\"xyz\"}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":36}}],\"action\":1}}}]}", "SELECT extract($1 FROM $2)", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"extract\"}}],\"args\":[{\"ParamRef\":{\"number\":1,\"location\":15}},{\"ParamRef\":{\"number\":2,\"location\":23}}],\"funcformat\":\"COERCE_SQL_SYNTAX\",\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"extract\"}}],\"args\":[{\"ParamRef\":{\"number\":1,\"location\":15}},{\"ParamRef\":{\"number\":2,\"location\":23}}],\"funcformat\":\"COERCE_SQL_SYNTAX\",\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "WITH w AS NOT MATERIALIZED (SELECT * FROM big_table) SELECT * FROM w LIMIT 1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":60}},\"location\":60}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"w\",\"inh\":true,\"relpersistence\":\"p\",\"location\":67}}],\"limitCount\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":75}},\"limitOption\":\"LIMIT_OPTION_COUNT\",\"withClause\":{\"ctes\":[{\"CommonTableExpr\":{\"ctename\":\"w\",\"ctematerialized\":\"CTEMaterializeNever\",\"ctequery\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":35}},\"location\":35}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"big_table\",\"inh\":true,\"relpersistence\":\"p\",\"location\":42}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":5}}]},\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":60}},\"location\":60}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"w\",\"inh\":true,\"relpersistence\":\"p\",\"location\":67}}],\"limitCount\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":75}},\"limitOption\":\"LIMIT_OPTION_COUNT\",\"withClause\":{\"ctes\":[{\"CommonTableExpr\":{\"ctename\":\"w\",\"ctematerialized\":\"CTEMaterializeNever\",\"ctequery\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":35}},\"location\":35}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"big_table\",\"inh\":true,\"relpersistence\":\"p\",\"location\":42}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":5}}]},\"op\":\"SETOP_NONE\"}}}]}", "CREATE USER test PASSWORD $1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"CreateRoleStmt\":{\"stmt_type\":\"ROLESTMT_USER\",\"role\":\"test\",\"options\":[{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"ParamRef\":{\"number\":1,\"location\":26}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":17}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"CreateRoleStmt\":{\"stmt_type\":\"ROLESTMT_USER\",\"role\":\"test\",\"options\":[{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"ParamRef\":{\"number\":1,\"location\":26}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":17}}]}}}]}", "ALTER USER test ENCRYPTED PASSWORD $2", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"AlterRoleStmt\":{\"role\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"test\",\"location\":11},\"options\":[{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"ParamRef\":{\"number\":2,\"location\":35}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":16}}],\"action\":1}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"AlterRoleStmt\":{\"role\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"test\",\"location\":11},\"options\":[{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"ParamRef\":{\"number\":2,\"location\":35}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":16}}],\"action\":1}}}]}", "SET SCHEMA $3", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"search_path\",\"args\":[{\"ParamRef\":{\"number\":3,\"location\":11}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"search_path\",\"args\":[{\"ParamRef\":{\"number\":3,\"location\":11}}]}}}]}", "SET ROLE $4", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"role\",\"args\":[{\"ParamRef\":{\"number\":4,\"location\":9}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"role\",\"args\":[{\"ParamRef\":{\"number\":4,\"location\":9}}]}}}]}", "SET SESSION AUTHORIZATION $5", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"session_authorization\",\"args\":[{\"ParamRef\":{\"number\":5,\"location\":26}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"session_authorization\",\"args\":[{\"ParamRef\":{\"number\":5,\"location\":26}}]}}}]}", "SELECT EXTRACT($1 FROM TIMESTAMP $2)", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"extract\"}}],\"args\":[{\"ParamRef\":{\"number\":1,\"location\":15}},{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":2,\"location\":33}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"timestamp\"}}],\"typemod\":-1,\"location\":23},\"location\":-1}}],\"funcformat\":\"COERCE_SQL_SYNTAX\",\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"extract\"}}],\"args\":[{\"ParamRef\":{\"number\":1,\"location\":15}},{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":2,\"location\":33}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"timestamp\"}}],\"typemod\":-1,\"location\":23},\"location\":-1}}],\"funcformat\":\"COERCE_SQL_SYNTAX\",\"location\":7}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT DATE $1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":12}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"date\"}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":12}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"date\"}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT INTERVAL $1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":16}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":16}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT INTERVAL $1 YEAR", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":16}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":4},\"location\":19}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":16}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":4},\"location\":19}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT INTERVAL (6) $1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":20}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":32767},\"location\":-1}},{\"A_Const\":{\"ival\":{\"ival\":6},\"location\":17}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"TypeCast\":{\"arg\":{\"ParamRef\":{\"number\":1,\"location\":20}},\"typeName\":{\"names\":[{\"String\":{\"sval\":\"pg_catalog\"}},{\"String\":{\"sval\":\"interval\"}}],\"typmods\":[{\"A_Const\":{\"ival\":{\"ival\":32767},\"location\":-1}},{\"A_Const\":{\"ival\":{\"ival\":6},\"location\":17}}],\"typemod\":-1,\"location\":7},\"location\":-1}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SET search_path = $1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"search_path\",\"args\":[{\"ParamRef\":{\"number\":1,\"location\":18}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"VariableSetStmt\":{\"kind\":\"VAR_SET_VALUE\",\"name\":\"search_path\",\"args\":[{\"ParamRef\":{\"number\":1,\"location\":18}}]}}}]}", "ALTER ROLE postgres LOGIN SUPERUSER PASSWORD $1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"AlterRoleStmt\":{\"role\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"postgres\",\"location\":11},\"options\":[{\"DefElem\":{\"defname\":\"canlogin\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":20}},{\"DefElem\":{\"defname\":\"superuser\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":26}},{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"ParamRef\":{\"number\":1,\"location\":45}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":36}}],\"action\":1}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"AlterRoleStmt\":{\"role\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"postgres\",\"location\":11},\"options\":[{\"DefElem\":{\"defname\":\"canlogin\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":20}},{\"DefElem\":{\"defname\":\"superuser\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":26}},{\"DefElem\":{\"defname\":\"password\",\"arg\":{\"ParamRef\":{\"number\":1,\"location\":45}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":36}}],\"action\":1}}}]}", "WITH a AS (SELECT * FROM x WHERE x.y = $1 AND x.z = 1) SELECT * FROM a WHERE b = 5", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":62}},\"location\":62}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"a\",\"inh\":true,\"relpersistence\":\"p\",\"location\":69}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"b\"}}],\"location\":77}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":5},\"location\":81}},\"location\":79}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"withClause\":{\"ctes\":[{\"CommonTableExpr\":{\"ctename\":\"a\",\"ctematerialized\":\"CTEMaterializeDefault\",\"ctequery\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":18}},\"location\":18}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"x\",\"inh\":true,\"relpersistence\":\"p\",\"location\":25}}],\"whereClause\":{\"BoolExpr\":{\"boolop\":\"AND_EXPR\",\"args\":[{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"x\"}},{\"String\":{\"sval\":\"y\"}}],\"location\":33}},\"rexpr\":{\"ParamRef\":{\"number\":1,\"location\":39}},\"location\":37}},{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"x\"}},{\"String\":{\"sval\":\"z\"}}],\"location\":46}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":52}},\"location\":50}}],\"location\":42}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":5}}]},\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":62}},\"location\":62}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"a\",\"inh\":true,\"relpersistence\":\"p\",\"location\":69}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"b\"}}],\"location\":77}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":5},\"location\":81}},\"location\":79}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"withClause\":{\"ctes\":[{\"CommonTableExpr\":{\"ctename\":\"a\",\"ctematerialized\":\"CTEMaterializeDefault\",\"ctequery\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":18}},\"location\":18}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"x\",\"inh\":true,\"relpersistence\":\"p\",\"location\":25}}],\"whereClause\":{\"BoolExpr\":{\"boolop\":\"AND_EXPR\",\"args\":[{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"x\"}},{\"String\":{\"sval\":\"y\"}}],\"location\":33}},\"rexpr\":{\"ParamRef\":{\"number\":1,\"location\":39}},\"location\":37}},{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"x\"}},{\"String\":{\"sval\":\"z\"}}],\"location\":46}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":52}},\"location\":50}}],\"location\":42}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}},\"location\":5}}]},\"op\":\"SETOP_NONE\"}}}]}", "SELECT count(*) from testjsonb WHERE j->'array' ? 'bar'", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"count\"}}],\"agg_star\":true,\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"testjsonb\",\"inh\":true,\"relpersistence\":\"p\",\"location\":21}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"?\"}}],\"lexpr\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"-\\u003e\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"j\"}}],\"location\":38}},\"rexpr\":{\"A_Const\":{\"sval\":{\"sval\":\"array\"},\"location\":41}},\"location\":39}},\"rexpr\":{\"A_Const\":{\"sval\":{\"sval\":\"bar\"},\"location\":51}},\"location\":49}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"count\"}}],\"agg_star\":true,\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"testjsonb\",\"inh\":true,\"relpersistence\":\"p\",\"location\":21}}],\"whereClause\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"?\"}}],\"lexpr\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"-\\u003e\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"j\"}}],\"location\":38}},\"rexpr\":{\"A_Const\":{\"sval\":{\"sval\":\"array\"},\"location\":41}},\"location\":39}},\"rexpr\":{\"A_Const\":{\"sval\":{\"sval\":\"bar\"},\"location\":51}},\"location\":49}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT DISTINCT a FROM b", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"distinctClause\":[{}],\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"a\"}}],\"location\":16}},\"location\":16}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"b\",\"inh\":true,\"relpersistence\":\"p\",\"location\":23}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"distinctClause\":[{}],\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"a\"}}],\"location\":16}},\"location\":16}}],\"fromClause\":[{\"RangeVar\":{\"relname\":\"b\",\"inh\":true,\"relpersistence\":\"p\",\"location\":23}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT * FROM generate_series(1, 2)", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeFunction\":{\"functions\":[{\"List\":{\"items\":[{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"generate_series\"}}],\"args\":[{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":30}},{\"A_Const\":{\"ival\":{\"ival\":2},\"location\":33}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":14}},{}]}}]}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"ColumnRef\":{\"fields\":[{\"A_Star\":{}}],\"location\":7}},\"location\":7}}],\"fromClause\":[{\"RangeFunction\":{\"functions\":[{\"List\":{\"items\":[{\"FuncCall\":{\"funcname\":[{\"String\":{\"sval\":\"generate_series\"}}],\"args\":[{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":30}},{\"A_Const\":{\"ival\":{\"ival\":2},\"location\":33}}],\"funcformat\":\"COERCE_EXPLICIT_CALL\",\"location\":14}},{}]}}]}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "SELECT 1 + 1", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"+\"}}],\"lexpr\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":11}},\"location\":9}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"val\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"+\"}}],\"lexpr\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":7}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":1},\"location\":11}},\"location\":9}},\"location\":7}}],\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", "COPY vistest FROM stdin FREEZE CSV", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"CopyStmt\":{\"relation\":{\"relname\":\"vistest\",\"inh\":true,\"relpersistence\":\"p\",\"location\":5},\"is_from\":true,\"options\":[{\"DefElem\":{\"defname\":\"freeze\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":24}},{\"DefElem\":{\"defname\":\"format\",\"arg\":{\"String\":{\"sval\":\"csv\"}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":31}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"CopyStmt\":{\"relation\":{\"relname\":\"vistest\",\"inh\":true,\"relpersistence\":\"p\",\"location\":5},\"is_from\":true,\"options\":[{\"DefElem\":{\"defname\":\"freeze\",\"arg\":{\"Boolean\":{\"boolval\":true}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":24}},{\"DefElem\":{\"defname\":\"format\",\"arg\":{\"String\":{\"sval\":\"csv\"}},\"defaction\":\"DEFELEM_UNSPEC\",\"location\":31}}]}}}]}", "MERGE into measurement m USING new_measurement nm ON (m.city_id = nm.city_id and m.logdate=nm.logdate) WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE WHEN MATCHED THEN UPDATE SET peaktemp = greatest(m.peaktemp, nm.peaktemp), unitsales = m.unitsales + coalesce(nm.unitsales, 0) WHEN NOT MATCHED THEN INSERT (city_id, logdate, peaktemp, unitsales) VALUES (city_id, logdate, peaktemp, unitsales)", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"MergeStmt\":{\"relation\":{\"relname\":\"measurement\",\"inh\":true,\"relpersistence\":\"p\",\"alias\":{\"aliasname\":\"m\"},\"location\":11},\"sourceRelation\":{\"RangeVar\":{\"relname\":\"new_measurement\",\"inh\":true,\"relpersistence\":\"p\",\"alias\":{\"aliasname\":\"nm\"},\"location\":31}},\"joinCondition\":{\"BoolExpr\":{\"boolop\":\"AND_EXPR\",\"args\":[{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"city_id\"}}],\"location\":54}},\"rexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"city_id\"}}],\"location\":66}},\"location\":64}},{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"logdate\"}}],\"location\":81}},\"rexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"logdate\"}}],\"location\":91}},\"location\":90}}],\"location\":77}},\"mergeWhenClauses\":[{\"MergeWhenClause\":{\"matchKind\":\"MERGE_WHEN_MATCHED\",\"commandType\":\"CMD_DELETE\",\"override\":\"OVERRIDING_NOT_SET\",\"condition\":{\"NullTest\":{\"arg\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":120}},\"nulltesttype\":\"IS_NULL\",\"location\":132}}}},{\"MergeWhenClause\":{\"matchKind\":\"MERGE_WHEN_MATCHED\",\"commandType\":\"CMD_UPDATE\",\"override\":\"OVERRIDING_NOT_SET\",\"targetList\":[{\"ResTarget\":{\"name\":\"peaktemp\",\"val\":{\"MinMaxExpr\":{\"op\":\"IS_GREATEST\",\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":201}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":213}}],\"location\":192}},\"location\":181}},{\"ResTarget\":{\"name\":\"unitsales\",\"val\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"+\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"unitsales\"}}],\"location\":239}},\"rexpr\":{\"CoalesceExpr\":{\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"unitsales\"}}],\"location\":262}},{\"A_Const\":{\"ival\":{},\"location\":276}}],\"location\":253}},\"location\":251}},\"location\":227}}]}},{\"MergeWhenClause\":{\"matchKind\":\"MERGE_WHEN_NOT_MATCHED_BY_TARGET\",\"commandType\":\"CMD_INSERT\",\"override\":\"OVERRIDING_NOT_SET\",\"targetList\":[{\"ResTarget\":{\"name\":\"city_id\",\"location\":309}},{\"ResTarget\":{\"name\":\"logdate\",\"location\":318}},{\"ResTarget\":{\"name\":\"peaktemp\",\"location\":327}},{\"ResTarget\":{\"name\":\"unitsales\",\"location\":337}}],\"values\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"city_id\"}}],\"location\":356}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"logdate\"}}],\"location\":365}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":374}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unitsales\"}}],\"location\":384}}]}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"MergeStmt\":{\"relation\":{\"relname\":\"measurement\",\"inh\":true,\"relpersistence\":\"p\",\"alias\":{\"aliasname\":\"m\"},\"location\":11},\"sourceRelation\":{\"RangeVar\":{\"relname\":\"new_measurement\",\"inh\":true,\"relpersistence\":\"p\",\"alias\":{\"aliasname\":\"nm\"},\"location\":31}},\"joinCondition\":{\"BoolExpr\":{\"boolop\":\"AND_EXPR\",\"args\":[{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"city_id\"}}],\"location\":54}},\"rexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"city_id\"}}],\"location\":66}},\"location\":64}},{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"logdate\"}}],\"location\":81}},\"rexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"logdate\"}}],\"location\":91}},\"location\":90}}],\"location\":77}},\"mergeWhenClauses\":[{\"MergeWhenClause\":{\"matchKind\":\"MERGE_WHEN_MATCHED\",\"commandType\":\"CMD_DELETE\",\"override\":\"OVERRIDING_NOT_SET\",\"condition\":{\"NullTest\":{\"arg\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":120}},\"nulltesttype\":\"IS_NULL\",\"location\":132}}}},{\"MergeWhenClause\":{\"matchKind\":\"MERGE_WHEN_MATCHED\",\"commandType\":\"CMD_UPDATE\",\"override\":\"OVERRIDING_NOT_SET\",\"targetList\":[{\"ResTarget\":{\"name\":\"peaktemp\",\"val\":{\"MinMaxExpr\":{\"op\":\"IS_GREATEST\",\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":201}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":213}}],\"location\":192}},\"location\":181}},{\"ResTarget\":{\"name\":\"unitsales\",\"val\":{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"+\"}}],\"lexpr\":{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"m\"}},{\"String\":{\"sval\":\"unitsales\"}}],\"location\":239}},\"rexpr\":{\"CoalesceExpr\":{\"args\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"nm\"}},{\"String\":{\"sval\":\"unitsales\"}}],\"location\":262}},{\"A_Const\":{\"ival\":{},\"location\":276}}],\"location\":253}},\"location\":251}},\"location\":227}}]}},{\"MergeWhenClause\":{\"matchKind\":\"MERGE_WHEN_NOT_MATCHED_BY_TARGET\",\"commandType\":\"CMD_INSERT\",\"override\":\"OVERRIDING_NOT_SET\",\"targetList\":[{\"ResTarget\":{\"name\":\"city_id\",\"location\":309}},{\"ResTarget\":{\"name\":\"logdate\",\"location\":318}},{\"ResTarget\":{\"name\":\"peaktemp\",\"location\":327}},{\"ResTarget\":{\"name\":\"unitsales\",\"location\":337}}],\"values\":[{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"city_id\"}}],\"location\":356}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"logdate\"}}],\"location\":365}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"peaktemp\"}}],\"location\":374}},{\"ColumnRef\":{\"fields\":[{\"String\":{\"sval\":\"unitsales\"}}],\"location\":384}}]}}]}}}]}", "ALTER TABLE ALL IN TABLESPACE foo OWNED BY bar, quux SET TABLESPACE fred NOWAIT", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"AlterTableMoveAllStmt\":{\"orig_tablespacename\":\"foo\",\"objtype\":\"OBJECT_TABLE\",\"roles\":[{\"RoleSpec\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"bar\",\"location\":43}},{\"RoleSpec\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"quux\",\"location\":48}}],\"new_tablespacename\":\"fred\",\"nowait\":true}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"AlterTableMoveAllStmt\":{\"orig_tablespacename\":\"foo\",\"objtype\":\"OBJECT_TABLE\",\"roles\":[{\"RoleSpec\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"bar\",\"location\":43}},{\"RoleSpec\":{\"roletype\":\"ROLESPEC_CSTRING\",\"rolename\":\"quux\",\"location\":48}}],\"new_tablespacename\":\"fred\",\"nowait\":true}}}]}", "CREATE PUBLICATION foo FOR TABLES IN SCHEMA bar", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"CreatePublicationStmt\":{\"pubname\":\"foo\",\"pubobjects\":[{\"PublicationObjSpec\":{\"pubobjtype\":\"PUBLICATIONOBJ_TABLES_IN_SCHEMA\",\"name\":\"bar\",\"location\":44}}]}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"CreatePublicationStmt\":{\"pubname\":\"foo\",\"pubobjects\":[{\"PublicationObjSpec\":{\"pubobjtype\":\"PUBLICATIONOBJ_TABLES_IN_SCHEMA\",\"name\":\"bar\",\"location\":44}}]}}}]}", "SELECT 123 AS abc where 456=$1OR 10=11", - "{\"version\":170004,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"name\":\"abc\",\"val\":{\"A_Const\":{\"ival\":{\"ival\":123},\"location\":7}},\"location\":7}}],\"whereClause\":{\"BoolExpr\":{\"boolop\":\"OR_EXPR\",\"args\":[{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"A_Const\":{\"ival\":{\"ival\":456},\"location\":24}},\"rexpr\":{\"ParamRef\":{\"number\":1,\"location\":28}},\"location\":27}},{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"A_Const\":{\"ival\":{\"ival\":10},\"location\":33}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":11},\"location\":36}},\"location\":35}}],\"location\":30}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", + "{\"version\":170007,\"stmts\":[{\"stmt\":{\"SelectStmt\":{\"targetList\":[{\"ResTarget\":{\"name\":\"abc\",\"val\":{\"A_Const\":{\"ival\":{\"ival\":123},\"location\":7}},\"location\":7}}],\"whereClause\":{\"BoolExpr\":{\"boolop\":\"OR_EXPR\",\"args\":[{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"A_Const\":{\"ival\":{\"ival\":456},\"location\":24}},\"rexpr\":{\"ParamRef\":{\"number\":1,\"location\":28}},\"location\":27}},{\"A_Expr\":{\"kind\":\"AEXPR_OP\",\"name\":[{\"String\":{\"sval\":\"=\"}}],\"lexpr\":{\"A_Const\":{\"ival\":{\"ival\":10},\"location\":33}},\"rexpr\":{\"A_Const\":{\"ival\":{\"ival\":11},\"location\":36}},\"location\":35}}],\"location\":30}},\"limitOption\":\"LIMIT_OPTION_DEFAULT\",\"op\":\"SETOP_NONE\"}}}]}", }; size_t testsLength = __LINE__ - 4; diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/01-numbers.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/01-numbers.psql new file mode 100644 index 00000000..1a99b319 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/01-numbers.psql @@ -0,0 +1 @@ +SELECT 1, 1.5, 0, 0.0 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/02-string.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/02-string.psql new file mode 100644 index 00000000..80a372e1 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/02-string.psql @@ -0,0 +1 @@ +SELECT 'abc', 'a''bc' diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/03-sql-functions.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/03-sql-functions.psql new file mode 100644 index 00000000..98777c4c --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/03-sql-functions.psql @@ -0,0 +1,6 @@ +SELECT + current_catalog, current_role, current_schema, current_user, session_user, + user, current_date, current_time, current_timestamp, localtime, + localtimestamp, current_time(0), current_timestamp(0), localtime(0), + localtimestamp(0), current_time(2), current_timestamp(2), localtime(2), + localtimestamp(2) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/04-functions.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/04-functions.psql new file mode 100644 index 00000000..2c0edd51 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/04-functions.psql @@ -0,0 +1,6 @@ +SELECT + now(), upper('abc'), larger('abcd', 'efghijklmnop'), + single('012345678901234567890123456789'), + single_long('01234567890123456789012345678901234567890123456789'), + nested(12, 13, other_function('fsajkh', 56, 67)), named_1(1, 2, a := 'b'), + named_2(b := '2', a := 'b', c := NULL) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/06-column-aliases.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/06-column-aliases.psql new file mode 100644 index 00000000..f811d6b9 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/06-column-aliases.psql @@ -0,0 +1 @@ +SELECT now(), lower('x') AS lx, 1 AS a, 2 AS "This", 'z' AS other diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/07-casts.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/07-casts.psql new file mode 100644 index 00000000..60b2c207 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/07-casts.psql @@ -0,0 +1 @@ +SELECT '12'::text, 12::varchar(20) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/08-fields-in-table.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/08-fields-in-table.psql new file mode 100644 index 00000000..f0e4ff75 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/08-fields-in-table.psql @@ -0,0 +1,2 @@ +SELECT a, "Weird", t.b::int4, t."WeirdER"::int8 +FROM table1 t diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/09-operators.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/09-operators.psql new file mode 100644 index 00000000..79659c8e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/09-operators.psql @@ -0,0 +1,4 @@ +SELECT + a + 1 AS new_a, a = 123 AS bool_a, c && '{x,y,z}'::text[] AS including_c, + @ d AS abs_d +FROM t diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/10-operators.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/10-operators.psql new file mode 100644 index 00000000..b4d562a4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/10-operators.psql @@ -0,0 +1,4 @@ +SELECT + (((a + b) + c) + d) + e, ((1 + 2) + 3) + 4, d + (b * 5), (e * c) + 2, + (x - 1) * 3 +FROM t diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/11-weird-operator.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/11-weird-operator.psql new file mode 100644 index 00000000..76ac38a8 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/11-weird-operator.psql @@ -0,0 +1,2 @@ +SELECT a OPERATOR("Schema".-) b +FROM c diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/12-boolean-operation.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/12-boolean-operation.psql new file mode 100644 index 00000000..d92c1dca --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/12-boolean-operation.psql @@ -0,0 +1,2 @@ +SELECT (a = b AND c = d AND e = f) OR g = h, NOT i +FROM z diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/13-joins.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/13-joins.psql new file mode 100644 index 00000000..d4bb3717 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/13-joins.psql @@ -0,0 +1,5 @@ +SELECT a +FROM + b + LEFT JOIN c ON b.x = c.y + JOIN d USING (z) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/14-star.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/14-star.psql new file mode 100644 index 00000000..c8968ee1 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/14-star.psql @@ -0,0 +1,2 @@ +SELECT *, count(*) +FROM a diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/15-where.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/15-where.psql new file mode 100644 index 00000000..54631175 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/15-where.psql @@ -0,0 +1,5 @@ +SELECT * +FROM a +WHERE + b = c + AND d < (now() - '1 week'::interval) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/16-groupby.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/16-groupby.psql new file mode 100644 index 00000000..3f60aa0e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/16-groupby.psql @@ -0,0 +1,3 @@ +SELECT a, x, count(*), min(b) +FROM c +GROUP BY a, x diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/17-orderby.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/17-orderby.psql new file mode 100644 index 00000000..dcae21fb --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/17-orderby.psql @@ -0,0 +1,5 @@ +SELECT * +FROM a +ORDER BY + b, c ASC, d DESC, e NULLS FIRST, f NULLS LAST, g ASC NULLS FIRST, + h DESC NULLS FIRST, i ASC NULLS LAST, j DESC NULLS LAST diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/18-limitoffset.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/18-limitoffset.psql new file mode 100644 index 00000000..9c997b48 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/18-limitoffset.psql @@ -0,0 +1,4 @@ +SELECT a +FROM b +LIMIT 10 +OFFSET 20 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/19-having.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/19-having.psql new file mode 100644 index 00000000..e40f7c90 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/19-having.psql @@ -0,0 +1,6 @@ +SELECT a, count(*) +FROM b +GROUP BY a +HAVING + count(*) > 10 + AND min(id) > 123 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/20-case.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/20-case.psql new file mode 100644 index 00000000..baaf974f --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/20-case.psql @@ -0,0 +1,12 @@ +SELECT + CASE + WHEN a = 1 THEN 2 + WHEN a = 2 THEN 4 + ELSE 5 + END, + CASE b + WHEN 1 THEN 5 + WHEN 2 THEN 15 + ELSE 0 + END +FROM x diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/21-in.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/21-in.psql new file mode 100644 index 00000000..193a77a6 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/21-in.psql @@ -0,0 +1,6 @@ +--- TODO: Should we split the IN list items here? +SELECT a +FROM b +WHERE + c IN (1, 2, 3) + AND d IN ('something longer', 'something longer 2', 'something longer 3', 'something longer 4', 'something longer 5', '') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/22-subselect.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/22-subselect.psql new file mode 100644 index 00000000..61b4145c --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/22-subselect.psql @@ -0,0 +1,20 @@ +SELECT + *, + ( + SELECT count(*) + FROM x + ), + ARRAY( + SELECT e + FROM f + ) +FROM a +WHERE + b IN ( + SELECT c + FROM d + ) + AND EXISTS ( + SELECT x + FROM y + ) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/23-null.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/23-null.psql new file mode 100644 index 00000000..6c910560 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/23-null.psql @@ -0,0 +1,2 @@ +SELECT a(b, NULL), c IS NULL, d IS NOT NULL +FROM e diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/24-range-function.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/24-range-function.psql new file mode 100644 index 00000000..5a87e1ba --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/24-range-function.psql @@ -0,0 +1,2 @@ +SELECT * +FROM unnest('{1,2,3}'::int4[]) x diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/25-coalesce.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/25-coalesce.psql new file mode 100644 index 00000000..e728a038 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/25-coalesce.psql @@ -0,0 +1,2 @@ +SELECT COALESCE(a, b || c, 'missing') +FROM d diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/26-range-subselect.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/26-range-subselect.psql new file mode 100644 index 00000000..9ddf4cba --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/26-range-subselect.psql @@ -0,0 +1,6 @@ +SELECT * +FROM + ( + SELECT a + FROM b + ) x diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/27-distinct.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/27-distinct.psql new file mode 100644 index 00000000..b1f53d51 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/27-distinct.psql @@ -0,0 +1,4 @@ +SELECT + DISTINCT + a, b +FROM c diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/28-distinct-on.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/28-distinct-on.psql new file mode 100644 index 00000000..a1985959 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/28-distinct-on.psql @@ -0,0 +1,5 @@ +SELECT + DISTINCT ON (a, b) + a, b, c +FROM t +ORDER BY a, b diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/29-param-ref.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/29-param-ref.psql new file mode 100644 index 00000000..57be617e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/29-param-ref.psql @@ -0,0 +1,2 @@ +--- Note: This was modified to remove use of ? which is no longer supported by the parser as a parameter reference +SELECT $1, $2::int4, $3 || 'z' diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/30-array.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/30-array.psql new file mode 100644 index 00000000..c411b4dc --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/30-array.psql @@ -0,0 +1,3 @@ +SELECT + ARRAY[1, 2, 3], ARRAY['a', NULL, 'c']::text[], + format('%s, %s', VARIADIC ARRAY[1, 2]), format('%s, %s', ARRAY[1, 2], 'a') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/31-indirection.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/31-indirection.psql new file mode 100644 index 00000000..c8ae9b7e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/31-indirection.psql @@ -0,0 +1,4 @@ +SELECT + a[2], a[2:], a[:2], a[2:3], b[2][2:][:2][2:3], + ('{red,green,blue}'::text[])[2] +FROM c diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/32-collate.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/32-collate.psql new file mode 100644 index 00000000..793d5853 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/32-collate.psql @@ -0,0 +1,3 @@ +SELECT a +FROM b +ORDER BY a COLLATE "C" DESC, z diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/33-window-functions.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/33-window-functions.psql new file mode 100644 index 00000000..3bc2705d --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/33-window-functions.psql @@ -0,0 +1,13 @@ +SELECT + count(*) OVER (), + sum(a) OVER ( + PARTITION BY b, c + ), + sum(a) OVER ( + ORDER BY c + ), + sum(a) OVER ( + PARTITION BY b, c + ORDER BY c DESC, a ASC + ) +FROM x diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/34-framed-functions.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/34-framed-functions.psql new file mode 100644 index 00000000..3c7fa568 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/34-framed-functions.psql @@ -0,0 +1,37 @@ +SELECT + sum(a) OVER ( + PARTITION BY b + ORDER BY c + RANGE UNBOUNDED PRECEDING + ), + sum(a) OVER ( + PARTITION BY b + ORDER BY c + GROUPS 2 PRECEDING EXCLUDE GROUP + ), + sum(a) OVER ( + PARTITION BY b + ORDER BY c + ROWS CURRENT ROW EXCLUDE CURRENT ROW + ), + sum(a) OVER ( + PARTITION BY b + ORDER BY c + RANGE UNBOUNDED PRECEDING EXCLUDE TIES + ), + sum(a) OVER ( + PARTITION BY b + ORDER BY c + ROWS 10 PRECEDING + ), + sum(a) OVER ( + PARTITION BY b + ORDER BY c + ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING + ), + sum(a) OVER ( + PARTITION BY b + ORDER BY c + ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING + ) +FROM d diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/35-setops.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/35-setops.psql new file mode 100644 index 00000000..ff8e6b6e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/35-setops.psql @@ -0,0 +1,15 @@ +--- TODO: The parenthesis around the first UNION are likely unnecessary +( + ( + SELECT 1 + UNION + SELECT 2 + ) + UNION + SELECT 3 +) +EXCEPT ALL ( + SELECT 4 + INTERSECT + SELECT 5 +) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/36-values.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/36-values.psql new file mode 100644 index 00000000..358eab12 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/36-values.psql @@ -0,0 +1,5 @@ +SELECT * +FROM + ( + VALUES (1, 'a'), (2, 'b') + ) x(f1, f2) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/37-cte.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/37-cte.psql new file mode 100644 index 00000000..1ee38962 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/37-cte.psql @@ -0,0 +1,12 @@ +WITH sub1 AS ( + SELECT 1 AS x +), sub2(a, b) AS ( + SELECT 2, 3 +), sub3 AS MATERIALIZED ( + SELECT 4 AS y +) +SELECT s1.*, s2.*, s3.* +FROM + sub1 s1, + sub2 s2, + sub3 s3 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/38-rcte.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/38-rcte.psql new file mode 100644 index 00000000..77fb1b97 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/38-rcte.psql @@ -0,0 +1,9 @@ +WITH RECURSIVE x AS ( + SELECT 1 AS i + UNION ALL + SELECT i + 1 + FROM x + WHERE i < 5 +) +SELECT * +FROM x diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/39-any.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/39-any.psql new file mode 100644 index 00000000..b8f8c304 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/39-any.psql @@ -0,0 +1,3 @@ +SELECT * +FROM pg_class +WHERE oid = ANY('{112,113}'::int4[]) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/40-all.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/40-all.psql new file mode 100644 index 00000000..31a44342 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/40-all.psql @@ -0,0 +1,3 @@ +SELECT * +FROM pg_class +WHERE oid <> ALL('{112,113}'::int4[]) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/41-special-a-expr.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/41-special-a-expr.psql new file mode 100644 index 00000000..299cea6e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/41-special-a-expr.psql @@ -0,0 +1,10 @@ +SELECT + 2 BETWEEN 1 AND 3, 2 BETWEEN 3 AND 1, 2 NOT BETWEEN 1 AND 3, + 2 BETWEEN SYMMETRIC 3 AND 1, 2 NOT BETWEEN SYMMETRIC 3 AND 1, + 1 IS DISTINCT FROM NULL, NULL IS DISTINCT FROM NULL, + 1 IS NOT DISTINCT FROM NULL, NULL IS NOT DISTINCT FROM NULL, 1.5 IS NULL, + 'null' IS NOT NULL, true IS TRUE, NULL::boolean IS TRUE, false IS NOT TRUE, + NULL::boolean IS NOT TRUE, true IS FALSE, NULL::boolean IS FALSE, + true IS NOT FALSE, NULL::boolean IS NOT FALSE, true IS UNKNOWN, + NULL::boolean IS UNKNOWN, true IS NOT UNKNOWN, NULL::boolean IS NOT UNKNOWN, + 'a' LIKE '%', 'a' ILIKE '%', NULLIF('a', 'a'), 'a' SIMILAR TO '%' diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/42-minimax.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/42-minimax.psql new file mode 100644 index 00000000..830c6213 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/42-minimax.psql @@ -0,0 +1,4 @@ +SELECT + LEAST(a, b, c), GREATEST(d, e, f), + LEAST(long_column_name * other_long_name, 31242352524) +FROM t diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/43-rowexpr.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/43-rowexpr.psql new file mode 100644 index 00000000..c9806b8a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/43-rowexpr.psql @@ -0,0 +1,5 @@ +SELECT * +FROM t +WHERE + (a, b) = (1, 2) + AND (c, d) = (long_table_column * other_long_column, '423543265666') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/44-bitstring.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/44-bitstring.psql new file mode 100644 index 00000000..f6990374 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/44-bitstring.psql @@ -0,0 +1,3 @@ +SELECT + b'', b'0', b'1', b'10101010', b'10000000', + b'01111111111111111111111111111111' diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/45-grouping-sets.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/45-grouping-sets.psql new file mode 100644 index 00000000..9ade107b --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/45-grouping-sets.psql @@ -0,0 +1,3 @@ +SELECT relkind, relhasindex, count(*) +FROM pg_class +GROUP BY GROUPING SETS ((), relkind, relhasindex, (relkind, relhasindex)) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/46-cube.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/46-cube.psql new file mode 100644 index 00000000..fdee116d --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/46-cube.psql @@ -0,0 +1,3 @@ +SELECT d1, d2, d3, GROUPING(d1, d2, d3), sum(v) +FROM test +GROUP BY CUBE (d1, (d2, d3)) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/47-rollup.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/47-rollup.psql new file mode 100644 index 00000000..65931601 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/47-rollup.psql @@ -0,0 +1,3 @@ +SELECT d1, d2, d3, sum(v) +FROM test +GROUP BY ROLLUP (d1, (d2, d3)) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/48-sublink-any-all.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/48-sublink-any-all.psql new file mode 100644 index 00000000..83e638f4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/48-sublink-any-all.psql @@ -0,0 +1,9 @@ +SELECT * +FROM generate_series(1, 10) i +WHERE + i > ANY ( + SELECT generate_series(1, 8, 2) + ) + AND i <> ALL ( + SELECT generate_series(3, 7, 2) + ) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/49-variadic-func-call.psql b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/49-variadic-func-call.psql new file mode 100644 index 00000000..ad72f849 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/08-selects.d/49-variadic-func-call.psql @@ -0,0 +1,6 @@ +SELECT + fun1(VARIADIC ( + SELECT array_agg(i) + FROM generate_series(1, 5) i + )), + fun2(VARIADIC ARRAY[1, 2]), fun3('whatever', VARIADIC ARRAY[3, 4]) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/01-basic.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/01-basic.psql new file mode 100644 index 00000000..5f3fb335 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/01-basic.psql @@ -0,0 +1,2 @@ +INSERT INTO t +VALUES ('a') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/02-with-columns.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/02-with-columns.psql new file mode 100644 index 00000000..8b2fd66d --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/02-with-columns.psql @@ -0,0 +1,2 @@ +INSERT INTO t (a, b) +VALUES (1, 2) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/03-many-columns.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/03-many-columns.psql new file mode 100644 index 00000000..b3d2304a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/03-many-columns.psql @@ -0,0 +1,3 @@ +--- TODO: Limit how many items we put on one line +INSERT INTO t (a, b, c, d, e, f, g, h, i) +VALUES ('value for column a', 'value for column b', 'value for column c', 'value for column d', 'value for column e', 'value for column f', 'value for column g', 'value for column h', 'value for column i') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/04-with-schema.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/04-with-schema.psql new file mode 100644 index 00000000..fa5d1fb4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/04-with-schema.psql @@ -0,0 +1,2 @@ +INSERT INTO "BadOne".t +VALUES ('a') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/05-multirow.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/05-multirow.psql new file mode 100644 index 00000000..87842208 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/05-multirow.psql @@ -0,0 +1,4 @@ +INSERT INTO t (a, b) +VALUES + (1, 2), (3, 4), (5, 6), (7, 8), (9, 10), (11, 12), (13, 14), (15, 16), + (17, 18), (19, 20) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/06-returning-all.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/06-returning-all.psql new file mode 100644 index 00000000..7c85fa52 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/06-returning-all.psql @@ -0,0 +1,3 @@ +INSERT INTO t +VALUES ('a') +RETURNING * diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/07-returning-some.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/07-returning-some.psql new file mode 100644 index 00000000..f2e6eba7 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/07-returning-some.psql @@ -0,0 +1,3 @@ +INSERT INTO t (a) +VALUES ('a') +RETURNING b, c, d diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/08-default.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/08-default.psql new file mode 100644 index 00000000..f7156742 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/08-default.psql @@ -0,0 +1,2 @@ +INSERT INTO t (a, b, c, d, e) +VALUES (1, 2, 3, DEFAULT, DEFAULT) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/09-cte.psql b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/09-cte.psql new file mode 100644 index 00000000..7e807bb7 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/09-inserts.d/09-cte.psql @@ -0,0 +1,6 @@ +WITH q AS ( + SELECT 1 AS z +) +INSERT INTO t (a) +SELECT z +FROM q diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/01-single-column-no-where.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/01-single-column-no-where.psql new file mode 100644 index 00000000..08ceaeb6 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/01-single-column-no-where.psql @@ -0,0 +1,2 @@ +UPDATE t +SET a = 123 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/02-many-columns-and-where.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/02-many-columns-and-where.psql new file mode 100644 index 00000000..04e0e36b --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/02-many-columns-and-where.psql @@ -0,0 +1,6 @@ +UPDATE t +SET + a = 123, + b = 234, + c = 56 +WHERE d = 123 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/03-with.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/03-with.psql new file mode 100644 index 00000000..adf4885a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/03-with.psql @@ -0,0 +1,4 @@ +UPDATE a al +SET b = x.w +FROM whatever x +WHERE al.id = x.id diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/04-returning-all.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/04-returning-all.psql new file mode 100644 index 00000000..7512e6f8 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/04-returning-all.psql @@ -0,0 +1,4 @@ +UPDATE t +SET a = 1 +WHERE id < 10 +RETURNING * diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/05-returning-some.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/05-returning-some.psql new file mode 100644 index 00000000..ac0adf50 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/05-returning-some.psql @@ -0,0 +1,4 @@ +UPDATE t +SET a = 1 +WHERE id < 10 +RETURNING a, id, b diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/06-multi-assign-simple.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/06-multi-assign-simple.psql new file mode 100644 index 00000000..ee787232 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/06-multi-assign-simple.psql @@ -0,0 +1,2 @@ +UPDATE t +SET (a, b, c) = (1, 2, 3) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/07-multi-assign-long.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/07-multi-assign-long.psql new file mode 100644 index 00000000..a4f5dd8c --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/07-multi-assign-long.psql @@ -0,0 +1,7 @@ +UPDATE t +SET + (a, b, c) = ( + SELECT q.x, q.y, q.z + FROM q + WHERE q.w = t.v + ) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/08-multi-assign-mix.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/08-multi-assign-mix.psql new file mode 100644 index 00000000..1d641e7e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/08-multi-assign-mix.psql @@ -0,0 +1,5 @@ +UPDATE t +SET + a = 2, + (b, c, d) = (3, 4, 5), + e = 6 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/09-cte.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/09-cte.psql new file mode 100644 index 00000000..375a9967 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/09-cte.psql @@ -0,0 +1,7 @@ +WITH w AS ( + SELECT 1 AS s, 2 AS d +) +UPDATE t +SET a = w.d +FROM w +WHERE w.s = t.a diff --git a/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/10-complex-where.psql b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/10-complex-where.psql new file mode 100644 index 00000000..6f07dab0 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/10-updates.d/10-complex-where.psql @@ -0,0 +1,7 @@ +UPDATE t +SET a = x.b +FROM b +WHERE + a.id = b.id + AND a.t >= b.tmin + AND a.t <= b.tmax diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/01-simple.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/01-simple.psql new file mode 100644 index 00000000..d6978c31 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/01-simple.psql @@ -0,0 +1 @@ +DELETE FROM a diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/02-where.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/02-where.psql new file mode 100644 index 00000000..acebc483 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/02-where.psql @@ -0,0 +1,2 @@ +DELETE FROM a al +WHERE al.id > 10 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/03-using.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/03-using.psql new file mode 100644 index 00000000..c59e12d4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/03-using.psql @@ -0,0 +1,3 @@ +DELETE FROM a +USING b +WHERE a.id = b.id diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/04-returning-all.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/04-returning-all.psql new file mode 100644 index 00000000..b218930b --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/04-returning-all.psql @@ -0,0 +1,2 @@ +DELETE FROM a +RETURNING * diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/05-returning-some.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/05-returning-some.psql new file mode 100644 index 00000000..a8f14bd1 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/05-returning-some.psql @@ -0,0 +1,2 @@ +DELETE FROM a +RETURNING b, c, d diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/06-cte.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/06-cte.psql new file mode 100644 index 00000000..a036106e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/06-cte.psql @@ -0,0 +1,6 @@ +WITH w AS ( + SELECT 2 AS x +) +DELETE FROM t +USING w +WHERE w.x = t.a diff --git a/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/07-complex-where.psql b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/07-complex-where.psql new file mode 100644 index 00000000..2e7c35bb --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/11-deletes.d/07-complex-where.psql @@ -0,0 +1,6 @@ +DELETE FROM x +USING y +WHERE + x.a = y.a + AND x.t >= t.tmin + AND x.t <= t.tmax diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/01-base.psql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/01-base.psql new file mode 100644 index 00000000..2ff22f05 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/01-base.psql @@ -0,0 +1,3 @@ +--- TODO: We should avoid the Push/Pop statement here +EXPLAIN + SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/01-base.sql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/01-base.sql new file mode 100644 index 00000000..94662809 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/01-base.sql @@ -0,0 +1 @@ +EXPLAIN SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/02-analyze.psql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/02-analyze.psql new file mode 100644 index 00000000..663f5f7e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/02-analyze.psql @@ -0,0 +1,2 @@ +EXPLAIN (ANALYZE) + SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/02-analyze.sql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/02-analyze.sql new file mode 100644 index 00000000..08645378 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/02-analyze.sql @@ -0,0 +1 @@ +EXPLAIN ANALYZE SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/03-verbose.psql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/03-verbose.psql new file mode 100644 index 00000000..4706e5c6 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/03-verbose.psql @@ -0,0 +1,2 @@ +EXPLAIN (VERBOSE) + SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/03-verbose.sql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/03-verbose.sql new file mode 100644 index 00000000..28b4b265 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/03-verbose.sql @@ -0,0 +1 @@ +EXPLAIN VERBOSE SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/04-analyze-verbose.psql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/04-analyze-verbose.psql new file mode 100644 index 00000000..e1ca1715 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/04-analyze-verbose.psql @@ -0,0 +1,2 @@ +EXPLAIN (ANALYZE, VERBOSE) + SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/04-analyze-verbose.sql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/04-analyze-verbose.sql new file mode 100644 index 00000000..cb9260da --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/04-analyze-verbose.sql @@ -0,0 +1 @@ +EXPLAIN ANALYZE VERBOSE SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/05-other.psql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/05-other.psql new file mode 100644 index 00000000..e35ddfe6 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/05-other.psql @@ -0,0 +1,2 @@ +EXPLAIN (ANALYZE, VERBOSE, COSTS OFF, SETTINGS ON, BUFFERS OFF, WAL ON, TIMING OFF, SUMMARY ON, FORMAT "json") + SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/05-other.sql b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/05-other.sql new file mode 100644 index 00000000..8f493c84 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/12-explains.d/05-other.sql @@ -0,0 +1 @@ +EXPLAIN ( analyze, verbose, costs off, settings on, buffers off, wal on, timing off, summary on, format json ) SELECT 1 diff --git a/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/01-system.psql b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/01-system.psql new file mode 100644 index 00000000..ca392634 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/01-system.psql @@ -0,0 +1,2 @@ +SELECT * +FROM pg_class TABLESAMPLE system(5) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/01-system.sql b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/01-system.sql new file mode 100644 index 00000000..9c557ac5 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/01-system.sql @@ -0,0 +1 @@ +SELECT * FROM pg_class TABLESAMPLE SYSTEM ( 5 ) \ No newline at end of file diff --git a/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/02-bernoulli.psql b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/02-bernoulli.psql new file mode 100644 index 00000000..fc715e44 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/02-bernoulli.psql @@ -0,0 +1,2 @@ +SELECT * +FROM pg_class x TABLESAMPLE bernoulli(5) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/02-bernoulli.sql b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/02-bernoulli.sql new file mode 100644 index 00000000..b3bae632 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/02-bernoulli.sql @@ -0,0 +1 @@ +SELECT * FROM pg_class AS x TABLESAMPLE BERNOULLI ( 5 ) \ No newline at end of file diff --git a/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/03-repeatable.psql b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/03-repeatable.psql new file mode 100644 index 00000000..e62a92f7 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/03-repeatable.psql @@ -0,0 +1,2 @@ +SELECT * +FROM pg_class TABLESAMPLE system(5) REPEATABLE (123.5) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/03-repeatable.sql b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/03-repeatable.sql new file mode 100644 index 00000000..e9a1f07c --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/13-tablesample.d/03-repeatable.sql @@ -0,0 +1 @@ +SELECT * FROM pg_class TABLESAMPLE SYSTEM ( 5 ) REPEATABLE ( 123.5 ) \ No newline at end of file diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/01-simple.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/01-simple.psql new file mode 100644 index 00000000..fd3cdb11 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/01-simple.psql @@ -0,0 +1 @@ +SELECT xmlelement(name element, xmlattributes(1 AS one, 'deuce' AS two), 'content') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/02-concat.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/02-concat.psql new file mode 100644 index 00000000..b3bde309 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/02-concat.psql @@ -0,0 +1 @@ +SELECT xmlconcat('', '') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/03-forest.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/03-forest.psql new file mode 100644 index 00000000..f2010e6a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/03-forest.psql @@ -0,0 +1 @@ +SELECT xmlforest(name, age, salary AS pay) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/04-parse.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/04-parse.psql new file mode 100644 index 00000000..26aa39b2 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/04-parse.psql @@ -0,0 +1,3 @@ +SELECT + xmlparse(document 'Manual...'), + xmlparse(content 'abcbarfoo') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/05-pi.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/05-pi.psql new file mode 100644 index 00000000..bdf8617a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/05-pi.psql @@ -0,0 +1 @@ +SELECT xmlpi(name xxx), xmlpi(name zzz, 'whatever') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/06-root.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/06-root.psql new file mode 100644 index 00000000..03fc2470 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/06-root.psql @@ -0,0 +1,5 @@ +SELECT + xmlroot(''::xml, version no value, standalone no value), + xmlroot(''::xml, version '1.0', standalone yes), + xmlroot(''::xml, version '1.0', standalone no), + xmlroot(''::xml, version '1.0') diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/07-serialize.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/07-serialize.psql new file mode 100644 index 00000000..7b4de232 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/07-serialize.psql @@ -0,0 +1,3 @@ +SELECT + xmlserialize(content 'good' AS char(10)), + xmlserialize(document 'bad' AS text) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/08-is-document.psql b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/08-is-document.psql new file mode 100644 index 00000000..9c3c06bb --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/14-xml.d/08-is-document.psql @@ -0,0 +1 @@ +SELECT 'bar'::xml IS DOCUMENT, NOT 'bar'::xml IS DOCUMENT diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/01-lateral.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/01-lateral.psql new file mode 100644 index 00000000..c7b0a52a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/01-lateral.psql @@ -0,0 +1,12 @@ +SELECT c.oid::regclass, u.grantor +FROM + pg_class c, + LATERAL ( + SELECT u.usename AS grantor + FROM + aclexplode(c.relacl) x + JOIN pg_user u ON x.grantor = u.usesysid + WHERE + x.privilege_type = 'SELECT' + AND x.grantee = 16514 + ) u diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/02-current-row.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/02-current-row.psql new file mode 100644 index 00000000..c7599679 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/02-current-row.psql @@ -0,0 +1,11 @@ +SELECT + i, + sum(i) OVER ( + ORDER BY i + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + ), + sum(i) OVER ( + ORDER BY i + ROWS BETWEEN 2 PRECEDING AND CURRENT ROW + ) +FROM generate_series(1, 10) i diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/03-filtered-aggregates.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/03-filtered-aggregates.psql new file mode 100644 index 00000000..31b2d597 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/03-filtered-aggregates.psql @@ -0,0 +1,2 @@ +SELECT count(*) FILTER (WHERE relkind = 'r') +FROM pg_class diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/04-cast-of-expression.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/04-cast-of-expression.psql new file mode 100644 index 00000000..a7bd7ac6 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/04-cast-of-expression.psql @@ -0,0 +1,3 @@ +--- TODO: The operator spacing on "->>" here could be improved (it should have no spaces) +SELECT (data ->> 'timestamp')::timestamptz, (1 = 1 OR 2 = 2)::int4 +FROM z diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/05-literal-new-line.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/05-literal-new-line.psql new file mode 100644 index 00000000..2da12a3b --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/05-literal-new-line.psql @@ -0,0 +1,2 @@ +SELECT ' +' diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/06-aggregate-filter-inside-case.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/06-aggregate-filter-inside-case.psql new file mode 100644 index 00000000..f518d9ab --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/06-aggregate-filter-inside-case.psql @@ -0,0 +1,7 @@ +SELECT + CASE + WHEN count(*) FILTER (WHERE col_state = 2) = count(col_id) THEN true + WHEN count(*) FILTER (WHERE col_state = 3) > 0 THEN false + ELSE NULL + END AS col_alias +FROM my_table diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/07-missing-ordinality-and-order-by.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/07-missing-ordinality-and-order-by.psql new file mode 100644 index 00000000..2224fede --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/07-missing-ordinality-and-order-by.psql @@ -0,0 +1,2 @@ +SELECT string_agg(E'\\U' || lpad(to_hex(ascii(unnest)), 8, '0'), '' ORDER BY ordinality) +FROM unnest(regexp_split_to_array($1, '')) WITH ORDINALITY diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/08-missing-dot-before-start.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/08-missing-dot-before-start.psql new file mode 100644 index 00000000..c13b43c1 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/08-missing-dot-before-start.psql @@ -0,0 +1 @@ +SELECT (unnest('{"(ACDT,10:30:00,t)","(ACSST,10:30:00,t)"}'::pg_timezone_abbrevs[])).* diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/09-missing-dot-before-column.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/09-missing-dot-before-column.psql new file mode 100644 index 00000000..42af886e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/09-missing-dot-before-column.psql @@ -0,0 +1 @@ +SELECT (unnest('{"(ACDT,10:30:00,t)","(ACSST,10:30:00,t)"}'::pg_timezone_abbrevs[])).abbrev diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/10-missing-not.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/10-missing-not.psql new file mode 100644 index 00000000..1116e44e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/10-missing-not.psql @@ -0,0 +1 @@ +SELECT 1 NOT IN (2, 3, 4), 'a' NOT LIKE 'z' diff --git a/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/11-distinct-aggregate.psql b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/11-distinct-aggregate.psql new file mode 100644 index 00000000..62e23e74 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/16-bugs.d/11-distinct-aggregate.psql @@ -0,0 +1,2 @@ +SELECT count(DISTINCT x), array_agg(DISTINCT id, ', ' ORDER BY id DESC) +FROM z diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/01-for-update.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/01-for-update.psql new file mode 100644 index 00000000..dc56b2e4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/01-for-update.psql @@ -0,0 +1,5 @@ +SELECT * +FROM pg_class +ORDER BY oid +LIMIT 5 +FOR UPDATE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/02-for-no-key-update.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/02-for-no-key-update.psql new file mode 100644 index 00000000..b29ec04b --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/02-for-no-key-update.psql @@ -0,0 +1,5 @@ +SELECT * +FROM pg_class +ORDER BY oid +LIMIT 5 +FOR NO KEY UPDATE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/03-for-share.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/03-for-share.psql new file mode 100644 index 00000000..970394a9 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/03-for-share.psql @@ -0,0 +1,5 @@ +SELECT * +FROM pg_class +ORDER BY oid +LIMIT 5 +FOR SHARE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/04-for-key-share.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/04-for-key-share.psql new file mode 100644 index 00000000..666aa3f1 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/04-for-key-share.psql @@ -0,0 +1,5 @@ +SELECT * +FROM pg_class +ORDER BY oid +LIMIT 5 +FOR KEY SHARE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/05-of-table.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/05-of-table.psql new file mode 100644 index 00000000..8372aebf --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/05-of-table.psql @@ -0,0 +1,7 @@ +SELECT * +FROM + pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid +ORDER BY c.oid ASC +LIMIT 5 +FOR SHARE OF c diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/06-of-tables.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/06-of-tables.psql new file mode 100644 index 00000000..e69b13b0 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/06-of-tables.psql @@ -0,0 +1,7 @@ +SELECT * +FROM + pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid +ORDER BY c.oid ASC +LIMIT 5 +FOR SHARE OF c, n diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/07-nowait.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/07-nowait.psql new file mode 100644 index 00000000..71d7c9c8 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/07-nowait.psql @@ -0,0 +1,5 @@ +SELECT * +FROM pg_class +ORDER BY oid +LIMIT 5 +FOR UPDATE NOWAIT diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/08-skip-locked.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/08-skip-locked.psql new file mode 100644 index 00000000..0d063218 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/08-skip-locked.psql @@ -0,0 +1,5 @@ +SELECT * +FROM pg_class +ORDER BY oid +LIMIT 5 +FOR UPDATE SKIP LOCKED diff --git a/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/09-multi.psql b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/09-multi.psql new file mode 100644 index 00000000..7e4177ba --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/17-locking-selects.d/09-multi.psql @@ -0,0 +1,8 @@ +SELECT * +FROM + pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid +ORDER BY c.oid ASC +LIMIT 5 +FOR UPDATE OF c NOWAIT +FOR SHARE OF n SKIP LOCKED diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/01-basic-nothing.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/01-basic-nothing.psql new file mode 100644 index 00000000..d4e31d94 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/01-basic-nothing.psql @@ -0,0 +1,3 @@ +INSERT INTO t (a, b, c) +VALUES ('aa', 'bb', 'cc') +ON CONFLICT DO NOTHING diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/02-constraint-nothing.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/02-constraint-nothing.psql new file mode 100644 index 00000000..26fe9784 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/02-constraint-nothing.psql @@ -0,0 +1,3 @@ +INSERT INTO t (a, b, c) +VALUES ('aa', 'bb', 'cc') +ON CONFLICT ON CONSTRAINT some_constraint DO NOTHING diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/03-columns-nothing.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/03-columns-nothing.psql new file mode 100644 index 00000000..f8c6aecb --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/03-columns-nothing.psql @@ -0,0 +1,3 @@ +INSERT INTO t (a, b, c) +VALUES ('aa', 'bb', 'cc') +ON CONFLICT (a, lower(b)) DO NOTHING diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/04-expr-complex.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/04-expr-complex.psql new file mode 100644 index 00000000..465a6e2c --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/04-expr-complex.psql @@ -0,0 +1,3 @@ +INSERT INTO t (a, b, c) +VALUES ('aa', 'bb', 'cc') +ON CONFLICT (a COLLATE "C", b text_pattern_ops, c COLLATE "C" text_pattern_ops) DO NOTHING diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/05-simple-update.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/05-simple-update.psql new file mode 100644 index 00000000..f60c660f --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/05-simple-update.psql @@ -0,0 +1,4 @@ +INSERT INTO t (a, b, c) +VALUES ('aa', 'bb', 'cc') +ON CONFLICT DO UPDATE +SET c = excluded.fruit diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/06-update-multicolumn.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/06-update-multicolumn.psql new file mode 100644 index 00000000..7f6b9bf7 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/06-update-multicolumn.psql @@ -0,0 +1,4 @@ +INSERT INTO insertconflicttest +VALUES (1, 'Apple'), (2, 'Orange') +ON CONFLICT (key) DO UPDATE +SET (fruit, key) = (excluded.fruit, excluded.key) diff --git a/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/07-update-complex.psql b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/07-update-complex.psql new file mode 100644 index 00000000..d54af6a5 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/18-conflicts.d/07-update-complex.psql @@ -0,0 +1,18 @@ +INSERT INTO dropcol (key, drop1, keep1, drop2, keep2) +VALUES (1, 2, '2', '2', 2) +ON CONFLICT (key) DO UPDATE +SET + drop1 = excluded.drop1, + keep1 = excluded.keep1, + drop2 = excluded.drop2, + keep2 = excluded.keep2 +WHERE + excluded.drop1 IS NOT NULL + AND excluded.keep1 IS NOT NULL + AND excluded.drop2 IS NOT NULL + AND excluded.keep2 IS NOT NULL + AND dropcol.drop1 IS NOT NULL + AND dropcol.keep1 IS NOT NULL + AND dropcol.drop2 IS NOT NULL + AND dropcol.keep2 IS NOT NULL +RETURNING * diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/01-rollback.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/01-rollback.sql new file mode 100644 index 00000000..61d34242 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/01-rollback.sql @@ -0,0 +1 @@ +ROLLBACK diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/02-rollback_and_chain.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/02-rollback_and_chain.sql new file mode 100644 index 00000000..4af752b9 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/02-rollback_and_chain.sql @@ -0,0 +1 @@ +ROLLBACK AND CHAIN diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/03-commit.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/03-commit.sql new file mode 100644 index 00000000..2a4398d8 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/03-commit.sql @@ -0,0 +1 @@ +COMMIT diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/04-commit_and_chain.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/04-commit_and_chain.sql new file mode 100644 index 00000000..3fe729f7 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/04-commit_and_chain.sql @@ -0,0 +1 @@ +COMMIT AND CHAIN diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/05-start_transaction.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/05-start_transaction.sql new file mode 100644 index 00000000..0762b28d --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/05-start_transaction.sql @@ -0,0 +1 @@ +START TRANSACTION diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/06-start_transaction_isolation_level_serializable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/06-start_transaction_isolation_level_serializable.sql new file mode 100644 index 00000000..0ecf06e2 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/06-start_transaction_isolation_level_serializable.sql @@ -0,0 +1 @@ +START TRANSACTION ISOLATION LEVEL SERIALIZABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/07-start_transaction_isolation_level_repeatable_read.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/07-start_transaction_isolation_level_repeatable_read.sql new file mode 100644 index 00000000..4b8d5b54 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/07-start_transaction_isolation_level_repeatable_read.sql @@ -0,0 +1 @@ +START TRANSACTION ISOLATION LEVEL REPEATABLE READ diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/08-start_transaction_isolation_level_read_committed.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/08-start_transaction_isolation_level_read_committed.sql new file mode 100644 index 00000000..c197fca4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/08-start_transaction_isolation_level_read_committed.sql @@ -0,0 +1 @@ +START TRANSACTION ISOLATION LEVEL READ COMMITTED diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/09-start_transaction_isolation_level_read_uncommitted.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/09-start_transaction_isolation_level_read_uncommitted.sql new file mode 100644 index 00000000..9bc1604d --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/09-start_transaction_isolation_level_read_uncommitted.sql @@ -0,0 +1 @@ +START TRANSACTION ISOLATION LEVEL READ UNCOMMITTED diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/10-start_transaction_read_write.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/10-start_transaction_read_write.sql new file mode 100644 index 00000000..c0429438 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/10-start_transaction_read_write.sql @@ -0,0 +1 @@ +START TRANSACTION READ WRITE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/11-start_transaction_read_only.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/11-start_transaction_read_only.sql new file mode 100644 index 00000000..70489e86 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/11-start_transaction_read_only.sql @@ -0,0 +1 @@ +START TRANSACTION READ ONLY diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/12-start_transaction_deferrable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/12-start_transaction_deferrable.sql new file mode 100644 index 00000000..ea347b20 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/12-start_transaction_deferrable.sql @@ -0,0 +1 @@ +START TRANSACTION DEFERRABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/13-start_transaction_not_deferrable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/13-start_transaction_not_deferrable.sql new file mode 100644 index 00000000..9aebb68d --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/13-start_transaction_not_deferrable.sql @@ -0,0 +1 @@ +START TRANSACTION NOT DEFERRABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/14-start_transaction_isolation_level_serializable,_deferrable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/14-start_transaction_isolation_level_serializable,_deferrable.sql new file mode 100644 index 00000000..a4135fe3 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/14-start_transaction_isolation_level_serializable,_deferrable.sql @@ -0,0 +1 @@ +START TRANSACTION ISOLATION LEVEL SERIALIZABLE, DEFERRABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/15-begin.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/15-begin.sql new file mode 100644 index 00000000..1bf4c3f4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/15-begin.sql @@ -0,0 +1 @@ +BEGIN diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/16-begin_isolation_level_serializable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/16-begin_isolation_level_serializable.sql new file mode 100644 index 00000000..283f8dc4 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/16-begin_isolation_level_serializable.sql @@ -0,0 +1 @@ +BEGIN ISOLATION LEVEL SERIALIZABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/17-begin_isolation_level_repeatable_read.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/17-begin_isolation_level_repeatable_read.sql new file mode 100644 index 00000000..d55a24b5 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/17-begin_isolation_level_repeatable_read.sql @@ -0,0 +1 @@ +BEGIN ISOLATION LEVEL REPEATABLE READ diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/18-begin_isolation_level_read_committed.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/18-begin_isolation_level_read_committed.sql new file mode 100644 index 00000000..85e76e60 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/18-begin_isolation_level_read_committed.sql @@ -0,0 +1 @@ +BEGIN ISOLATION LEVEL READ COMMITTED diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/19-begin_isolation_level_read_uncommitted.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/19-begin_isolation_level_read_uncommitted.sql new file mode 100644 index 00000000..658cbe01 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/19-begin_isolation_level_read_uncommitted.sql @@ -0,0 +1 @@ +BEGIN ISOLATION LEVEL READ UNCOMMITTED diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/20-begin_read_write.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/20-begin_read_write.sql new file mode 100644 index 00000000..2216aaa8 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/20-begin_read_write.sql @@ -0,0 +1 @@ +BEGIN READ WRITE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/21-begin_read_only.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/21-begin_read_only.sql new file mode 100644 index 00000000..1e3dc861 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/21-begin_read_only.sql @@ -0,0 +1 @@ +BEGIN READ ONLY diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/22-begin_deferrable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/22-begin_deferrable.sql new file mode 100644 index 00000000..2a1e2197 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/22-begin_deferrable.sql @@ -0,0 +1 @@ +BEGIN DEFERRABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/23-begin_not_deferrable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/23-begin_not_deferrable.sql new file mode 100644 index 00000000..8d2169d9 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/23-begin_not_deferrable.sql @@ -0,0 +1 @@ +BEGIN NOT DEFERRABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/24-begin_isolation_level_serializable,_deferrable.sql b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/24-begin_isolation_level_serializable,_deferrable.sql new file mode 100644 index 00000000..26aa148a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/19-transactions.d/24-begin_isolation_level_serializable,_deferrable.sql @@ -0,0 +1 @@ +BEGIN ISOLATION LEVEL SERIALIZABLE, DEFERRABLE diff --git a/c_src/libpg_query/test/sql/deparse-depesz/README.md b/c_src/libpg_query/test/sql/deparse-depesz/README.md new file mode 100644 index 00000000..81f3dfc7 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse-depesz/README.md @@ -0,0 +1,33 @@ +Files in this folder are based on *.psql sample files in Hubert "depesz" Lubaczewski's +pg-sql-prettyprinter project (https://gitlab.com/depesz/pg-sql-prettyprinter/), and +modified to match libpg_query deparser formatting logic. + +--- + +Copyright (c) 2022-2023, Hubert 'depesz' Lubaczewski +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/c_src/libpg_query/test/sql/deparse/case.sql b/c_src/libpg_query/test/sql/deparse/case.sql new file mode 100644 index 00000000..f518d9ab --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/case.sql @@ -0,0 +1,7 @@ +SELECT + CASE + WHEN count(*) FILTER (WHERE col_state = 2) = count(col_id) THEN true + WHEN count(*) FILTER (WHERE col_state = 3) > 0 THEN false + ELSE NULL + END AS col_alias +FROM my_table diff --git a/c_src/libpg_query/test/sql/deparse/comment_multiline.sql b/c_src/libpg_query/test/sql/deparse/comment_multiline.sql new file mode 100644 index 00000000..66464ca6 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/comment_multiline.sql @@ -0,0 +1,5 @@ + +-- +-- Name: btree_gin; Type: EXTENSION; Schema: -; Owner: - +-- +CREATE EXTENSION IF NOT EXISTS btree_gin SCHEMA public diff --git a/c_src/libpg_query/test/sql/deparse/complex_depesz.sql b/c_src/libpg_query/test/sql/deparse/complex_depesz.sql new file mode 100644 index 00000000..47a1186e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/complex_depesz.sql @@ -0,0 +1,34 @@ +SELECT + decode(a.category, NULL, b.category, a.category) AS category, + b.par AS "Total object Request", b.ps AS "objects Served", + b.ar AS "Total sushi Request", a.sushis AS "sushis Served", + round(decode(b.ar, 0, 0, (b.ar - decode(a.sushis, NULL, 0, a.sushis)::numeric) / b.ar) * 100, 3) AS "USR", + a.clk AS points, + decode(b.ps, 0, 0, round((a.clk / b.ps) * 100, 3)) AS "CTR", a.cpc AS "CPC", + a.tc AS "Cost", + decode(b.ps, 0, 0, (a.tc / b.ps) * 1000::numeric(8, 3)) AS effectcost +FROM + ( + SELECT + decode(b.category, NULL, 'N/A', b.category) AS category, + sum(doughnuts) AS sushis, sum(points) AS clk, + round(sum(total_cost)::numeric, 3) AS tc, + decode(sum(points), 0, 0, round(sum(total_cost) / sum(points)::numeric, 3)) AS cpc + FROM + daily_city_dealer_summary a, + category_dealer_map b + WHERE + a.category_dealer_id = b.category_dealer_id + AND created_day BETWEEN '2010-05-01' AND '2010-05-25' + GROUP BY b.category + ) a + FULL JOIN ( + SELECT + decode(a.category, NULL, 'N/A', decode(a.category, '-', 'World-Remaining countries', a.category)) AS category, + sum(valid_object_request) AS par, sum(valid_sushi_request) AS ar, + sum(object_doughnuts) AS ps + FROM traffic_hit a + WHERE request_date BETWEEN '2010-05-01' AND '2010-05-25' + GROUP BY a.category + ) b ON lower(a.category) = lower(b.category) +ORDER BY 4 DESC diff --git a/c_src/libpg_query/test/sql/deparse/complex_gitlab.sql b/c_src/libpg_query/test/sql/deparse/complex_gitlab.sql new file mode 100644 index 00000000..84b408f8 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/complex_gitlab.sql @@ -0,0 +1,56 @@ +-- From https://handbook.gitlab.com/handbook/enterprise-data/platform/sql-style-guide/ +WITH my_data AS ( + SELECT my_data.* + FROM + prod.my_data_with_a_long_table_name my_data + JOIN prod.other_thing ON true + WHERE my_data.filter = 'my_filter' +), some_cte AS ( + SELECT + DISTINCT + id AS other_id, other_field_1, other_field_2, date_field_at, + data_by_row, field_4, field_5, + lag(other_field_2) OVER ( + PARTITION BY other_id, other_field_1 + ORDER BY 5 + ) AS previous_other_field_2 + FROM prod.my_other_data +), + +/* +This is a very long comment: It is good practice to leave comments in code to +explain complex logic in CTEs or business logic which may not be intuitive to +someone who does not have intimate knowledge of the data source. This can help +new users familiarize themselves with the code quickly. +*/ +final AS ( + SELECT + -- This is a singel line comment + my_data.field_1 AS detailed_field_1, + my_data.field_2 AS detailed_field_2, my_data.detailed_field_3, + date_trunc('month', some_cte.date_field_at) AS date_field_month, + some_cte.data_by_row['id']::number AS id_field, + iff(my_data.detailed_field_3 > my_data.field_2, true, false) AS is_boolean, + CASE + WHEN + my_data.cancellation_date IS NULL + AND my_data.expiration_date IS NOT NULL THEN my_data.expiration_date + WHEN my_data.cancellation_date IS NULL THEN my_data.start_date + 7 + ELSE + -- There is a reason for this number (BUG: this is supposed to be after the "7") + my_data.cancellation_date + END AS adjusted_cancellation_date, + count(*) AS number_of_records, sum(some_cte.field_4) AS field_4_sum, + max(some_cte.field_5) AS field_5_max + FROM + my_data + LEFT JOIN some_cte ON my_data.id = some_cte.id + WHERE + my_data.field_1 = 'abc' + AND (my_data.field_2 = 'def' OR my_data.field_2 = 'ghi') + GROUP BY 1, 2, 3, 4, 5, 6 + HAVING count(*) > 1 + ORDER BY 8 DESC +) +SELECT * +FROM final diff --git a/c_src/libpg_query/test/sql/deparse/complex_mattm.sql b/c_src/libpg_query/test/sql/deparse/complex_mattm.sql new file mode 100644 index 00000000..a59d8b02 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/complex_mattm.sql @@ -0,0 +1,26 @@ +-- From https://github.com/mattm/sql-style-guide +WITH hubspot_interest AS ( + SELECT + email, + timestamp_millis(property_beacon_interest) AS expressed_interest_at + FROM hubspot.contact + WHERE property_beacon_interest IS NOT NULL +), support_interest AS ( + SELECT conversation.email, conversation.created_at AS expressed_interest_at + FROM + helpscout.conversation + JOIN helpscout.conversation_tag ON conversation.id = conversation_tag.conversation_id + WHERE conversation_tag.tag = 'beacon-interest' +), combined_interest AS ( + SELECT * + FROM hubspot_interest + UNION ALL + SELECT * + FROM support_interest +), first_interest AS ( + SELECT email, min(expressed_interest_at) AS expressed_interest_at + FROM combined_interest + GROUP BY email +) +SELECT * +FROM first_interest diff --git a/c_src/libpg_query/test/sql/deparse/ddl_alter_table_add_constraint.sql b/c_src/libpg_query/test/sql/deparse/ddl_alter_table_add_constraint.sql new file mode 100644 index 00000000..41aea7ff --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/ddl_alter_table_add_constraint.sql @@ -0,0 +1,2 @@ +ALTER TABLE ONLY public.vacuum_insight_runs_7d + ADD CONSTRAINT vacuum_insight_runs_7d_pkey PRIMARY KEY (server_id, check_name, run_at) diff --git a/c_src/libpg_query/test/sql/deparse/ddl_create_index.sql b/c_src/libpg_query/test/sql/deparse/ddl_create_index.sql new file mode 100644 index 00000000..75d5b86e --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/ddl_create_index.sql @@ -0,0 +1,3 @@ +CREATE UNIQUE INDEX schema_tables_database_id_schema_name_table_name_idx +ON public.schema_tables USING btree (database_id, schema_name, table_name) +WHERE removed_at IS NULL diff --git a/c_src/libpg_query/test/sql/deparse/ddl_create_table.sql b/c_src/libpg_query/test/sql/deparse/ddl_create_table.sql new file mode 100644 index 00000000..0293320f --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/ddl_create_table.sql @@ -0,0 +1,14 @@ +CREATE TABLE public.vacuum_run_stats_35d ( + vacuum_run_stats_id uuid DEFAULT public.gen_random_uuid() NOT NULL, + server_id uuid NOT NULL, + vacuum_run_id uuid NOT NULL, + collected_at timestamp NOT NULL, + phase int NOT NULL, + heap_blks_total bigint NOT NULL, + heap_blks_scanned bigint NOT NULL, + heap_blks_vacuumed bigint NOT NULL, + index_vacuum_count bigint NOT NULL, + max_dead_tuples bigint NOT NULL, + num_dead_tuples bigint NOT NULL +) +PARTITION BY RANGE (collected_at) diff --git a/c_src/libpg_query/test/sql/deparse/ddl_create_trigger.sql b/c_src/libpg_query/test/sql/deparse/ddl_create_trigger.sql new file mode 100644 index 00000000..a4079803 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/ddl_create_trigger.sql @@ -0,0 +1 @@ +CREATE TRIGGER query_runs_notify AFTER INSERT ON public.query_runs REFERENCING NEW TABLE rows EXECUTE FUNCTION public.query_runs_notify() diff --git a/c_src/libpg_query/test/sql/deparse/ddl_create_type.sql b/c_src/libpg_query/test/sql/deparse/ddl_create_type.sql new file mode 100644 index 00000000..56f24c8c --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/ddl_create_type.sql @@ -0,0 +1,6 @@ +CREATE TYPE public.schema_table_event_type AS ENUM ( + 'manual_vacuum', + 'auto_vacuum', + 'manual_analyze', + 'auto_analyze' +) diff --git a/c_src/libpg_query/test/sql/deparse/insert_long.sql b/c_src/libpg_query/test/sql/deparse/insert_long.sql new file mode 100644 index 00000000..392d192b --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/insert_long.sql @@ -0,0 +1,9 @@ +INSERT INTO schema_migrations (version) +VALUES + ('20121115104253'), ('20121115104424'), ('20121115144719'), + ('20121222152557'), ('20121222210347'), ('20130129121255'), + ('20130129163021'), ('20130129175021'), ('20130129180846'), + ('20130130131612'), ('20130208115344'), ('20130217171132'), + ('20130222164352'), ('20130305141105'), ('20130404094832'), + ('20130429153359'), ('20130701150108'), ('20130706202400'), + ('20130706202500') diff --git a/c_src/libpg_query/test/sql/deparse/nested_cte.sql b/c_src/libpg_query/test/sql/deparse/nested_cte.sql new file mode 100644 index 00000000..285e497a --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/nested_cte.sql @@ -0,0 +1,11 @@ +--- Note: This is a slightly odd choice (using a WITH on the INSERT's SELECT clause), but valid syntax +WITH q AS ( + SELECT 1 AS z +) +INSERT INTO t (a) +WITH qq AS ( + SELECT * + FROM q +) +SELECT z +FROM qq diff --git a/c_src/libpg_query/test/sql/deparse/simple.sql b/c_src/libpg_query/test/sql/deparse/simple.sql new file mode 100644 index 00000000..e0c9c6d1 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/simple.sql @@ -0,0 +1,10 @@ +SELECT col1, col2 +FROM + xyz + JOIN abc ON a = b +WHERE + c IN ( + SELECT id + FROM test + ) + AND col2 > 123 diff --git a/c_src/libpg_query/test/sql/deparse/union.sql b/c_src/libpg_query/test/sql/deparse/union.sql new file mode 100644 index 00000000..f3ddaab9 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/union.sql @@ -0,0 +1,30 @@ +WITH input AS ( + SELECT database_id, fingerprint, last_occurred_at, index + FROM unnest($1::int[], $2::bigint[], $3::date[], $4::int[]) _(database_id, fingerprint, last_occurred_at, index) +), existing_queries AS ( + SELECT + queries.id AS query_id, input.database_id, input.fingerprint, + input.last_occurred_at, input.index + FROM + queries + JOIN input USING (database_id, fingerprint) +), update_occurrences AS ( + UPDATE query_occurrences + SET last = last_occurred_at + FROM existing_queries q + WHERE + q.query_id = query_occurrences.query_id + AND last < last_occurred_at + RETURNING index +) +SELECT index, $5 AS "exists" +FROM update_occurrences +UNION ( + SELECT input.index, $6 AS "exists" + FROM + input + LEFT JOIN existing_queries USING (database_id, fingerprint) + WHERE existing_queries.database_id IS NULL + LIMIT 1 +) +LIMIT 5 diff --git a/c_src/libpg_query/test/sql/deparse/union_2.sql b/c_src/libpg_query/test/sql/deparse/union_2.sql new file mode 100644 index 00000000..e8b05e50 --- /dev/null +++ b/c_src/libpg_query/test/sql/deparse/union_2.sql @@ -0,0 +1,9 @@ +( + SELECT 1 + LIMIT 1 +) +UNION ( + SELECT 1 + LIMIT 1 +) +LIMIT 2 diff --git a/c_src/libpg_query/test/sql/postgres_regress/aggregates.sql b/c_src/libpg_query/test/sql/postgres_regress/aggregates.sql index 675b23ad..fe4d89ae 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/aggregates.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/aggregates.sql @@ -595,6 +595,25 @@ explain (costs off) select sum(two order by two) from tenk1; reset enable_presorted_aggregate; +-- +-- Test cases with FILTER clause +-- + +-- Ensure we presort when the aggregate contains plain Vars +explain (costs off) +select sum(two order by two) filter (where two > 1) from tenk1; + +-- Ensure we presort for RelabelType'd Vars +explain (costs off) +select string_agg(distinct f1, ',') filter (where length(f1) > 1) +from varchar_tbl; + +-- Ensure we don't presort when the aggregate's argument contains an +-- explicit cast. +explain (costs off) +select string_agg(distinct f1::varchar(2), ',') filter (where length(f1) > 1) +from varchar_tbl; + -- -- Test combinations of DISTINCT and/or ORDER BY -- diff --git a/c_src/libpg_query/test/sql/postgres_regress/alter_table.sql b/c_src/libpg_query/test/sql/postgres_regress/alter_table.sql index da127244..ab23d80f 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/alter_table.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/alter_table.sql @@ -2180,13 +2180,15 @@ SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment F -- filenode function call can return NULL for a relation dropped concurrently -- with the call's surrounding query, so ignore a NULL mapped_oid for -- relations that no longer exist after all calls finish. +-- Temporary relations are ignored, as not supported by pg_filenode_relation(). CREATE TEMP TABLE filenode_mapping AS SELECT oid, mapped_oid, reltablespace, relfilenode, relname FROM pg_class, pg_filenode_relation(reltablespace, pg_relation_filenode(oid)) AS mapped_oid -WHERE relkind IN ('r', 'i', 'S', 't', 'm') AND mapped_oid IS DISTINCT FROM oid; - +WHERE relkind IN ('r', 'i', 'S', 't', 'm') + AND relpersistence != 't' + AND mapped_oid IS DISTINCT FROM oid; SELECT m.* FROM filenode_mapping m LEFT JOIN pg_class c ON c.oid = m.oid WHERE c.oid IS NOT NULL OR m.mapped_oid IS NOT NULL; @@ -2797,6 +2799,15 @@ ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY; \d part_rp100 DROP TABLE range_parted2; +-- Test that hash partitions continue to work after they're concurrently +-- detached (bugs #18371, #19070) +CREATE TABLE hash_parted2 (a int) PARTITION BY HASH(a); +CREATE TABLE part_hp PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 2, REMAINDER 0); +ALTER TABLE hash_parted2 DETACH PARTITION part_hp CONCURRENTLY; +DROP TABLE hash_parted2; +INSERT INTO part_hp VALUES (1); +DROP TABLE part_hp; + -- Check ALTER TABLE commands for partitioned tables and partitions -- cannot add/drop column to/from *only* the parent @@ -3027,6 +3038,23 @@ drop table attbl, atref; /* End test case for bug #17409 */ +/* Test case for bug #18970 */ + +create table attbl(a int); +create table atref(b attbl check ((b).a is not null)); +alter table attbl alter column a type numeric; -- someday this should work +alter table atref drop constraint atref_b_check; + +create statistics atref_stat on ((b).a is not null) from atref; +alter table attbl alter column a type numeric; -- someday this should work +drop statistics atref_stat; + +create index atref_idx on atref (((b).a)); +alter table attbl alter column a type numeric; -- someday this should work +drop table attbl, atref; + +/* End test case for bug #18970 */ + -- Test that ALTER TABLE rewrite preserves a clustered index -- for normal indexes and indexes on constraints. create table alttype_cluster (a int); diff --git a/c_src/libpg_query/test/sql/postgres_regress/collate.icu.utf8.sql b/c_src/libpg_query/test/sql/postgres_regress/collate.icu.utf8.sql index 4eb1adf0..c797b518 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/collate.icu.utf8.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/collate.icu.utf8.sql @@ -508,7 +508,6 @@ DROP TABLE test7; CREATE COLLATION testcoll_rulesx (provider = icu, locale = '', rules = '!!wrong!!'); - -- nondeterministic collations CREATE COLLATION ctest_det (provider = icu, locale = '', deterministic = true); @@ -856,6 +855,20 @@ RESET enable_partitionwise_aggregate; RESET max_parallel_workers_per_gather; RESET enable_incremental_sort; +-- Check that DEFAULT expressions in SQL/JSON functions use the same collation +-- as the RETURNING type. Mismatched collations should raise an error. +CREATE DOMAIN d1 AS text COLLATE case_insensitive; +CREATE DOMAIN d2 AS text COLLATE "C"; +SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT ('C' COLLATE "C") COLLATE case_insensitive ON EMPTY) = 'a'; -- true +SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT 'C' ON EMPTY) = 'a'; -- true +SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT 'C'::d2 ON EMPTY) = 'a'; -- error +SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT 'C' COLLATE "C" ON EMPTY) = 'a'; -- error +SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A' ON EMPTY) = 'a'; -- true +SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A' COLLATE case_insensitive ON EMPTY) = 'a'; -- true +SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A'::d2 ON EMPTY) = 'a'; -- error +SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A' COLLATE "C" ON EMPTY) = 'a'; -- error +DROP DOMAIN d1, d2; + -- cleanup RESET search_path; SET client_min_messages TO warning; diff --git a/c_src/libpg_query/test/sql/postgres_regress/constraints.sql b/c_src/libpg_query/test/sql/postgres_regress/constraints.sql index e3e3bea7..b5e10f79 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/constraints.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/constraints.sql @@ -632,3 +632,14 @@ DROP DOMAIN constraint_comments_dom; DROP ROLE regress_constraint_comments; DROP ROLE regress_constraint_comments_noaccess; + +-- Leave some constraints for the pg_upgrade test to pick up +CREATE DOMAIN constraint_comments_dom AS int; + +ALTER DOMAIN constraint_comments_dom ADD CONSTRAINT inv_ck CHECK (value > 0) NOT VALID; +COMMENT ON CONSTRAINT inv_ck ON DOMAIN constraint_comments_dom IS 'comment on invalid constraint'; + +-- Create a table that exercises pg_upgrade +CREATE TABLE regress_notnull1 (a integer); +CREATE TABLE regress_notnull2 () INHERITS (regress_notnull1); +ALTER TABLE ONLY regress_notnull2 ALTER COLUMN a SET NOT NULL; diff --git a/c_src/libpg_query/test/sql/postgres_regress/conversion.sql b/c_src/libpg_query/test/sql/postgres_regress/conversion.sql index b567a1a5..a80d6236 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/conversion.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/conversion.sql @@ -300,11 +300,14 @@ insert into gb18030_inputs values ('\x666f6f84309c38', 'valid, translates to UTF-8 by mapping function'), ('\x666f6f84309c', 'incomplete char '), ('\x666f6f84309c0a', 'incomplete char, followed by newline '), + ('\x666f6f84', 'incomplete char at end'), ('\x666f6f84309c3800', 'invalid, NUL byte'), ('\x666f6f84309c0038', 'invalid, NUL byte'); --- Test GB18030 verification -select description, inbytes, (test_conv(inbytes, 'gb18030', 'gb18030')).* from gb18030_inputs; +-- Test GB18030 verification. Round-trip through text so the backing of the +-- bytea values is palloc, not shared_buffers. This lets Valgrind detect +-- reads past the end. +select description, inbytes, (test_conv(inbytes::text::bytea, 'gb18030', 'gb18030')).* from gb18030_inputs; -- Test conversions from GB18030 select description, inbytes, (test_conv(inbytes, 'gb18030', 'utf8')).* from gb18030_inputs; diff --git a/c_src/libpg_query/test/sql/postgres_regress/create_index.sql b/c_src/libpg_query/test/sql/postgres_regress/create_index.sql index e296891c..0c292cd6 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/create_index.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/create_index.sql @@ -629,7 +629,7 @@ DROP TABLE cwi_test; CREATE TABLE syscol_table (a INT); -- System columns cannot be indexed -CREATE INDEX ON syscolcol_table (ctid); +CREATE INDEX ON syscol_table (ctid); -- nor used in expressions CREATE INDEX ON syscol_table ((ctid >= '(1000,0)')); diff --git a/c_src/libpg_query/test/sql/postgres_regress/create_table.sql b/c_src/libpg_query/test/sql/postgres_regress/create_table.sql index 1fd4cbfa..8628d60b 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/create_table.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/create_table.sql @@ -62,6 +62,14 @@ CREATE TABLE withoid() WITH (oids = true); CREATE TEMP TABLE withoutoid() WITHOUT OIDS; DROP TABLE withoutoid; CREATE TEMP TABLE withoutoid() WITH (oids = false); DROP TABLE withoutoid; +-- temporary tables are ignored by pg_filenode_relation(). +CREATE TEMP TABLE relation_filenode_check(c1 int); +SELECT relpersistence, + pg_filenode_relation (reltablespace, pg_relation_filenode(oid)) + FROM pg_class + WHERE relname = 'relation_filenode_check'; +DROP TABLE relation_filenode_check; + -- check restriction with default expressions -- invalid use of column reference in default expressions CREATE TABLE default_expr_column (id int DEFAULT (id)); diff --git a/c_src/libpg_query/test/sql/postgres_regress/event_trigger.sql b/c_src/libpg_query/test/sql/postgres_regress/event_trigger.sql index 013546b8..c613c0cf 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/event_trigger.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/event_trigger.sql @@ -202,9 +202,15 @@ INSERT INTO undroppable_objs VALUES ('table', 'audit_tbls.schema_two_table_three'); CREATE TABLE dropped_objects ( - type text, - schema text, - object text + object_type text, + schema_name text, + object_name text, + object_identity text, + address_names text[], + address_args text[], + is_temporary bool, + original bool, + normal bool ); -- This tests errors raised within event triggers; the one in audit_tbls @@ -245,8 +251,12 @@ BEGIN END IF; INSERT INTO dropped_objects - (type, schema, object) VALUES - (obj.object_type, obj.schema_name, obj.object_identity); + (object_type, schema_name, object_name, + object_identity, address_names, address_args, + is_temporary, original, normal) VALUES + (obj.object_type, obj.schema_name, obj.object_name, + obj.object_identity, obj.address_names, obj.address_args, + obj.is_temporary, obj.original, obj.normal); END LOOP; END $$; @@ -263,10 +273,12 @@ DROP SCHEMA schema_one, schema_two CASCADE; DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three'; DROP SCHEMA schema_one, schema_two CASCADE; -SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast'; +-- exclude TOAST objects because they have unstable names +SELECT * FROM dropped_objects + WHERE schema_name IS NULL OR schema_name <> 'pg_toast'; DROP OWNED BY regress_evt_user; -SELECT * FROM dropped_objects WHERE type = 'schema'; +SELECT * FROM dropped_objects WHERE object_type = 'schema'; DROP ROLE regress_evt_user; @@ -285,9 +297,10 @@ BEGIN IF NOT r.normal AND NOT r.original THEN CONTINUE; END IF; - RAISE NOTICE 'NORMAL: orig=% normal=% istemp=% type=% identity=% name=% args=%', + RAISE NOTICE 'NORMAL: orig=% normal=% istemp=% type=% identity=% schema=% name=% addr=% args=%', r.original, r.normal, r.is_temporary, r.object_type, - r.object_identity, r.address_names, r.address_args; + r.object_identity, r.schema_name, r.object_name, + r.address_names, r.address_args; END LOOP; END; $$; CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop @@ -337,6 +350,46 @@ DROP INDEX evttrig.one_idx; DROP SCHEMA evttrig CASCADE; DROP TABLE a_temp_tbl; +-- check unfiltered results, too +CREATE OR REPLACE FUNCTION event_trigger_report_dropped() + RETURNS event_trigger + LANGUAGE plpgsql +AS $$ +DECLARE r record; +BEGIN + FOR r IN SELECT * from pg_event_trigger_dropped_objects() + LOOP + RAISE NOTICE 'DROP: orig=% normal=% istemp=% type=% identity=% schema=% name=% addr=% args=%', + r.original, r.normal, r.is_temporary, r.object_type, + r.object_identity, r.schema_name, r.object_name, + r.address_names, r.address_args; + END LOOP; +END; $$; + +CREATE FUNCTION event_trigger_dummy_trigger() + RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + RETURN new; +END; $$; + +CREATE TABLE evtrg_nontemp_table (f1 int primary key, f2 int default 42); +CREATE TRIGGER evtrg_nontemp_trig + BEFORE INSERT ON evtrg_nontemp_table + EXECUTE FUNCTION event_trigger_dummy_trigger(); +CREATE POLICY evtrg_nontemp_pol ON evtrg_nontemp_table USING (f2 > 0); +DROP TABLE evtrg_nontemp_table; + +CREATE TEMP TABLE a_temp_tbl (f1 int primary key, f2 int default 42); +CREATE TRIGGER a_temp_trig + BEFORE INSERT ON a_temp_tbl + EXECUTE FUNCTION event_trigger_dummy_trigger(); +CREATE POLICY a_temp_pol ON a_temp_tbl USING (f2 > 0); +DROP TABLE a_temp_tbl; + +DROP FUNCTION event_trigger_dummy_trigger(); + -- CREATE OPERATOR CLASS without FAMILY clause should report -- both CREATE OPERATOR FAMILY and CREATE OPERATOR CLASS CREATE OPERATOR CLASS evttrigopclass FOR TYPE int USING btree AS STORAGE int; diff --git a/c_src/libpg_query/test/sql/postgres_regress/foreign_key.sql b/c_src/libpg_query/test/sql/postgres_regress/foreign_key.sql index 6aa675c7..46bb9331 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/foreign_key.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/foreign_key.sql @@ -473,7 +473,8 @@ CREATE TABLE FKTABLE ( fk_id_del_set_null int, fk_id_del_set_default int DEFAULT 0, FOREIGN KEY (tid, fk_id_del_set_null) REFERENCES PKTABLE ON DELETE SET NULL (fk_id_del_set_null), - FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES PKTABLE ON DELETE SET DEFAULT (fk_id_del_set_default) + -- this tests handling of duplicate entries in SET DEFAULT column list + FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES PKTABLE ON DELETE SET DEFAULT (fk_id_del_set_default, fk_id_del_set_default) ); SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = 'fktable'::regclass::oid ORDER BY oid; @@ -1489,29 +1490,52 @@ CREATE TABLE part33_self_fk ( ); ALTER TABLE part3_self_fk ATTACH PARTITION part33_self_fk FOR VALUES FROM (30) TO (40); -SELECT cr.relname, co.conname, co.contype, co.convalidated, +-- verify that this constraint works +INSERT INTO parted_self_fk VALUES (1, NULL), (2, NULL), (3, NULL); +INSERT INTO parted_self_fk VALUES (10, 1), (11, 2), (12, 3) RETURNING tableoid::regclass; + +INSERT INTO parted_self_fk VALUES (4, 5); -- error: referenced doesn't exist +DELETE FROM parted_self_fk WHERE id = 1 RETURNING *; -- error: reference remains + +SELECT cr.relname, co.conname, co.convalidated, p.conname AS conparent, p.convalidated, cf.relname AS foreignrel FROM pg_constraint co JOIN pg_class cr ON cr.oid = co.conrelid LEFT JOIN pg_class cf ON cf.oid = co.confrelid LEFT JOIN pg_constraint p ON p.oid = co.conparentid -WHERE cr.oid IN (SELECT relid FROM pg_partition_tree('parted_self_fk')) -ORDER BY co.contype, cr.relname, co.conname, p.conname; +WHERE co.contype = 'f' AND + cr.oid IN (SELECT relid FROM pg_partition_tree('parted_self_fk')) +ORDER BY cr.relname, co.conname, p.conname; -- detach and re-attach multiple times just to ensure everything is kosher ALTER TABLE parted_self_fk DETACH PARTITION part2_self_fk; + +INSERT INTO part2_self_fk VALUES (16, 9); -- error: referenced doesn't exist +DELETE FROM parted_self_fk WHERE id = 2 RETURNING *; -- error: reference remains + ALTER TABLE parted_self_fk ATTACH PARTITION part2_self_fk FOR VALUES FROM (10) TO (20); + +INSERT INTO parted_self_fk VALUES (16, 9); -- error: referenced doesn't exist +DELETE FROM parted_self_fk WHERE id = 3 RETURNING *; -- error: reference remains + ALTER TABLE parted_self_fk DETACH PARTITION part2_self_fk; ALTER TABLE parted_self_fk ATTACH PARTITION part2_self_fk FOR VALUES FROM (10) TO (20); -SELECT cr.relname, co.conname, co.contype, co.convalidated, +ALTER TABLE parted_self_fk DETACH PARTITION part3_self_fk; +ALTER TABLE parted_self_fk ATTACH PARTITION part3_self_fk FOR VALUES FROM (30) TO (40); + +ALTER TABLE part3_self_fk DETACH PARTITION part33_self_fk; +ALTER TABLE part3_self_fk ATTACH PARTITION part33_self_fk FOR VALUES FROM (30) TO (40); + +SELECT cr.relname, co.conname, co.convalidated, p.conname AS conparent, p.convalidated, cf.relname AS foreignrel FROM pg_constraint co JOIN pg_class cr ON cr.oid = co.conrelid LEFT JOIN pg_class cf ON cf.oid = co.confrelid LEFT JOIN pg_constraint p ON p.oid = co.conparentid -WHERE cr.oid IN (SELECT relid FROM pg_partition_tree('parted_self_fk')) -ORDER BY co.contype, cr.relname, co.conname, p.conname; +WHERE co.contype = 'f' AND + cr.oid IN (SELECT relid FROM pg_partition_tree('parted_self_fk')) +ORDER BY cr.relname, co.conname, p.conname; -- Leave this table around, for pg_upgrade/pg_dump tests @@ -2157,3 +2181,51 @@ SET client_min_messages TO warning; DROP SCHEMA fkpart12 CASCADE; RESET client_min_messages; RESET search_path; + +-- Exercise the column mapping code with foreign keys. In this test we'll +-- create a partitioned table which has a partition with a dropped column and +-- check to ensure that an UPDATE cascades the changes correctly to the +-- partitioned table. +CREATE SCHEMA fkpart13; +SET search_path TO fkpart13; + +CREATE TABLE fkpart13_t1 (a int PRIMARY KEY); + +CREATE TABLE fkpart13_t2 ( + part_id int PRIMARY KEY, + column_to_drop int, + FOREIGN KEY (part_id) REFERENCES fkpart13_t1 ON UPDATE CASCADE ON DELETE CASCADE +) PARTITION BY LIST (part_id); + +CREATE TABLE fkpart13_t2_p1 PARTITION OF fkpart13_t2 FOR VALUES IN (1); + +-- drop the column +ALTER TABLE fkpart13_t2 DROP COLUMN column_to_drop; + +-- create a new partition without the dropped column +CREATE TABLE fkpart13_t2_p2 PARTITION OF fkpart13_t2 FOR VALUES IN (2); + +CREATE TABLE fkpart13_t3 ( + a int NOT NULL, + FOREIGN KEY (a) + REFERENCES fkpart13_t2 + ON UPDATE CASCADE ON DELETE CASCADE +); + +INSERT INTO fkpart13_t1 (a) VALUES (1); +INSERT INTO fkpart13_t2 (part_id) VALUES (1); +INSERT INTO fkpart13_t3 (a) VALUES (1); + +-- Test a cascading update works correctly with with the dropped column +UPDATE fkpart13_t1 SET a = 2 WHERE a = 1; +SELECT tableoid::regclass,* FROM fkpart13_t2; +SELECT tableoid::regclass,* FROM fkpart13_t3; + +-- Exercise code in ExecGetTriggerResultRel() as there's been previous issues +-- with ResultRelInfos being returned with the incorrect ri_RootResultRelInfo +WITH cte AS ( + UPDATE fkpart13_t2_p1 SET part_id = part_id +) UPDATE fkpart13_t1 SET a = 2 WHERE a = 1; + +DROP SCHEMA fkpart13 CASCADE; +RESET search_path; diff --git a/c_src/libpg_query/test/sql/postgres_regress/generated.sql b/c_src/libpg_query/test/sql/postgres_regress/generated.sql index cb55d778..9152e191 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/generated.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/generated.sql @@ -199,6 +199,10 @@ COPY gtest1 FROM stdin; COPY gtest1 (a, b) FROM stdin; +COPY gtest1 FROM stdin WHERE b <> 10; + +COPY gtest1 FROM stdin WHERE gtest1 IS NULL; + SELECT * FROM gtest1 ORDER BY a; TRUNCATE gtest3; @@ -387,6 +391,11 @@ CREATE TABLE gtest24 (a int PRIMARY KEY, b gtestdomain1 GENERATED ALWAYS AS (a * INSERT INTO gtest24 (a) VALUES (4); -- ok INSERT INTO gtest24 (a) VALUES (6); -- error +CREATE DOMAIN gtestdomainnn AS int CHECK (VALUE IS NOT NULL); +CREATE TABLE gtest24nn (a int, b gtestdomainnn GENERATED ALWAYS AS (a * 2) STORED); +INSERT INTO gtest24nn (a) VALUES (4); -- ok +INSERT INTO gtest24nn (a) VALUES (NULL); -- error + -- typed tables (currently not supported) CREATE TYPE gtest_type AS (f1 integer, f2 text, f3 bigint); CREATE TABLE gtest28 OF gtest_type (f1 WITH OPTIONS GENERATED ALWAYS AS (f2 *2) STORED); @@ -454,7 +463,10 @@ SELECT tableoid::regclass, * FROM gtest_parent ORDER BY 1, 2, 3; -- generated columns in partition key (not allowed) CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE (f3); +CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((f3)); CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((f3 * 3)); +CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((gtest_part_key)); +CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((gtest_part_key is not null)); -- ALTER TABLE ... ADD COLUMN CREATE TABLE gtest25 (a int PRIMARY KEY); @@ -545,6 +557,31 @@ ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION; -- error \d gtest30_1 ALTER TABLE gtest30_1 ALTER COLUMN b DROP EXPRESSION; -- error +-- composite type dependencies +CREATE TABLE gtest31_1 (a int, b text GENERATED ALWAYS AS ('hello') STORED, c text); +CREATE TABLE gtest31_2 (x int, y gtest31_1); +ALTER TABLE gtest31_1 ALTER COLUMN b TYPE varchar; -- fails + +-- bug #18970: these cases are unsupported, but make sure they fail cleanly +ALTER TABLE gtest31_2 ADD CONSTRAINT cc CHECK ((y).b IS NOT NULL); +ALTER TABLE gtest31_1 ALTER COLUMN b SET EXPRESSION AS ('hello1'); +ALTER TABLE gtest31_2 DROP CONSTRAINT cc; + +CREATE STATISTICS gtest31_2_stat ON ((y).b is not null) FROM gtest31_2; +ALTER TABLE gtest31_1 ALTER COLUMN b SET EXPRESSION AS ('hello2'); +DROP STATISTICS gtest31_2_stat; + +CREATE INDEX gtest31_2_y_idx ON gtest31_2(((y).b)); +ALTER TABLE gtest31_1 ALTER COLUMN b SET EXPRESSION AS ('hello3'); + +DROP TABLE gtest31_1, gtest31_2; + +-- Check it for a partitioned table, too +CREATE TABLE gtest31_1 (a int, b text GENERATED ALWAYS AS ('hello') STORED, c text) PARTITION BY LIST (a); +CREATE TABLE gtest31_2 (x int, y gtest31_1); +ALTER TABLE gtest31_1 ALTER COLUMN b TYPE varchar; -- fails +DROP TABLE gtest31_1, gtest31_2; + -- triggers CREATE TABLE gtest26 ( a int PRIMARY KEY, diff --git a/c_src/libpg_query/test/sql/postgres_regress/inherit.sql b/c_src/libpg_query/test/sql/postgres_regress/inherit.sql index 51251b0e..572512cb 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/inherit.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/inherit.sql @@ -377,8 +377,9 @@ CREATE TABLE inhta (); CREATE TABLE inhtb () INHERITS (inhta); CREATE TABLE inhtc () INHERITS (inhtb); CREATE TABLE inhtd () INHERITS (inhta, inhtb, inhtc); -ALTER TABLE inhta ADD COLUMN i int; +ALTER TABLE inhta ADD COLUMN i int, ADD COLUMN j bigint DEFAULT 1; \d+ inhta +\d+ inhtd DROP TABLE inhta, inhtb, inhtc, inhtd; -- Test for renaming in diamond inheritance diff --git a/c_src/libpg_query/test/sql/postgres_regress/limit.sql b/c_src/libpg_query/test/sql/postgres_regress/limit.sql index 6f0cda98..603910fe 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/limit.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/limit.sql @@ -196,6 +196,9 @@ CREATE VIEW limit_thousand_v_3 AS SELECT thousand FROM onek WHERE thousand < 995 ORDER BY thousand FETCH FIRST (NULL+1) ROWS WITH TIES; \d+ limit_thousand_v_3 CREATE VIEW limit_thousand_v_4 AS SELECT thousand FROM onek WHERE thousand < 995 - ORDER BY thousand FETCH FIRST NULL ROWS ONLY; + ORDER BY thousand FETCH FIRST (5::bigint) ROWS WITH TIES; \d+ limit_thousand_v_4 +CREATE VIEW limit_thousand_v_5 AS SELECT thousand FROM onek WHERE thousand < 995 + ORDER BY thousand FETCH FIRST NULL ROWS ONLY; +\d+ limit_thousand_v_5 -- leave these views diff --git a/c_src/libpg_query/test/sql/postgres_regress/maintain_every.sql b/c_src/libpg_query/test/sql/postgres_regress/maintain_every.sql new file mode 100644 index 00000000..263e9727 --- /dev/null +++ b/c_src/libpg_query/test/sql/postgres_regress/maintain_every.sql @@ -0,0 +1,26 @@ +-- Test maintenance commands that visit every eligible relation. Run as a +-- non-superuser, to skip other users' tables. + +CREATE ROLE regress_maintain; +SET ROLE regress_maintain; + +-- Test database-wide ANALYZE ("use_own_xacts" mode) setting relhassubclass=f +-- for non-partitioning inheritance, w/ ON COMMIT DELETE ROWS building an +-- empty index. +CREATE TEMP TABLE past_inh_db_other (); -- need 2 tables for "use_own_xacts" +CREATE TEMP TABLE past_inh_db_parent () ON COMMIT DELETE ROWS; +CREATE TEMP TABLE past_inh_db_child () INHERITS (past_inh_db_parent); +CREATE INDEX ON past_inh_db_parent ((1)); +ANALYZE past_inh_db_parent; +SELECT reltuples, relhassubclass + FROM pg_class WHERE oid = 'past_inh_db_parent'::regclass; +DROP TABLE past_inh_db_child; +SET client_min_messages = error; -- hide WARNINGs for other users' tables +ANALYZE; +RESET client_min_messages; +SELECT reltuples, relhassubclass + FROM pg_class WHERE oid = 'past_inh_db_parent'::regclass; +DROP TABLE past_inh_db_parent, past_inh_db_other; + +RESET ROLE; +DROP ROLE regress_maintain; diff --git a/c_src/libpg_query/test/sql/postgres_regress/merge.sql b/c_src/libpg_query/test/sql/postgres_regress/merge.sql index 556777e4..d8ac0a4d 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/merge.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/merge.sql @@ -1720,6 +1720,55 @@ WHEN MATCHED THEN DELETE; SELECT * FROM new_measurement ORDER BY city_id, logdate; +-- MERGE into inheritance root table +DROP TRIGGER insert_measurement_trigger ON measurement; +ALTER TABLE measurement ADD CONSTRAINT mcheck CHECK (city_id = 0) NO INHERIT; + +EXPLAIN (COSTS OFF) +MERGE INTO measurement m + USING (VALUES (1, '01-17-2007'::date)) nm(city_id, logdate) ON + (m.city_id = nm.city_id and m.logdate=nm.logdate) +WHEN NOT MATCHED THEN INSERT + (city_id, logdate, peaktemp, unitsales) + VALUES (city_id - 1, logdate, 25, 100); + +BEGIN; +MERGE INTO measurement m + USING (VALUES (1, '01-17-2007'::date)) nm(city_id, logdate) ON + (m.city_id = nm.city_id and m.logdate=nm.logdate) +WHEN NOT MATCHED THEN INSERT + (city_id, logdate, peaktemp, unitsales) + VALUES (city_id - 1, logdate, 25, 100); +SELECT * FROM ONLY measurement ORDER BY city_id, logdate; +ROLLBACK; + +ALTER TABLE measurement ENABLE ROW LEVEL SECURITY; +ALTER TABLE measurement FORCE ROW LEVEL SECURITY; +CREATE POLICY measurement_p ON measurement USING (peaktemp IS NOT NULL); + +MERGE INTO measurement m + USING (VALUES (1, '01-17-2007'::date)) nm(city_id, logdate) ON + (m.city_id = nm.city_id and m.logdate=nm.logdate) +WHEN NOT MATCHED THEN INSERT + (city_id, logdate, peaktemp, unitsales) + VALUES (city_id - 1, logdate, NULL, 100); -- should fail + +MERGE INTO measurement m + USING (VALUES (1, '01-17-2007'::date)) nm(city_id, logdate) ON + (m.city_id = nm.city_id and m.logdate=nm.logdate) +WHEN NOT MATCHED THEN INSERT + (city_id, logdate, peaktemp, unitsales) + VALUES (city_id - 1, logdate, 25, 100); -- ok +SELECT * FROM ONLY measurement ORDER BY city_id, logdate; + +MERGE INTO measurement m + USING (VALUES (1, '01-18-2007'::date)) nm(city_id, logdate) ON + (m.city_id = nm.city_id and m.logdate=nm.logdate) +WHEN NOT MATCHED THEN INSERT + (city_id, logdate, peaktemp, unitsales) + VALUES (city_id - 1, logdate, 25, 200) +RETURNING merge_action(), m.*; + DROP TABLE measurement, new_measurement CASCADE; DROP FUNCTION measurement_insert_trigger(); diff --git a/c_src/libpg_query/test/sql/postgres_regress/privileges.sql b/c_src/libpg_query/test/sql/postgres_regress/privileges.sql index b7e1cb6c..0b417955 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/privileges.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/privileges.sql @@ -325,8 +325,6 @@ CREATE VIEW atest12v AS SELECT * FROM atest12 WHERE b <<< 5; CREATE VIEW atest12sbv WITH (security_barrier=true) AS SELECT * FROM atest12 WHERE b <<< 5; -GRANT SELECT ON atest12v TO PUBLIC; -GRANT SELECT ON atest12sbv TO PUBLIC; -- This plan should use nestloop, knowing that few rows will be selected. EXPLAIN (COSTS OFF) SELECT * FROM atest12v x, atest12v y WHERE x.a = y.b; @@ -348,8 +346,16 @@ CREATE FUNCTION leak2(integer,integer) RETURNS boolean CREATE OPERATOR >>> (procedure = leak2, leftarg = integer, rightarg = integer, restrict = scalargtsel); --- This should not show any "leak" notices before failing. +-- These should not show any "leak" notices before failing. EXPLAIN (COSTS OFF) SELECT * FROM atest12 WHERE a >>> 0; +EXPLAIN (COSTS OFF) SELECT * FROM atest12v WHERE a >>> 0; +EXPLAIN (COSTS OFF) SELECT * FROM atest12sbv WHERE a >>> 0; + +-- Now regress_priv_user1 grants access to regress_priv_user2 via the views. +SET SESSION AUTHORIZATION regress_priv_user1; +GRANT SELECT ON atest12v TO PUBLIC; +GRANT SELECT ON atest12sbv TO PUBLIC; +SET SESSION AUTHORIZATION regress_priv_user2; -- These plans should continue to use a nestloop, since they execute with the -- privileges of the view owner. @@ -1481,6 +1487,14 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole, SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole, 'SELECT, fake_privilege', FALSE); -- error +-- Test quoting and dequoting of user names in ACLs +CREATE ROLE "regress_""quoted"; +SELECT makeaclitem('regress_"quoted'::regrole, 'regress_"quoted'::regrole, + 'SELECT', TRUE); +SELECT '"regress_""quoted"=r*/"regress_""quoted"'::aclitem; +SELECT '""=r*/""'::aclitem; -- used to be misparsed as """" +DROP ROLE "regress_""quoted"; + -- Test non-throwing aclitem I/O SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem'); SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem'); @@ -1750,6 +1764,13 @@ DROP USER regress_priv_user7; DROP USER regress_priv_user8; -- does not exist +-- leave some default ACLs for pg_upgrade's dump-restore test input. +ALTER DEFAULT PRIVILEGES FOR ROLE pg_signal_backend + REVOKE USAGE ON TYPES FROM pg_signal_backend; +ALTER DEFAULT PRIVILEGES FOR ROLE pg_read_all_settings + REVOKE USAGE ON TYPES FROM pg_read_all_settings; + + -- permissions with LOCK TABLE CREATE USER regress_locktable_user; CREATE TABLE lock_table (a int); diff --git a/c_src/libpg_query/test/sql/postgres_regress/psql.sql b/c_src/libpg_query/test/sql/postgres_regress/psql.sql index 3b3c6f6e..f8ad7af5 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/psql.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/psql.sql @@ -1025,6 +1025,7 @@ select \if false \\ (bogus \else \\ 42 \endif \\ forty_two; \pset arg1 arg2 \q \reset + \restrict test \s arg1 \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 \setenv arg1 arg2 @@ -1033,6 +1034,7 @@ select \if false \\ (bogus \else \\ 42 \endif \\ forty_two; \t arg1 \T arg1 \timing arg1 + \unrestrict not_valid \unset arg1 \w arg1 \watch arg1 arg2 diff --git a/c_src/libpg_query/test/sql/postgres_regress/publication.sql b/c_src/libpg_query/test/sql/postgres_regress/publication.sql index 479d4f32..cd2795d0 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/publication.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/publication.sql @@ -1106,6 +1106,85 @@ DROP TABLE sch1.tbl1; DROP SCHEMA sch1 cascade; DROP SCHEMA sch2 cascade; +-- Test that the INSERT ON CONFLICT command correctly checks REPLICA IDENTITY +-- when the target table is published. +CREATE TABLE testpub_insert_onconfl_no_ri (a int unique, b int); +CREATE TABLE testpub_insert_onconfl_parted (a int unique, b int) PARTITION by RANGE (a); +CREATE TABLE testpub_insert_onconfl_part_no_ri PARTITION OF testpub_insert_onconfl_parted FOR VALUES FROM (1) TO (10); + +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION pub1 FOR ALL TABLES; +RESET client_min_messages; + +-- fail - missing REPLICA IDENTITY +INSERT INTO testpub_insert_onconfl_no_ri VALUES (1, 1) ON CONFLICT (a) DO UPDATE SET b = 2; + +-- ok - no updates +INSERT INTO testpub_insert_onconfl_no_ri VALUES (1, 1) ON CONFLICT DO NOTHING; + +-- fail - missing REPLICA IDENTITY in partition testpub_insert_onconfl_no_ri +INSERT INTO testpub_insert_onconfl_parted VALUES (1, 1) ON CONFLICT (a) DO UPDATE SET b = 2; + +-- ok - no updates +INSERT INTO testpub_insert_onconfl_parted VALUES (1, 1) ON CONFLICT DO NOTHING; + +DROP PUBLICATION pub1; +DROP TABLE testpub_insert_onconfl_no_ri; +DROP TABLE testpub_insert_onconfl_parted; + +-- Test that the MERGE command correctly checks REPLICA IDENTITY when the +-- target table is published. +CREATE TABLE testpub_merge_no_ri (a int, b int); +CREATE TABLE testpub_merge_pk (a int primary key, b int); + +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION pub1 FOR ALL TABLES; +RESET client_min_messages; + +-- fail - missing REPLICA IDENTITY +MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1 + WHEN MATCHED THEN UPDATE SET b = s.b; + +-- fail - missing REPLICA IDENTITY +MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1 + WHEN MATCHED THEN DELETE; + +-- ok - insert and do nothing are not restricted +MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1 + WHEN MATCHED THEN DO NOTHING + WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, 0); + +-- ok - REPLICA IDENTITY is DEFAULT and table has a PK +MERGE INTO testpub_merge_pk USING testpub_merge_no_ri s ON s.a >= 1 + WHEN MATCHED AND s.a > 0 THEN UPDATE SET b = s.b + WHEN MATCHED THEN DELETE; + +DROP PUBLICATION pub1; +DROP TABLE testpub_merge_no_ri; +DROP TABLE testpub_merge_pk; + RESET SESSION AUTHORIZATION; DROP ROLE regress_publication_user, regress_publication_user2; DROP ROLE regress_publication_user_dummy; + +-- stage objects for pg_dump tests +CREATE SCHEMA pubme CREATE TABLE t0 (c int, d int) CREATE TABLE t1 (c int); +CREATE SCHEMA pubme2 CREATE TABLE t0 (c int, d int); +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION dump_pub_qual_1ct FOR + TABLE ONLY pubme.t0 (c, d) WHERE (c > 0); +CREATE PUBLICATION dump_pub_qual_2ct FOR + TABLE ONLY pubme.t0 (c) WHERE (c > 0), + TABLE ONLY pubme.t1 (c); +CREATE PUBLICATION dump_pub_nsp_1ct FOR + TABLES IN SCHEMA pubme; +CREATE PUBLICATION dump_pub_nsp_2ct FOR + TABLES IN SCHEMA pubme, + TABLES IN SCHEMA pubme2; +CREATE PUBLICATION dump_pub_all FOR + TABLE ONLY pubme.t0, + TABLE ONLY pubme.t1 WHERE (c < 0), + TABLES IN SCHEMA pubme, + TABLES IN SCHEMA pubme2 + WITH (publish_via_partition_root = true); +RESET client_min_messages; diff --git a/c_src/libpg_query/test/sql/postgres_regress/rowsecurity.sql b/c_src/libpg_query/test/sql/postgres_regress/rowsecurity.sql index eab7d990..6e71dc72 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/rowsecurity.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/rowsecurity.sql @@ -2162,7 +2162,7 @@ DROP VIEW rls_view; DROP TABLE rls_tbl; DROP TABLE ref_tbl; --- Leaky operator test +-- Leaky operator tests CREATE TABLE rls_tbl (a int); INSERT INTO rls_tbl SELECT x/10 FROM generate_series(1, 100) x; ANALYZE rls_tbl; @@ -2177,9 +2177,58 @@ CREATE FUNCTION op_leak(int, int) RETURNS bool CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int, restrict = scalarltsel); SELECT * FROM rls_tbl WHERE a <<< 1000; +RESET SESSION AUTHORIZATION; + +CREATE TABLE rls_child_tbl () INHERITS (rls_tbl); +INSERT INTO rls_child_tbl SELECT x/10 FROM generate_series(1, 100) x; +ANALYZE rls_child_tbl; + +CREATE TABLE rls_ptbl (a int) PARTITION BY RANGE (a); +CREATE TABLE rls_part PARTITION OF rls_ptbl FOR VALUES FROM (-100) TO (100); +INSERT INTO rls_ptbl SELECT x/10 FROM generate_series(1, 100) x; +ANALYZE rls_ptbl, rls_part; + +ALTER TABLE rls_ptbl ENABLE ROW LEVEL SECURITY; +ALTER TABLE rls_part ENABLE ROW LEVEL SECURITY; +GRANT SELECT ON rls_ptbl TO regress_rls_alice; +GRANT SELECT ON rls_part TO regress_rls_alice; +CREATE POLICY p1 ON rls_tbl USING (a < 0); +CREATE POLICY p2 ON rls_ptbl USING (a < 0); +CREATE POLICY p3 ON rls_part USING (a < 0); + +SET SESSION AUTHORIZATION regress_rls_alice; +SELECT * FROM rls_tbl WHERE a <<< 1000; +SELECT * FROM rls_child_tbl WHERE a <<< 1000; +SELECT * FROM rls_ptbl WHERE a <<< 1000; +SELECT * FROM rls_part WHERE a <<< 1000; +SELECT * FROM (SELECT * FROM rls_tbl UNION ALL + SELECT * FROM rls_tbl) t WHERE a <<< 1000; +SELECT * FROM (SELECT * FROM rls_child_tbl UNION ALL + SELECT * FROM rls_child_tbl) t WHERE a <<< 1000; +RESET SESSION AUTHORIZATION; + +REVOKE SELECT ON rls_tbl FROM regress_rls_alice; +CREATE VIEW rls_tbl_view AS SELECT * FROM rls_tbl; + +ALTER TABLE rls_child_tbl ENABLE ROW LEVEL SECURITY; +GRANT SELECT ON rls_child_tbl TO regress_rls_alice; +CREATE POLICY p4 ON rls_child_tbl USING (a < 0); + +SET SESSION AUTHORIZATION regress_rls_alice; +SELECT * FROM rls_tbl WHERE a <<< 1000; +SELECT * FROM rls_tbl_view WHERE a <<< 1000; +SELECT * FROM rls_child_tbl WHERE a <<< 1000; +SELECT * FROM (SELECT * FROM rls_tbl UNION ALL + SELECT * FROM rls_tbl) t WHERE a <<< 1000; +SELECT * FROM (SELECT * FROM rls_child_tbl UNION ALL + SELECT * FROM rls_child_tbl) t WHERE a <<< 1000; DROP OPERATOR <<< (int, int); DROP FUNCTION op_leak(int, int); RESET SESSION AUTHORIZATION; +DROP TABLE rls_part; +DROP TABLE rls_ptbl; +DROP TABLE rls_child_tbl; +DROP VIEW rls_tbl_view; DROP TABLE rls_tbl; -- Bug #16006: whole-row Vars in a policy don't play nice with sub-selects diff --git a/c_src/libpg_query/test/sql/postgres_regress/sqljson.sql b/c_src/libpg_query/test/sql/postgres_regress/sqljson.sql index 3fd6ac26..343d344d 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/sqljson.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/sqljson.sql @@ -199,6 +199,8 @@ SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL) --SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL); --SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb); SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i); +SELECT JSON_ARRAY(WITH x AS (SELECT 1) VALUES (TRUE)); + -- Should fail SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i)); SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i)); diff --git a/c_src/libpg_query/test/sql/postgres_regress/stats_ext.sql b/c_src/libpg_query/test/sql/postgres_regress/stats_ext.sql index 0c08a6cc..0c204157 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/stats_ext.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/stats_ext.sql @@ -40,6 +40,18 @@ CREATE STATISTICS tst ON x, x, y, x, x, (x || 'x'), (y + 1), (x || 'x'), (x || ' CREATE STATISTICS tst ON (x || 'x'), (x || 'x'), (y + 1), (x || 'x'), (x || 'x'), (y + 1), (x || 'x'), (x || 'x'), (y + 1) FROM ext_stats_test; CREATE STATISTICS tst ON (x || 'x'), (x || 'x'), y FROM ext_stats_test; CREATE STATISTICS tst (unrecognized) ON x, y FROM ext_stats_test; +-- unsupported targets +CREATE STATISTICS tst ON a FROM (VALUES (x)) AS foo; +CREATE STATISTICS tst ON a FROM foo NATURAL JOIN bar; +CREATE STATISTICS tst ON a FROM (SELECT * FROM ext_stats_test) AS foo; +CREATE STATISTICS tst ON a FROM ext_stats_test s TABLESAMPLE system (x); +CREATE STATISTICS tst ON a FROM XMLTABLE('foo' PASSING 'bar' COLUMNS a text); +CREATE STATISTICS tst ON a FROM JSON_TABLE(jsonb '123', '$' COLUMNS (item int)); +CREATE FUNCTION tftest(int) returns table(a int, b int) as $$ +SELECT $1, $1+i FROM generate_series(1,5) g(i); +$$ LANGUAGE sql IMMUTABLE STRICT; +CREATE STATISTICS alt_stat2 ON a FROM tftest(1); +DROP FUNCTION tftest; -- incorrect expressions CREATE STATISTICS tst ON (y) FROM ext_stats_test; -- single column reference CREATE STATISTICS tst ON y + z FROM ext_stats_test; -- missing parentheses @@ -57,6 +69,14 @@ DROP STATISTICS ab1_a_b_stats; ALTER STATISTICS ab1_a_b_stats RENAME TO ab1_a_b_stats_new; RESET SESSION AUTHORIZATION; DROP ROLE regress_stats_ext; +CREATE STATISTICS pg_temp.stats_ext_temp ON a, b FROM ab1; +SELECT regexp_replace(pg_describe_object(tableoid, oid, 0), + 'pg_temp_[0-9]*', 'pg_temp_REDACTED') AS descr, + pg_statistics_obj_is_visible(oid) AS visible + FROM pg_statistic_ext + WHERE stxname = 'stats_ext_temp'; +DROP STATISTICS stats_ext_temp; -- shall fail +DROP STATISTICS pg_temp.stats_ext_temp; CREATE STATISTICS IF NOT EXISTS ab1_a_b_stats ON a, b FROM ab1; DROP STATISTICS ab1_a_b_stats; @@ -1633,7 +1653,14 @@ CREATE FUNCTION op_leak(int, int) RETURNS bool LANGUAGE plpgsql; CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int, restrict = scalarltsel); +CREATE FUNCTION op_leak(record, record) RETURNS bool + AS 'BEGIN RAISE NOTICE ''op_leak => %, %'', $1, $2; RETURN $1 < $2; END' + LANGUAGE plpgsql; +CREATE OPERATOR <<< (procedure = op_leak, leftarg = record, rightarg = record, + restrict = scalarltsel); SELECT * FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Permission denied +SELECT * FROM tststats.priv_test_tbl t + WHERE a <<< 0 AND (b <<< 0 OR t.* <<< (1, 1) IS NOT NULL); -- Permission denied DELETE FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Permission denied -- Grant access via a security barrier view, but hide all data @@ -1645,18 +1672,48 @@ GRANT SELECT, DELETE ON tststats.priv_test_view TO regress_stats_user1; -- Should now have access via the view, but see nothing and leak nothing SET SESSION AUTHORIZATION regress_stats_user1; SELECT * FROM tststats.priv_test_view WHERE a <<< 0 AND b <<< 0; -- Should not leak +SELECT * FROM tststats.priv_test_view t + WHERE a <<< 0 AND (b <<< 0 OR t.* <<< (1, 1) IS NOT NULL); -- Should not leak DELETE FROM tststats.priv_test_view WHERE a <<< 0 AND b <<< 0; -- Should not leak -- Grant table access, but hide all data with RLS RESET SESSION AUTHORIZATION; ALTER TABLE tststats.priv_test_tbl ENABLE ROW LEVEL SECURITY; +CREATE POLICY priv_test_tbl_pol ON tststats.priv_test_tbl USING (2 * a < 0); GRANT SELECT, DELETE ON tststats.priv_test_tbl TO regress_stats_user1; -- Should now have direct table access, but see nothing and leak nothing SET SESSION AUTHORIZATION regress_stats_user1; SELECT * FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak +SELECT * FROM tststats.priv_test_tbl t + WHERE a <<< 0 AND (b <<< 0 OR t.* <<< (1, 1) IS NOT NULL); -- Should not leak DELETE FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak +-- Create plain inheritance parent table with no access permissions +RESET SESSION AUTHORIZATION; +CREATE TABLE tststats.priv_test_parent_tbl (a int, b int); +ALTER TABLE tststats.priv_test_tbl INHERIT tststats.priv_test_parent_tbl; + +-- Should not have access to parent, and should leak nothing +SET SESSION AUTHORIZATION regress_stats_user1; +SELECT * FROM tststats.priv_test_parent_tbl WHERE a <<< 0 AND b <<< 0; -- Permission denied +SELECT * FROM tststats.priv_test_parent_tbl t + WHERE a <<< 0 AND (b <<< 0 OR t.* <<< (1, 1) IS NOT NULL); -- Permission denied +DELETE FROM tststats.priv_test_parent_tbl WHERE a <<< 0 AND b <<< 0; -- Permission denied + +-- Grant table access to parent, but hide all data with RLS +RESET SESSION AUTHORIZATION; +ALTER TABLE tststats.priv_test_parent_tbl ENABLE ROW LEVEL SECURITY; +CREATE POLICY priv_test_parent_tbl_pol ON tststats.priv_test_parent_tbl USING (2 * a < 0); +GRANT SELECT, DELETE ON tststats.priv_test_parent_tbl TO regress_stats_user1; + +-- Should now have direct table access to parent, but see nothing and leak nothing +SET SESSION AUTHORIZATION regress_stats_user1; +SELECT * FROM tststats.priv_test_parent_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak +SELECT * FROM tststats.priv_test_parent_tbl t + WHERE a <<< 0 AND (b <<< 0 OR t.* <<< (1, 1) IS NOT NULL); -- Should not leak +DELETE FROM tststats.priv_test_parent_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak + -- privilege checks for pg_stats_ext and pg_stats_ext_exprs RESET SESSION AUTHORIZATION; CREATE TABLE stats_ext_tbl (id INT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, col TEXT); @@ -1683,10 +1740,46 @@ SELECT statistics_name, most_common_vals FROM pg_stats_ext x SELECT statistics_name, most_common_vals FROM pg_stats_ext_exprs x WHERE tablename = 'stats_ext_tbl' ORDER BY ROW(x.*); +-- CREATE STATISTICS checks for CREATE on the schema +RESET SESSION AUTHORIZATION; +CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT, c INT GENERATED ALWAYS AS (b * 2) STORED); +CREATE SCHEMA sts_sch2; +GRANT USAGE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1; +ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.fail ON a, b, c FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.fail ON a, b, c FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +REVOKE CREATE ON SCHEMA sts_sch1 FROM regress_stats_user1; +GRANT CREATE ON SCHEMA sts_sch2 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.pass1 ON a, b, c FROM sts_sch1.tbl; +RESET SESSION AUTHORIZATION; +GRANT CREATE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl; +CREATE STATISTICS sts_sch2.pass2 ON a, b, c FROM sts_sch1.tbl; + +-- re-creating statistics via ALTER TABLE bypasses checks for CREATE on schema +RESET SESSION AUTHORIZATION; +REVOKE CREATE ON SCHEMA sts_sch1, sts_sch2 FROM regress_stats_user1; +SET SESSION AUTHORIZATION regress_stats_user1; +ALTER TABLE sts_sch1.tbl ALTER COLUMN a TYPE SMALLINT; +ALTER TABLE sts_sch1.tbl ALTER COLUMN c SET EXPRESSION AS (a * 3); + -- Tidy up DROP OPERATOR <<< (int, int); DROP FUNCTION op_leak(int, int); +DROP OPERATOR <<< (record, record); +DROP FUNCTION op_leak(record, record); RESET SESSION AUTHORIZATION; DROP TABLE stats_ext_tbl; DROP SCHEMA tststats CASCADE; +DROP SCHEMA sts_sch1, sts_sch2 CASCADE; DROP USER regress_stats_user1; diff --git a/c_src/libpg_query/test/sql/postgres_regress/strings.sql b/c_src/libpg_query/test/sql/postgres_regress/strings.sql index 39596789..6c1dbe50 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/strings.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/strings.sql @@ -193,6 +193,29 @@ SELECT 'abcd\efg' SIMILAR TO '_bcd\%' ESCAPE '' AS true; SELECT 'abcdefg' SIMILAR TO '_bcd%' ESCAPE NULL AS null; SELECT 'abcdefg' SIMILAR TO '_bcd#%' ESCAPE '##' AS error; +-- Characters that should be left alone in character classes when a +-- SIMILAR TO regexp pattern is converted to POSIX style. +-- Underscore "_" +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '_[_[:alpha:]_]_'; +-- Percentage "%" +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '%[%[:alnum:]%]%'; +-- Dot "." +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '.[.[:alnum:].].'; +-- Dollar "$" +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '$[$[:alnum:]$]$'; +-- Opening parenthesis "(" +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '()[([:alnum:](]()'; +-- Caret "^" +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '^[^[:alnum:]^[^^][[^^]][\^][[\^]]\^]^'; +-- Closing square bracket "]" at the beginning of character class +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '[]%][^]%][^%]%'; +-- Closing square bracket effective after two carets at the beginning +-- of character class. +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '[^^]^'; +-- Closing square bracket after an escape sequence at the beginning of +-- a character closes the character class +EXPLAIN (COSTS OFF) SELECT * FROM TEXT_TBL WHERE f1 SIMILAR TO '[|a]%' ESCAPE '|'; + -- Test backslash escapes in regexp_replace's replacement string SELECT regexp_replace('1112223333', E'(\\d{3})(\\d{3})(\\d{4})', E'(\\1) \\2-\\3'); SELECT regexp_replace('foobarrbazz', E'(.)\\1', E'X\\&Y', 'g'); diff --git a/c_src/libpg_query/test/sql/postgres_regress/subselect.sql b/c_src/libpg_query/test/sql/postgres_regress/subselect.sql index e5a562c3..583cbd62 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/subselect.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/subselect.sql @@ -412,6 +412,15 @@ select (select view_a) from view_a; select (select (select view_a)) from view_a; select (select (a.*)::text) from view_a a; +-- +-- Test case for bug #19037: no relation entry for relid N +-- + +explain (costs off) +select (1 = any(array_agg(f1))) = any (select false) from int4_tbl; + +select (1 = any(array_agg(f1))) = any (select false) from int4_tbl; + -- -- Check that whole-row Vars reading the result of a subselect don't include -- any junk columns therein @@ -890,6 +899,23 @@ fetch backward all in c1; commit; +-- +-- Check that JsonConstructorExpr is treated as non-strict, and thus can be +-- wrapped in a PlaceHolderVar +-- + +begin; + +create temp table json_tab (a int); +insert into json_tab values (1); + +explain (verbose, costs off) +select * from json_tab t1 left join (select json_array(1, a) from json_tab t2) s on false; + +select * from json_tab t1 left join (select json_array(1, a) from json_tab t2) s on false; + +rollback; + -- -- Verify that we correctly flatten cases involving a subquery output -- expression that doesn't need to be wrapped in a PlaceHolderVar diff --git a/c_src/libpg_query/test/sql/postgres_regress/triggers.sql b/c_src/libpg_query/test/sql/postgres_regress/triggers.sql index a3c3115a..5a0fa012 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/triggers.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/triggers.sql @@ -2110,6 +2110,11 @@ BBB 42 CCC 42 \. +-- check detach/reattach behavior; statement triggers with transition tables +-- should not prevent a table from becoming a partition again +alter table parent detach partition child1; +alter table parent attach partition child1 for values in ('AAA'); + -- DML affecting parent sees tuples collected from children even if -- there is no transition table trigger on the children drop trigger child1_insert_trig on child1; @@ -2329,6 +2334,11 @@ copy parent (a, b) from stdin; DDD 42 \. +-- check disinherit/reinherit behavior; statement triggers with transition +-- tables should not prevent a table from becoming an inheritance child again +alter table child1 no inherit parent; +alter table child1 inherit parent; + -- DML affecting parent sees tuples collected from children even if -- there is no transition table trigger on the children drop trigger child1_insert_trig on child1; diff --git a/c_src/libpg_query/test/sql/postgres_regress/with.sql b/c_src/libpg_query/test/sql/postgres_regress/with.sql index bcf0242f..1a1dfa7b 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/with.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/with.sql @@ -949,6 +949,13 @@ WITH RECURSIVE x(n) AS ( ORDER BY (SELECT n FROM x)) SELECT * FROM x; +-- and this +WITH RECURSIVE x(n) AS ( + WITH sub_cte AS (SELECT * FROM x) + DELETE FROM graph RETURNING f) + SELECT * FROM x; + + CREATE TEMPORARY TABLE y (a INTEGER); INSERT INTO y SELECT generate_series(1, 10); @@ -1076,6 +1083,20 @@ select ( with cte(foo) as ( values(f1) ) values((select foo from cte)) ) from int4_tbl; +-- +-- test for bug #19055: interaction of WITH with aggregates +-- +-- The reference to cte1 must determine the aggregate's level, +-- even though it contains no Vars referencing cte1 +explain (verbose, costs off) +select f1, (with cte1(x,y) as (select 1,2) + select count((select i4.f1 from cte1))) as ss +from int4_tbl i4; + +select f1, (with cte1(x,y) as (select 1,2) + select count((select i4.f1 from cte1))) as ss +from int4_tbl i4; + -- -- test for nested-recursive-WITH bug -- diff --git a/c_src/libpg_query/test/sql/postgres_regress/xml.sql b/c_src/libpg_query/test/sql/postgres_regress/xml.sql index 4c3520ce..0ea4f508 100644 --- a/c_src/libpg_query/test/sql/postgres_regress/xml.sql +++ b/c_src/libpg_query/test/sql/postgres_regress/xml.sql @@ -435,6 +435,8 @@ EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM xmltableview1; -- errors SELECT * FROM XMLTABLE (ROW () PASSING null COLUMNS v1 timestamp) AS f (v1, v2); +SELECT * FROM XMLTABLE (ROW () PASSING null COLUMNS v1 timestamp __pg__is_not_null 1) AS f (v1); + -- XMLNAMESPACES tests SELECT * FROM XMLTABLE(XMLNAMESPACES('http://x.y' AS zz), '/zz:rows/zz:row' diff --git a/c_src/libpg_query/test/summary.c b/c_src/libpg_query/test/summary.c new file mode 100644 index 00000000..5ef856a3 --- /dev/null +++ b/c_src/libpg_query/test/summary.c @@ -0,0 +1,257 @@ +#include +#include "src/pg_query_summary.h" + +#include +#include + +#include "test/framework/main.h" + +static void +test_cleanup(void) +{ +} + +static PgQuerySummaryParseResultInternal summary_internal(char *query, int parser_options, int truncate_limit) +{ + PgQuerySummaryParseResultInternal parse_result = pg_query_summary_internal(query, parser_options, truncate_limit); + + return parse_result; +} + +static Summary summary(char *query, int parser_options, int truncate_limit) +{ + PgQuerySummaryParseResultInternal parse_result = pg_query_summary_internal(query, parser_options, truncate_limit); + + if (parse_result.error != NULL) + { + printf(" ERROR: %s\n", parse_result.error->message); + exit(1); + } + + /* + * This is (roughly) equivalent to the Rust tests that assert + * `result.warnings` is empty. + */ + if (parse_result.stderr_buffer && + strstr(parse_result.stderr_buffer, "WARNING")) + { + printf(" ERROR: stderr_buffer contained a warning:\n%s\n", parse_result.stderr_buffer); + exit(1); + } + + Summary summary = parse_result.summary; + + /* We no longer have a use for parts using the system allocator. */ + pg_query_free_summary_parse_result_internal(parse_result); + + return summary; +} + +static char * +ctx_to_str(ContextType ctx) +{ + switch (ctx) + { + case CONTEXT_NONE: + return "CONTEXT_NONE"; + case CONTEXT_SELECT: + return "CONTEXT_SELECT"; + case CONTEXT_DML: + return "CONTEXT_DML"; + case CONTEXT_DDL: + return "CONTEXT_DDL"; + case CONTEXT_CALL: + return "CONTEXT_CALL"; + default: + return ""; + } +} + +/* Assert that `aliases` contains an alias with the key `key` and value `val`. */ +#define TEST_SUMMARY_ASSERT_ALIAS(aliases, key, val) TEST_SUMMARY_ASSERT_ALIAS_impl(test_state, aliases, #key, key, val) +void +TEST_SUMMARY_ASSERT_ALIAS_impl(TestState * test_state, List *aliases, char *expected_key_str, char *expected_key, char *expected_val) +{ + ListCell *lc = NULL; + + foreach(lc, aliases) + { + SummaryAlias *alias = lfirst(lc); + + if (TEST_BOUNDED_STRCMP(alias->key, expected_key) == 0) + { + TEST_ASSERT_STR_EQUAL(alias->value, expected_val); + return; + } + } + + /* If we get here, we didn't find a match. */ + TEST_FAIL(" FAIL: Expected an alias with key '%s', but it doesn't exist\n", expected_key_str); +} + +/* Assert that `filter_columns` contains an alias with the key `key` and value `val`. */ +#define TEST_SUMMARY_ASSERT_FILTER_COLUMN(filter_columns, schema, table, column) TEST_SUMMARY_ASSERT_FILTER_COLUMN_impl(test_state, filter_columns, schema, table, column) +void +TEST_SUMMARY_ASSERT_FILTER_COLUMN_impl(TestState * test_state, + List *filter_columns, char *schema_name, char *table_name, char *column) +{ + ListCell *lc = NULL; + int found = 0; + + foreach(lc, filter_columns) + { + FilterColumn *fc = lfirst(lc); + + if ((TEST_BOUNDED_STRCMP(fc->schema_name, schema_name) == 0) && + (TEST_BOUNDED_STRCMP(fc->table_name, table_name) == 0) && + (TEST_BOUNDED_STRCMP(fc->column, column) == 0)) + { + found = 1; + return; + } + } + + if (found) + TEST_PASS(); + else + TEST_FAIL(" FAIL: Expected to find a filter column where schema_name=%s, table_name=%s, column=%s\n", schema_name, table_name, column); +} + +/* Assert that `functions` contains functions with matching names. */ +#define TEST_SUMMARY_ASSERT_FUNCTIONS(functions, names) TEST_SUMMARY_ASSERT_FUNCTIONS_impl(test_state, functions, names) +void +TEST_SUMMARY_ASSERT_FUNCTIONS_impl(TestState * test_state, List *functions, char *names[]) +{ + for (size_t i = 0; names[i]; i++) + { + int found = 0; + ListCell *lc = NULL; + + foreach(lc, functions) + { + SummaryFunction *fn = lfirst(lc); + + if (TEST_BOUNDED_STRCMP(fn->name, names[i]) == 0) + { + found = 1; + break; + } + } + + if (found) + TEST_PASS(); + else + TEST_FAIL(" FAIL: Expected to find a function where name=%s\n", names[i]); + } +} + +/* Assert that `functions` contains functions with matching names. */ +#define TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(functions, ctx, names) TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX_impl(test_state, functions, ctx, names) +void +TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX_impl(TestState * test_state, List *functions, ContextType ctx, char *names[]) +{ + for (size_t i = 0; names[i]; i++) + { + int found = 0; + ContextType actual_ctx = CONTEXT_NONE; + ListCell *lc = NULL; + + foreach(lc, functions) + { + SummaryFunction *fn = lfirst(lc); + + if (TEST_BOUNDED_STRCMP(fn->name, names[i]) == 0) + { + found = 1; + actual_ctx = fn->context; + break; + } + } + + if (found) + { + if (ctx == actual_ctx) + TEST_PASS(); + else + TEST_FAIL(" FAIL: Expected function with name=%s to have context=%s, but it has context=%s\n", names[i], ctx_to_str(ctx), ctx_to_str(actual_ctx)); + } + else + TEST_FAIL(" FAIL: Expected to find a function where name=%s\n", names[i]); + } +} + +/* Assert that `tables` contains tables with matching names, schema_name, table_name, and context. */ +#define TEST_SUMMARY_ASSERT_TABLES(tables, names) TEST_SUMMARY_ASSERT_TABLES_impl(test_state, tables, names) +void +TEST_SUMMARY_ASSERT_TABLES_impl(TestState * test_state, List *tables, char *names[]) +{ + for (size_t i = 0; names[i]; i++) + { + int found = 0; + ListCell *lc = NULL; + + foreach(lc, tables) + { + SummaryTable *table = lfirst(lc); + + if (TEST_BOUNDED_STRCMP(table->name, names[i]) == 0) + { + found = 1; + break; + } + } + + if (found) + TEST_PASS(); + else + TEST_FAIL(" FAIL: Expected to find a table where name=%s\n", names[i]); + } +} + +/* Assert that `tables` contains tables with matching names, schema_name, table_name, and context. */ +#define TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(tables, ctx, names) TEST_SUMMARY_ASSERT_TABLES_WITH_CTX_impl(test_state, tables, ctx, names) +void +TEST_SUMMARY_ASSERT_TABLES_WITH_CTX_impl(TestState * test_state, List *tables, ContextType ctx, char *names[]) +{ + for (size_t i = 0; names[i]; i++) + { + int found = 0; + ContextType actual_ctx = CONTEXT_NONE; + ListCell *lc = NULL; + + foreach(lc, tables) + { + SummaryTable *table = lfirst(lc); + + if (TEST_BOUNDED_STRCMP(table->name, names[i]) == 0) + { + found = 1; + actual_ctx = table->context; + break; + } + } + + if (found) + { + if (ctx == actual_ctx) + TEST_PASS(); + else + TEST_FAIL(" FAIL: Expected table with name=%s to have context=%s, but it has context=%s\n", names[i], ctx_to_str(ctx), ctx_to_str(actual_ctx)); + } + else + TEST_FAIL(" FAIL: Expected to find a table where name=%s\n", names[i]); + } +} + +#include "summary_tests.c" + +int +main(int argc, char *argv[]) +{ + TestFn *tests[] = { +#include "summary_tests_list.c" + NULL + }; + + return test_run_with_mcxt(argc, argv, tests, &test_cleanup); +} diff --git a/c_src/libpg_query/test/summary_tests.c b/c_src/libpg_query/test/summary_tests.c new file mode 100644 index 00000000..8390a773 --- /dev/null +++ b/c_src/libpg_query/test/summary_tests.c @@ -0,0 +1,1075 @@ +void it_parses_simple_query(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM test WHERE a = 1", 0, -1); + + TEST_ASSERT_LIST_LENGTH(result.tables, 1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_LENGTH(result.aliases, 0); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 1); + TEST_ASSERT_NULL(result.truncated_query); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_parses_simple_query_with_alias(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM test AS x WHERE a = 1", 0, -1); + + TEST_ASSERT_LIST_LENGTH(result.tables, 1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_LENGTH(result.aliases, 1); + TEST_SUMMARY_ASSERT_ALIAS(result.aliases, "x", "test"); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 1); + TEST_ASSERT_NULL(result.truncated_query); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_parses_query_with_nested_select_where(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM test WHERE col1 = (SELECT col2 FROM test2 WHERE col3 = 123)", 0, -1); + + TEST_ASSERT_LIST_LENGTH(result.tables, 2); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", "test2", NULL})); + TEST_ASSERT_LIST_LENGTH(result.aliases, 0); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "col1"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "col3"); + + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_handles_errors(TestState* test_state) { + TEST_INIT(); + + PgQuerySummaryParseResultInternal parse_result = summary_internal("CREATE RANDOM ix_test ON contacts.person;", 0, -1); + TEST_ASSERT_STR_EQUAL(parse_result.error->message, "syntax error at or near \"RANDOM\""); + pg_query_free_summary_parse_result_internal(parse_result); + + parse_result = summary_internal("SELECT 'ERR", 0, -1); + TEST_ASSERT_STR_EQUAL(parse_result.error->message, "unterminated quoted string at or near \"'ERR\""); + pg_query_free_summary_parse_result_internal(parse_result); +} + +void it_handles_basic_query(TestState* test_state) { + TEST_INIT(); + char* query = "SELECT * FROM \"t0\""; + Summary result = summary(query, 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"t0", NULL})); + TEST_ASSERT_LIST_LENGTH(result.aliases, 0); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 0); + TEST_ASSERT_NULL(result.truncated_query); +} + +void it_handles_join_expression(TestState* test_state) { + TEST_INIT(); + char* query = "SELECT * FROM \"t0\" JOIN \"t1\" ON (1)"; + Summary result = summary(query, 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 2); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"t0", "t1", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_handles_recursion_without_error(TestState* test_state) { + TEST_INIT(); + // The Ruby version of pg_query fails here because of Ruby protobuf limitations + char* query = "SELECT * FROM \"t0\"\n\ + JOIN \"t1\" ON (1) JOIN \"t2\" ON (1) JOIN \"t3\" ON (1) JOIN \"t4\" ON (1) JOIN \"t5\" ON (1)\n\ + JOIN \"t6\" ON (1) JOIN \"t7\" ON (1) JOIN \"t8\" ON (1) JOIN \"t9\" ON (1) JOIN \"t10\" ON (1)\n\ + JOIN \"t11\" ON (1) JOIN \"t12\" ON (1) JOIN \"t13\" ON (1) JOIN \"t14\" ON (1) JOIN \"t15\" ON (1)\n\ + JOIN \"t16\" ON (1) JOIN \"t17\" ON (1) JOIN \"t18\" ON (1) JOIN \"t19\" ON (1) JOIN \"t20\" ON (1)\n\ + JOIN \"t21\" ON (1) JOIN \"t22\" ON (1) JOIN \"t23\" ON (1) JOIN \"t24\" ON (1) JOIN \"t25\" ON (1)\n\ + JOIN \"t26\" ON (1) JOIN \"t27\" ON (1) JOIN \"t28\" ON (1) JOIN \"t29\" ON (1)"; + Summary result = summary(query, 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 30); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", + "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", + "t20", "t21", "t22", "t23", "t24", "t25", "t26", "t27", "t28", "t29", + NULL + })); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_parses_real_queries(TestState* test_state) { + TEST_INIT(); + char* query = "\n\ + SELECT memory_total_bytes, memory_free_bytes, memory_pagecache_bytes, memory_buffers_bytes, memory_applications_bytes,\n\ + (memory_swap_total_bytes - memory_swap_free_bytes) AS swap, date_part($0, s.collected_at) AS collected_at\n\ + FROM snapshots s JOIN system_snapshots ON (snapshot_id = s.id)\n\ + WHERE s.database_id = $0 AND s.collected_at BETWEEN $0 AND $0\n\ + ORDER BY collected_at"; + Summary result = summary(query, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"snapshots", "system_snapshots", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"snapshots", "system_snapshots", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_parses_empty_queries(TestState* test_state) { + TEST_INIT(); + Summary result = summary("-- nothing", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.statement_types, 0); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_LENGTH(result.aliases, 0); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 0); + TEST_ASSERT_NULL(result.truncated_query); +} + +void it_parses_floats_with_leading_dot(TestState* test_state) { + TEST_INIT(); + // summary() will exit(1) if there's an error. + summary("SELECT .1", 0, -1); +} + +void it_parses_bit_strings_hex_notation(TestState* test_state) { + TEST_INIT(); + // summary() will exit(1) if there's an error. + summary("SELECT X'EFFF'", 0, -1); +} + +void it_parses_ALTER_TABLE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("ALTER TABLE test ADD PRIMARY KEY (gid)", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("AlterTableStmt")); +} + +void it_parses_SET(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SET statement_timeout=1", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("VariableSetStmt")); +} + +void it_parses_SHOW(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SHOW work_mem", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("VariableShowStmt")); +} + +void it_parses_COPY(TestState* test_state) { + TEST_INIT(); + Summary result = summary("COPY test (id) TO stdout", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CopyStmt")); +} + +void it_parses_DROP_TABLE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("drop table abc.test123 cascade", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"abc.test123", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"abc.test123", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); + + result = summary("drop table abc.test123, test", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"abc.test123", "test", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"abc.test123", "test", NULL})); +} + +void it_parses_COMMIT(TestState* test_state) { + TEST_INIT(); + Summary result = summary("COMMIT", 0, -1); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("TransactionStmt")); +} + +void it_parses_CHECKPOINT(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CHECKPOINT", 0, -1); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CheckPointStmt")); +} + +void it_parses_VACUUM(TestState* test_state) { + TEST_INIT(); + Summary result = summary("VACUUM my_table", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"my_table", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"my_table", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("VacuumStmt")); +} + +void it_parses_MERGE(TestState* test_state) { + TEST_INIT(); + Summary result = summary( + "WITH cte AS (SELECT * FROM g.other_table CROSS JOIN p) MERGE INTO my_table USING cte ON (id=oid) WHEN MATCHED THEN UPDATE SET a=b WHEN NOT MATCHED THEN INSERT (id, a) VALUES (oid, b);", + 0, + -1 + ); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"g.other_table", "p", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"my_table", NULL})); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"g.other_table", "my_table", "p", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make1("cte")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("MergeStmt", "SelectStmt")); +} + +void it_parses_EXPLAIN(TestState* test_state) { + TEST_INIT(); + Summary result = summary("EXPLAIN DELETE FROM test", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("ExplainStmt", "DeleteStmt")); +} + +void it_parses_SELECT_INTO(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CREATE TEMP TABLE test AS SELECT 1", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("CreateTableAsStmt", "SelectStmt")); +} + +void it_parses_LOCK(TestState* test_state) { + TEST_INIT(); + Summary result = summary("LOCK TABLE public.schema_migrations IN ACCESS SHARE MODE", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"public.schema_migrations", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("LockStmt")); +} + +void it_parses_CREATE_TABLE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CREATE TABLE test (a int4)", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CreateStmt")); +} + +void it_parses_CREATE_TABLE_AS(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CREATE TABLE foo AS SELECT * FROM bar;", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"bar", "foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"bar", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("CreateTableAsStmt", "SelectStmt")); + + char* sql = "CREATE TABLE foo AS SELECT id FROM bar UNION SELECT id from baz;"; + result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"bar", "baz", "foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"bar", "baz", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("CreateTableAsStmt", "SelectStmt")); +} + +void it_fails_to_parse_CREATE_TABLE_WITH_OIDS(TestState* test_state) { + PgQuerySummaryParseResultInternal parse_result = summary_internal("CREATE TABLE test (a int4) WITH OIDS", 0, -1); + TEST_ASSERT_STR_EQUAL(parse_result.error->message, "syntax error at or near \"OIDS\""); + pg_query_free_summary_parse_result_internal(parse_result); +} + + +void it_parses_CREATE_INDEX(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CREATE INDEX testidx ON test USING btree (a, (lower(b) || upper(c))) WHERE pow(a, 2) > 25", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"test", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"test", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("IndexStmt")); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){"lower", "pow", "upper", NULL})); +} + +void it_parses_CREATE_SCHEMA(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CREATE SCHEMA IF NOT EXISTS test AUTHORIZATION joe", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CreateSchemaStmt")); +} + +void it_parses_CREATE_VIEW(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CREATE VIEW myview AS SELECT * FROM mytab", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"mytab", "myview", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"myview", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"mytab", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("ViewStmt", "SelectStmt")); +} + +void it_parses_REFRESH_MATERIALIZED_VIEW(TestState* test_state) { + TEST_INIT(); + Summary result = summary("REFRESH MATERIALIZED VIEW myview", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"myview", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"myview", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("RefreshMatViewStmt")); +} + +void it_parses_CREATE_RULE(TestState* test_state) { + TEST_INIT(); + char* sql = "CREATE RULE shoe_ins_protect AS ON INSERT TO shoe DO INSTEAD NOTHING"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"shoe", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"shoe", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("RuleStmt")); +} + +void it_parses_CREATE_TRIGGER(TestState* test_state) { + TEST_INIT(); + char* sql = "CREATE TRIGGER check_update BEFORE UPDATE ON accounts FOR EACH ROW EXECUTE PROCEDURE check_account_update()"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"accounts", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"accounts", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CreateTrigStmt")); +} + +void it_parses_DROP_SCHEMA(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP SCHEMA myschema", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); +} + +void it_parses_DROP_VIEW(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP VIEW myview, myview2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); +} + +void it_parses_DROP_INDEX(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP INDEX CONCURRENTLY myindex", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); +} + +void it_parses_DROP_RULE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP RULE myrule ON mytable CASCADE", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"mytable", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"mytable", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); +} + +void it_parses_DROP_TRIGGER(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP TRIGGER IF EXISTS mytrigger ON mytable RESTRICT", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"mytable", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"mytable", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); +} + +void it_parses_GRANT(TestState* test_state) { + TEST_INIT(); + Summary result = summary("GRANT INSERT, UPDATE ON mytable TO myuser", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"mytable", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"mytable", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("GrantStmt")); +} + +void it_parses_REVOKE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("REVOKE admins FROM joe", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("GrantRoleStmt")); +} + +void it_parses_TRUNCATE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("TRUNCATE bigtable, \"fattable\" RESTART IDENTITY", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"bigtable", "fattable", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DDL, ((char*[]){"bigtable", "fattable", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("TruncateStmt")); +} + +void it_parses_WITH(TestState* test_state) { + TEST_INIT(); + Summary result = summary("WITH a AS (SELECT * FROM x WHERE x.y = $1 AND x.z = 1) SELECT * FROM a", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"x", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make1("a")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_parses_multi_line_functions(TestState* test_state) { + TEST_INIT(); + char* sql = "CREATE OR REPLACE FUNCTION thing(parameter_thing text)\n\ + RETURNS bigint AS\n\ +$BODY$\n\ +DECLARE\n\ + local_thing_id BIGINT := 0;\n\ +BEGIN\n\ + SELECT thing_id INTO local_thing_id FROM thing_map\n\ + WHERE\n\ + thing_map_field = parameter_thing\n\ + ORDER BY 1 LIMIT 1;\n\ +\n\ + IF NOT FOUND THEN\n\ + local_thing_id = 0;\n\ + END IF;\n\ + RETURN local_thing_id;\n\ +END;\n\ +$BODY$\n\ + LANGUAGE plpgsql STABLE"; + Summary result = summary(sql, 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"thing", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_DDL, ((char*[]){"thing", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CreateFunctionStmt")); +} + +void it_parses_table_functions(TestState* test_state) { + TEST_INIT(); + char* sql = "CREATE FUNCTION getfoo(int) RETURNS TABLE (f1 int) AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL"; + Summary result = summary(sql, 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"getfoo", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_DDL, ((char*[]){"getfoo", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CreateFunctionStmt")); +} + +void it_finds_called_functions(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT testfunc(1);", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"testfunc", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_DDL, ((char*[]){NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){"testfunc", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_functions_invoked_with_CALL(TestState* test_state) { + TEST_INIT(); + Summary result = summary("CALL testfunc(1);", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"testfunc", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_DDL, ((char*[]){NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){"testfunc", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("CallStmt")); +} + +void it_finds_dropped_functions(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP FUNCTION IF EXISTS testfunc(x integer);", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"testfunc", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_DDL, ((char*[]){"testfunc", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); +} + +void it_finds_renamed_functions(TestState* test_state) { + TEST_INIT(); + Summary result = summary("ALTER FUNCTION testfunc(integer) RENAME TO testfunc2;", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"testfunc", "testfunc2", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_DDL, ((char*[]){"testfunc", "testfunc2", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("RenameStmt")); +} + +void it_finds_nested_tables_in_SELECT(TestState* test_state) { + TEST_INIT(); + char* sql = "select u.email, (select count(*) from enrollments e where e.user_id = u.id) as num_enrollments from users u"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"enrollments", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"enrollments", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_separates_CTE_names_from_table_names(TestState* test_state) { + TEST_INIT(); + char* sql = "WITH cte_name AS (SELECT 1) SELECT * FROM table_name, cte_name"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"table_name", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"table_name", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make1("cte_name")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_tables_in_SELECT_FROM_TABLESAMPLE(TestState* test_state) { + TEST_INIT(); + char* sql = "SELECT * FROM tbl TABLESAMPLE sample(1)"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"tbl", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"tbl", NULL})); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_tables_in_SELECT_FROM_XMLTABLE(TestState* test_state) { + TEST_INIT(); + char* sql = "SELECT xmltable.* FROM xmlelements, XMLTABLE('/root' PASSING data COLUMNS element text)"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"xmlelements", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"xmlelements", NULL})); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_ignores_JSON_TABLE(TestState* test_state) { + TEST_INIT(); + char* sql = "SELECT jt.* FROM my_films, JSON_TABLE (js, '$.favorites[*]' COLUMNS (id FOR ORDINALITY, kind text PATH '$.kind')) AS jt;"; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"my_films", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"my_films", NULL})); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_FROM_clause(TestState* test_state) { + TEST_INIT(); + Summary result = summary("select u.* from (select * from users) u", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_WHERE_clause(TestState* test_state) { + TEST_INIT(); + Summary result = summary("select users.id from users where 1 = (select count(*) from user_roles)", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_tables_in_SELECT_with_subselects_without_FROM(TestState* test_state) { + TEST_INIT(); + char* query = "\n\ + SELECT *\n\ + FROM pg_catalog.pg_class c\n\ + JOIN (\n\ + SELECT 17650 AS oid\n\ + UNION ALL\n\ + SELECT 17663 AS oid\n\ + ) vals ON c.oid = vals.oid\n\ + "; + Summary result = summary(query, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"pg_catalog.pg_class", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"pg_catalog.pg_class", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); + // TODO: add filter_columns + // expect(query.filter_columns).to eq [["pg_catalog.pg_class", "oid"], ["vals", "oid"]] +} + +void it_finds_nested_tables_in_IN_clause(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + where users.id IN (select user_roles.user_id from user_roles)\n\ + and (users.created_at between '2016-06-01' and '2016-06-30')\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_ORDER_BY_clause(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + order by (\n\ + select max(user_roles.role_id)\n\ + from user_roles\n\ + where user_roles.user_id = users.id\n\ + )\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_ORDER_BY_clause_with_multiple_entries(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + order by (\n\ + select max(user_roles.role_id)\n\ + from user_roles\n\ + where user_roles.user_id = users.id\n\ + ) asc, (\n\ + select max(user_logins.role_id)\n\ + from user_logins\n\ + where user_logins.user_id = users.id\n\ + ) desc\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_logins", "user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_logins", "user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_GROUP_BY_clause(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + group by (\n\ + select max(user_roles.role_id)\n\ + from user_roles\n\ + where user_roles.user_id = users.id\n\ + )\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_GROUP_BY_clause_with_multiple_entries(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + group by (\n\ + select max(user_roles.role_id)\n\ + from user_roles\n\ + where user_roles.user_id = users.id\n\ + ), (\n\ + select max(user_logins.role_id)\n\ + from user_logins\n\ + where user_logins.user_id = users.id\n\ + )\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_logins", "user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_logins", "user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_HAVING_clause(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + group by users.id\n\ + having 1 > (\n\ + select count(user_roles.role_id)\n\ + from user_roles\n\ + where user_roles.user_id = users.id\n\ + )\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_HAVING_clause_with_boolean_expression(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select users.*\n\ + from users\n\ + group by users.id\n\ + having true and 1 > (\n\ + select count(user_roles.role_id)\n\ + from user_roles\n\ + where user_roles.user_id = users.id\n\ + )\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"user_roles", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"user_roles", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_a_subselect_on_a_JOIN(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + select foo.*\n\ + from foo\n\ + join ( select * from bar ) b\n\ + on b.baz = foo.quux\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"bar", "foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"foo", "bar", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_nested_tables_in_a_subselect_in_a_JOIN_condition(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + SELECT *\n\ + FROM foo\n\ + INNER JOIN join_a ON foo.id = join_a.id AND join_a.id IN (\n\ + SELECT id\n\ + FROM sub_a\n\ + INNER JOIN sub_b ON sub_a.id = sub_b.id AND sub_b.id IN (\n\ + SELECT id\n\ + FROM sub_c\n\ + INNER JOIN sub_d ON sub_c.id IN (SELECT id from sub_e)\n\ + )\n\ + )\n\ + INNER JOIN join_b ON foo.id = join_b.id AND join_b.id IN (\n\ + SELECT id FROM sub_f\n\ + )\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"foo", "join_a", "join_b", "sub_a", "sub_b", "sub_c", "sub_d", "sub_e", "sub_f", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"foo", "join_a", "join_b", "sub_a", "sub_b", "sub_c", "sub_d", "sub_e", "sub_f", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_correctly_categorizes_CTEs_after_UNION_SELECT(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + WITH cte_a AS (\n\ + SELECT * FROM table_a\n\ + ), cte_b AS (\n\ + SELECT * FROM table_b\n\ + )\n\ + SELECT id FROM table_c\n\ + LEFT JOIN cte_b ON table_c.id = cte_b.c_id\n\ + UNION\n\ + SELECT * FROM cte_a\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"table_a", "table_b", "table_c", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make2("cte_a", "cte_b")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_correctly_categorizes_CTEs_after_EXCEPT_SELECT(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + WITH cte_a AS (\n\ + SELECT * FROM table_a\n\ + ), cte_b AS (\n\ + SELECT * FROM table_b\n\ + )\n\ + SELECT id FROM table_c\n\ + LEFT JOIN cte_b ON table_c.id = cte_b.c_id\n\ + EXCEPT\n\ + SELECT * FROM cte_a\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"table_a", "table_b", "table_c", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make2("cte_a", "cte_b")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_correctly_categorizes_CTEs_after_INTERSECT_SELECT(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + WITH cte_a AS (\n\ + SELECT * FROM table_a\n\ + ), cte_b AS (\n\ + SELECT * FROM table_b\n\ + )\n\ + SELECT id FROM table_c\n\ + LEFT JOIN cte_b ON table_c.id = cte_b.c_id\n\ + INTERSECT\n\ + SELECT * FROM cte_a\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"table_a", "table_b", "table_c", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make2("cte_a", "cte_b")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_tables_inside_subselectes_in_MIN_MAX_COALESCE(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + SELECT GREATEST(\n\ + date_trunc($1, $2::timestamptz) + $3::interval,\n\ + COALESCE(\n\ + (\n\ + SELECT first_aggregate_starts_at\n\ + FROM schema_aggregate_infos\n\ + WHERE base_table = $4 LIMIT $5\n\ + ),\n\ + now() + $6::interval\n\ + )\n\ + ) AS first_hourly_start_ts\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"schema_aggregate_infos", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"schema_aggregate_infos", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_tables_inside_CASE_statements(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + SELECT\n\ + CASE\n\ + WHEN id IN (SELECT foo_id FROM when_a) THEN (SELECT MAX(id) FROM then_a)\n\ + WHEN id IN (SELECT foo_id FROM when_b) THEN (SELECT MAX(id) FROM then_b)\n\ + ELSE (SELECT MAX(id) FROM elsey)\n\ + END\n\ + FROM foo\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"elsey", "foo", "then_a", "then_b", "when_a", "when_b", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"elsey", "foo", "then_a", "then_b", "when_a", "when_b", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_tables_inside_casts(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + SELECT 1\n\ + FROM foo\n\ + WHERE x = any(cast(array(SELECT a FROM bar) as bigint[]))\n\ + OR x = any(array(SELECT a FROM baz)::bigint[])\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"bar", "baz", "foo", NULL})); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_functions_in_FROM_clause(TestState* test_state) { + TEST_INIT(); + char* sql = "SELECT * FROM my_custom_func()"; + Summary result = summary(sql, 0, -1); + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"my_custom_func", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){"my_custom_func", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_finds_functions_in_LATERAL_clause(TestState* test_state) { + TEST_INIT(); + char* sql = "\n\ + SELECT *\n\ + FROM unnest($1::text[]) AS a(x)\n\ + LEFT OUTER JOIN LATERAL (\n\ + SELECT json_build_object($2, z.z)\n\ + FROM (\n\ + SELECT *\n\ + FROM (\n\ + SELECT row_to_json(\n\ + (SELECT * FROM (SELECT public.my_function(b) FROM public.c) d)\n\ + )\n\ + ) e\n\ + ) f\n\ + ) AS g ON (1)\n\ + "; + Summary result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"public.c", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS(result.functions, ((char*[]){"json_build_object", "public.my_function", "row_to_json", "unnest", NULL})); + TEST_SUMMARY_ASSERT_FUNCTIONS_WITH_CTX(result.functions, CONTEXT_CALL, ((char*[]){"json_build_object", "public.my_function", "row_to_json", "unnest", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("SelectStmt")); +} + +void it_parses_INSERT(TestState* test_state) { + TEST_INIT(); + Summary result = summary("insert into users(pk, name) values (1, 'bob');", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"users", NULL})); + + result = summary("insert into users(pk, name) select pk, name from other_users;", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"other_users", "users", NULL})); + + char* sql = "\n\ + with cte as (\n\ + select pk, name from other_users\n\ + )\n\ + insert into users(pk, name) select * from cte;\n\ + "; + result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"other_users", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"other_users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make1("cte")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("InsertStmt", "SelectStmt")); +} + +void it_parses_UPDATE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("update users set name = 'bob';", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("UpdateStmt")); + + result = summary("update users set name = (select name from other_users limit 1);", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"other_users", "users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("UpdateStmt", "SelectStmt")); + + char* sql = "\n\ + with cte as (\n\ + select name from other_users limit 1\n\ + )\n\ + update users set name = (select name from cte);\n\ + "; + result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"other_users", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"other_users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.cte_names, list_make1("cte")); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("UpdateStmt", "SelectStmt")); + + sql = "\n\ + UPDATE users SET name = users_new.name\n\ + FROM users_new\n\ + INNER JOIN join_table ON join_table.user_id = new_users.id\n\ + WHERE users.id = users_new.id\n\ + "; + result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"join_table", "users", "users_new", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"join_table", "users_new", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("UpdateStmt")); +} + +void it_parses_DELETE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DELETE FROM users;", 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DeleteStmt")); + + char* sql = "\n\ + DELETE FROM users USING foo\n\ + WHERE foo_id = foo.id AND foo.action = 'delete';\n\ + "; + result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"foo", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DeleteStmt")); + + sql = "\n\ + DELETE FROM users\n\ + WHERE foo_id IN (SELECT id FROM foo WHERE action = 'delete');\n\ + "; + result = summary(sql, 0, -1); + TEST_SUMMARY_ASSERT_TABLES(result.tables, ((char*[]){"foo", "users", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_SELECT, ((char*[]){"foo", NULL})); + TEST_SUMMARY_ASSERT_TABLES_WITH_CTX(result.tables, CONTEXT_DML, ((char*[]){"users", NULL})); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make2("DeleteStmt", "SelectStmt")); +} + +void it_parses_DROP_TYPE(TestState* test_state) { + TEST_INIT(); + Summary result = summary("DROP TYPE IF EXISTS repack.pk_something", 0, -1); + TEST_ASSERT_LIST_EQUAL(result.statement_types, list_make1("DropStmt")); + + // TODO: VERIFY THIS IS CORRECT. + TEST_ASSERT_LIST_LENGTH(result.tables, 0); + TEST_ASSERT_LIST_LENGTH(result.aliases, 0); + TEST_ASSERT_LIST_LENGTH(result.cte_names, 0); + TEST_ASSERT_LIST_LENGTH(result.functions, 0); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 0); + TEST_ASSERT_NULL(result.truncated_query); +} + +// filter column tests + +void it_finds_unqualified_names(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM x WHERE y = $1 AND z = 1", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_finds_qualified_names(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM x WHERE x.y = $1 AND x.z = 1", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "z"); +} + +void it_traverses_into_ctes(TestState* test_state) { + TEST_INIT(); + Summary result = summary("WITH a AS (SELECT * FROM x WHERE x.y = $1 AND x.z = 1) SELECT * FROM a WHERE b = 5", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 3); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "b"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "z"); +} + +void it_recognizes_boolean_tests(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM x WHERE x.y IS TRUE AND x.z IS NOT FALSE", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "z"); +} + +void it_recognizes_null_tests(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM x WHERE x.y IS NULL AND x.z IS NOT NULL", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "z"); +} + +void it_finds_coalesce_argument_names(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM x WHERE x.y = COALESCE(z.a, z.b)", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 3); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "z", "a"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "z", "b"); +} + +void it_finds_unqualified_names_in_union_query(TestState* test_state) { + TEST_INIT(); + Summary result = summary("SELECT * FROM x where y = $1 UNION SELECT * FROM x where z = $2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_finds_unqualified_names_in_union_all_query(TestState* test_state) { + Summary result = summary("SELECT * FROM x where y = $1 UNION ALL SELECT * FROM x where z = $2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_finds_unqualified_names_in_except_query(TestState* test_state) { + Summary result = summary("SELECT * FROM x where y = $1 EXCEPT SELECT * FROM x where z = $2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_finds_unqualified_names_in_except_all_query(TestState* test_state) { + Summary result = summary("SELECT * FROM x where y = $1 EXCEPT ALL SELECT * FROM x where z = $2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_finds_unqualified_names_in_intersect_query(TestState* test_state) { + Summary result = summary("SELECT * FROM x where y = $1 INTERSECT SELECT * FROM x where z = $2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_finds_unqualified_names_in_intersect_all_query(TestState* test_state) { + Summary result = summary("SELECT * FROM x where y = $1 INTERSECT ALL SELECT * FROM x where z = $2", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, NULL, "z"); +} + +void it_ignores_target_list_columns(TestState* test_state) { + Summary result = summary("SELECT a, y, z FROM x WHERE x.y = $1 AND x.z = 1", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "z"); +} + +void it_ignores_order_by_columns(TestState* test_state) { + Summary result = summary("SELECT * FROM x WHERE x.y = $1 AND x.z = 1 ORDER BY a, b", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 2); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "y"); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, NULL, "x", "z"); +} + +void it_handles_all_tables_in_schema(TestState* test_state) { + Summary result = summary("GRANT SELECT ON ALL TABLES IN SCHEMA public TO myrole", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 0); +} + +void it_handles_schema_qualified_columns(TestState* test_state) { + Summary result = summary("SELECT * FROM b.c WHERE a.b.c = 1", 0, -1); + TEST_ASSERT_LIST_LENGTH(result.filter_columns, 1); + TEST_SUMMARY_ASSERT_FILTER_COLUMN(result.filter_columns, "a", "b", "c"); +} diff --git a/c_src/libpg_query/test/summary_tests_list.c b/c_src/libpg_query/test/summary_tests_list.c new file mode 100644 index 00000000..dd18fa4f --- /dev/null +++ b/c_src/libpg_query/test/summary_tests_list.c @@ -0,0 +1,94 @@ +// Generated by ./scripts/update_summary_tests_list.rb + +&it_parses_simple_query, +&it_parses_simple_query_with_alias, +&it_parses_query_with_nested_select_where, +&it_handles_errors, +&it_handles_basic_query, +&it_handles_join_expression, +&it_handles_recursion_without_error, +&it_parses_real_queries, +&it_parses_empty_queries, +&it_parses_floats_with_leading_dot, +&it_parses_bit_strings_hex_notation, +&it_parses_ALTER_TABLE, +&it_parses_SET, +&it_parses_SHOW, +&it_parses_COPY, +&it_parses_DROP_TABLE, +&it_parses_COMMIT, +&it_parses_CHECKPOINT, +&it_parses_VACUUM, +&it_parses_MERGE, +&it_parses_EXPLAIN, +&it_parses_SELECT_INTO, +&it_parses_LOCK, +&it_parses_CREATE_TABLE, +&it_parses_CREATE_TABLE_AS, +&it_fails_to_parse_CREATE_TABLE_WITH_OIDS, +&it_parses_CREATE_INDEX, +&it_parses_CREATE_SCHEMA, +&it_parses_CREATE_VIEW, +&it_parses_REFRESH_MATERIALIZED_VIEW, +&it_parses_CREATE_RULE, +&it_parses_CREATE_TRIGGER, +&it_parses_DROP_SCHEMA, +&it_parses_DROP_VIEW, +&it_parses_DROP_INDEX, +&it_parses_DROP_RULE, +&it_parses_DROP_TRIGGER, +&it_parses_GRANT, +&it_parses_REVOKE, +&it_parses_TRUNCATE, +&it_parses_WITH, +&it_parses_multi_line_functions, +&it_parses_table_functions, +&it_finds_called_functions, +&it_finds_functions_invoked_with_CALL, +&it_finds_dropped_functions, +&it_finds_renamed_functions, +&it_finds_nested_tables_in_SELECT, +&it_separates_CTE_names_from_table_names, +&it_finds_tables_in_SELECT_FROM_TABLESAMPLE, +&it_finds_tables_in_SELECT_FROM_XMLTABLE, +&it_ignores_JSON_TABLE, +&it_finds_nested_tables_in_FROM_clause, +&it_finds_nested_tables_in_WHERE_clause, +&it_finds_tables_in_SELECT_with_subselects_without_FROM, +&it_finds_nested_tables_in_IN_clause, +&it_finds_nested_tables_in_ORDER_BY_clause, +&it_finds_nested_tables_in_ORDER_BY_clause_with_multiple_entries, +&it_finds_nested_tables_in_GROUP_BY_clause, +&it_finds_nested_tables_in_GROUP_BY_clause_with_multiple_entries, +&it_finds_nested_tables_in_HAVING_clause, +&it_finds_nested_tables_in_HAVING_clause_with_boolean_expression, +&it_finds_nested_tables_in_a_subselect_on_a_JOIN, +&it_finds_nested_tables_in_a_subselect_in_a_JOIN_condition, +&it_correctly_categorizes_CTEs_after_UNION_SELECT, +&it_correctly_categorizes_CTEs_after_EXCEPT_SELECT, +&it_correctly_categorizes_CTEs_after_INTERSECT_SELECT, +&it_finds_tables_inside_subselectes_in_MIN_MAX_COALESCE, +&it_finds_tables_inside_CASE_statements, +&it_finds_tables_inside_casts, +&it_finds_functions_in_FROM_clause, +&it_finds_functions_in_LATERAL_clause, +&it_parses_INSERT, +&it_parses_UPDATE, +&it_parses_DELETE, +&it_parses_DROP_TYPE, +&it_finds_unqualified_names, +&it_finds_qualified_names, +&it_traverses_into_ctes, +&it_recognizes_boolean_tests, +&it_recognizes_null_tests, +&it_finds_coalesce_argument_names, +&it_finds_unqualified_names_in_union_query, +&it_finds_unqualified_names_in_union_all_query, +&it_finds_unqualified_names_in_except_query, +&it_finds_unqualified_names_in_except_all_query, +&it_finds_unqualified_names_in_intersect_query, +&it_finds_unqualified_names_in_intersect_all_query, +&it_ignores_target_list_columns, +&it_ignores_order_by_columns, +&it_handles_all_tables_in_schema, +&it_handles_schema_qualified_columns, diff --git a/c_src/libpg_query/test/summary_truncate.c b/c_src/libpg_query/test/summary_truncate.c new file mode 100644 index 00000000..9133957c --- /dev/null +++ b/c_src/libpg_query/test/summary_truncate.c @@ -0,0 +1,202 @@ +#include +#include "src/pg_query_summary.h" + +#include +#include + +#include "test/framework/main.h" + +static Summary summary(char *query, int parser_options, int truncate_limit) +{ + PgQuerySummaryParseResultInternal parse_result = pg_query_summary_internal(query, parser_options, truncate_limit); + + if (parse_result.error != NULL) + { + printf(" ERROR: %s\n", parse_result.error->message); + exit(1); + } + + Summary summary = parse_result.summary; + + /* We no longer have a use for parts using the system allocator. */ + pg_query_free_summary_parse_result_internal(parse_result); + + return summary; +} + +void +it_omits_target_list(TestState * test_state) +{ + TEST_INIT(); + char *query = "SELECT a, b, c, d, e, f FROM xyz WHERE a = b"; + Summary result = summary(query, 0, 40); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "SELECT ... FROM xyz WHERE a = b"); +} + +void +it_omits_CTE_definition(TestState * test_state) +{ + TEST_INIT(); + char *query = "WITH x AS (SELECT * FROM y) SELECT * FROM x"; + Summary result = summary(query, 0, 40); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "WITH x AS (...) SELECT * FROM x"); +} + +void +it_omits_WHERE_clause(TestState * test_state) +{ + TEST_INIT(); + char *query = "SELECT * FROM z WHERE a = b AND x = y"; + Summary result = summary(query, 0, 30); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "SELECT * FROM z WHERE ..."); +} + +void +it_omits_INSERT_field_list(TestState * test_state) +{ + TEST_INIT(); + char *query = "INSERT INTO \"x\" (a, b, c, d, e, f) VALUES ($1)"; + Summary result = summary(query, 0, 32); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "INSERT INTO x (...) VALUES ($1)"); +} + +void +it_omits_comments(TestState * test_state) +{ + TEST_INIT(); + char *query = "SELECT $1 /* application:test */"; + Summary result = summary(query, 0, 100); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "SELECT $1"); +} + +void +it_falls_back_to_simple_truncation(TestState * test_state) +{ + TEST_INIT(); + char *query = "SELECT * FROM t"; + Summary result = summary(query, 0, 10); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "SELECT ..."); +} + +void +it_handles_problematic_cases(TestState * test_state) +{ + TEST_INIT(); + char *query = "SELECT CASE WHEN $2.typtype = $1 THEN $2.typtypmod ELSE $1.atttypmod END"; + Summary result = summary(query, 0, 50); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "SELECT ..."); +} + +void +it_omits_UPDATE_target_list(TestState * test_state) +{ + TEST_INIT(); + char *query = "UPDATE x SET a = 1, c = 2, e = 'str'"; + Summary result = summary(query, 0, 30); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "UPDATE x SET ... = ..."); +} + +void +it_omits_ON_CONFLICT_target_list(TestState * test_state) +{ + TEST_INIT(); + char *query = "INSERT INTO y(a) VALUES(1) ON CONFLICT DO UPDATE SET a = 123456789"; + Summary result = summary(query, 0, 65); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "INSERT INTO y (a) VALUES (1) ON CONFLICT DO UPDATE SET ... = ..."); +} + +void +it_omits_ON_CONFLICT_target_list_2(TestState * test_state) +{ + TEST_INIT(); + char *query = "\ + INSERT INTO foo (a, b, c, d) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29) \ + ON CONFLICT (id) \ + DO UPDATE SET (a, b, c, d) = (excluded.a,excluded.b,excluded.c,case when foo.d = excluded.d then excluded.d end) \ + "; + Summary result = summary(query, 0, 100); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "INSERT INTO foo (a, b, c, d) VALUES (...) ON CONFLICT (id) DO UPDATE SET ... = ...");; +} + +void +it_handles_GRANT(TestState * test_state) +{ + TEST_INIT(); + char *query = "GRANT SELECT (abc, def, ghj) ON TABLE t1 TO r1"; + Summary result = summary(query, 0, 35); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "GRANT select (abc, def, ghj) ON ..."); +} + +void +it_does_not_segfault_on_target_list_from_CTE_already_removed_from_possible_truncations(TestState * test_state) +{ + TEST_INIT(); + char *query = "\ + WITH activity AS ( \ + SELECT pid, COALESCE(a.usename, '') AS usename \ + FROM pganalyze.get_stat_activity() a \ + ) \ + SELECT \ + FROM pganalyze.get_stat_progress_vacuum() v \ + JOIN activity a USING (pid) \ + "; + Summary result = summary(query, 0, 100); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "WITH activity AS (...) SELECT FROM pganalyze.get_stat_progress_vacuum() v JOIN activity a USING (...");; +} + +/* If we truncate the index expression in the future this would remove (lower(d) || upper(d)) first */ +void +it_handles_CREATE_INDEX(TestState * test_state) +{ + TEST_INIT(); + char *query = "CREATE INDEX testidx ON test USING btree ((lower(d) || upper(d)), a, (b+c))"; + Summary result = summary(query, 0, 60); + + TEST_ASSERT_STR_EQUAL(result.truncated_query, "CREATE INDEX testidx ON test USING btree ((lower(d) || up...");; +} + +void +char_truncate_works(TestState * test_state) +{ + char *query = "WITH \"原チコ氏にはす腹腹腹腹腹腹腹腹腹腹腹\" AS (SELECT) SELECT w"; + Summary result = summary(query, 0, 21); + char *output = "WITH \"原チコ氏にはす腹腹腹腹腹..."; + + TEST_ASSERT_STR_EQUAL(result.truncated_query, output);; +} + +int +main(int argc, char *argv[]) +{ + TestFn *tests[] = { + &it_omits_target_list, + &it_omits_CTE_definition, + &it_omits_WHERE_clause, + &it_omits_INSERT_field_list, + &it_omits_comments, + &it_falls_back_to_simple_truncation, + &it_handles_problematic_cases, + &it_omits_UPDATE_target_list, + &it_omits_ON_CONFLICT_target_list, + &it_omits_ON_CONFLICT_target_list_2, + &it_handles_GRANT, + &it_does_not_segfault_on_target_list_from_CTE_already_removed_from_possible_truncations, + &it_handles_CREATE_INDEX, + &char_truncate_works, + NULL + }; + + return test_run_with_mcxt(argc, argv, tests, NULL); +} diff --git a/c_src/libpg_query_ex.c b/c_src/libpg_query_ex.c index fd021974..fa269c82 100644 --- a/c_src/libpg_query_ex.c +++ b/c_src/libpg_query_ex.c @@ -2,6 +2,8 @@ #include #include +#define MAX_QUERY_SIZE 65536 /* queries larger than this are rejected */ + #include "libpg_query/pg_query.h" static ERL_NIF_TERM result_tuple(ErlNifEnv *env, const char *status, @@ -23,16 +25,43 @@ ERL_NIF_TERM make_binary(ErlNifEnv *env, char *source) { return binary; } +ERL_NIF_TERM make_error_response(ErlNifEnv *env, char *message) { + ERL_NIF_TERM error_map = enif_make_new_map(env); + if (!enif_make_map_put(env, error_map, enif_make_atom(env, "message"), + make_binary(env, message), &error_map)) { + return enif_raise_exception(env, make_binary(env, "failed to update map")); + } + return error_map; +} + +ERL_NIF_TERM query_too_long_error(ErlNifEnv *env, size_t query_size) { + char error_msg[128]; + snprintf(error_msg, 128, + "cannot parse query: query size %lu is bigger than maximum size %i", + query_size, MAX_QUERY_SIZE); + ERL_NIF_TERM error_map = make_error_response(env, error_msg); + return enif_make_tuple2(env, enif_make_atom(env, "error"), error_map); +} + +static ERL_NIF_TERM max_query_size(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]) { + return enif_make_int64(env, MAX_QUERY_SIZE); +} + static ERL_NIF_TERM parse_query(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary query; ERL_NIF_TERM term; if (argc == 1 && enif_inspect_binary(env, argv[0], &query)) { + if (query.size >= MAX_QUERY_SIZE) { + return query_too_long_error(env, query.size); + } + // add one more byte for the null termination char statement[query.size + 1]; - strncpy(statement, (char *)query.data, query.size); + memcpy(statement, (char *)query.data, query.size); // terminate the string statement[query.size] = 0; @@ -40,27 +69,14 @@ static ERL_NIF_TERM parse_query(ErlNifEnv *env, int argc, PgQueryProtobufParseResult result = pg_query_parse_protobuf(statement); if (result.error) { - ERL_NIF_TERM error_map = enif_make_new_map(env); - - if (!enif_make_map_put( - env, - error_map, - enif_make_atom(env, "message"), - make_binary(env, result.error->message), - &error_map - )) { - return enif_raise_exception(env, make_binary(env, "failed to update map")); - } - - if (!enif_make_map_put( - env, - error_map, - enif_make_atom(env, "cursorpos"), - // drop the cursorpos by one, so it's zero-indexed - enif_make_int(env, result.error->cursorpos - 1), - &error_map - )) { - return enif_raise_exception(env, make_binary(env, "failed to update map")); + ERL_NIF_TERM error_map = make_error_response(env, result.error->message); + + if (!enif_make_map_put(env, error_map, enif_make_atom(env, "cursorpos"), + // drop the cursorpos by one, so it's zero-indexed + enif_make_int(env, result.error->cursorpos - 1), + &error_map)) { + return enif_raise_exception(env, + make_binary(env, "failed to update map")); } term = enif_make_tuple2(env, enif_make_atom(env, "error"), error_map); @@ -77,7 +93,7 @@ static ERL_NIF_TERM parse_query(ErlNifEnv *env, int argc, } static ERL_NIF_TERM deparse_query(ErlNifEnv *env, int argc, - const ERL_NIF_TERM argv[]) { + const ERL_NIF_TERM argv[]) { ErlNifBinary proto; ERL_NIF_TERM term; @@ -89,17 +105,7 @@ static ERL_NIF_TERM deparse_query(ErlNifEnv *env, int argc, PgQueryDeparseResult result = pg_query_deparse_protobuf(parse_tree); if (result.error) { - ERL_NIF_TERM error_map = enif_make_new_map(env); - - if (!enif_make_map_put( - env, - error_map, - enif_make_atom(env, "message"), - make_binary(env, result.error->message), - &error_map - )) { - return enif_raise_exception(env, make_binary(env, "failed to update map")); - } + ERL_NIF_TERM error_map = make_error_response(env, result.error->message); term = enif_make_tuple2(env, enif_make_atom(env, "error"), error_map); } else { @@ -114,15 +120,19 @@ static ERL_NIF_TERM deparse_query(ErlNifEnv *env, int argc, } static ERL_NIF_TERM scan_query(ErlNifEnv *env, int argc, - const ERL_NIF_TERM argv[]) { + const ERL_NIF_TERM argv[]) { ErlNifBinary query; ERL_NIF_TERM term; if (argc == 1 && enif_inspect_binary(env, argv[0], &query)) { + if (query.size >= MAX_QUERY_SIZE) { + return query_too_long_error(env, query.size); + } + // add one more byte for the null termination char statement[query.size + 1]; - strncpy(statement, (char *)query.data, query.size); + memcpy(statement, (char *)query.data, query.size); // terminate the string statement[query.size] = 0; @@ -130,27 +140,15 @@ static ERL_NIF_TERM scan_query(ErlNifEnv *env, int argc, PgQueryScanResult result = pg_query_scan(statement); if (result.error) { - ERL_NIF_TERM error_map = enif_make_new_map(env); - - if (!enif_make_map_put( - env, - error_map, - enif_make_atom(env, "message"), - make_binary(env, result.error->message), - &error_map - )) { - return enif_raise_exception(env, make_binary(env, "failed to update map")); - } - - if (result.error->cursorpos > 0 && !enif_make_map_put( - env, - error_map, - enif_make_atom(env, "cursorpos"), - // drop the cursorpos by one, so it's zero-indexed - enif_make_int(env, result.error->cursorpos - 1), - &error_map - )) { - return enif_raise_exception(env, make_binary(env, "failed to update map")); + ERL_NIF_TERM error_map = make_error_response(env, result.error->message); + + if (result.error->cursorpos > 0 && + !enif_make_map_put(env, error_map, enif_make_atom(env, "cursorpos"), + // drop the cursorpos by one, so it's zero-indexed + enif_make_int(env, result.error->cursorpos - 1), + &error_map)) { + return enif_raise_exception(env, + make_binary(env, "failed to update map")); } term = enif_make_tuple2(env, enif_make_atom(env, "error"), error_map); @@ -166,9 +164,10 @@ static ERL_NIF_TERM scan_query(ErlNifEnv *env, int argc, } static ErlNifFunc funcs[] = { - {"parse_query", 1, parse_query}, - {"deparse_query", 1, deparse_query}, - {"scan_query", 1, scan_query} + {"parse_query", 1, parse_query}, + {"deparse_query", 1, deparse_query}, + {"scan_query", 1, scan_query}, + {"max_query_size", 0, max_query_size}, }; ERL_NIF_INIT(Elixir.PgQuery.Parser, funcs, NULL, NULL, NULL, NULL) diff --git a/fuzz/corpus/parse/001_select_simple.sql b/fuzz/corpus/parse/001_select_simple.sql new file mode 100644 index 00000000..2e3761f7 --- /dev/null +++ b/fuzz/corpus/parse/001_select_simple.sql @@ -0,0 +1 @@ +SELECT 1 diff --git a/fuzz/corpus/parse/002_select_where.sql b/fuzz/corpus/parse/002_select_where.sql new file mode 100644 index 00000000..ecaa756f --- /dev/null +++ b/fuzz/corpus/parse/002_select_where.sql @@ -0,0 +1 @@ +SELECT id, name FROM users WHERE active = true diff --git a/fuzz/corpus/parse/003_select_join.sql b/fuzz/corpus/parse/003_select_join.sql new file mode 100644 index 00000000..f620ddce --- /dev/null +++ b/fuzz/corpus/parse/003_select_join.sql @@ -0,0 +1 @@ +SELECT u.id, o.total FROM users u JOIN orders o ON u.id = o.user_id diff --git a/fuzz/corpus/parse/004_insert.sql b/fuzz/corpus/parse/004_insert.sql new file mode 100644 index 00000000..aac8717a --- /dev/null +++ b/fuzz/corpus/parse/004_insert.sql @@ -0,0 +1 @@ +INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com') diff --git a/fuzz/corpus/parse/005_update.sql b/fuzz/corpus/parse/005_update.sql new file mode 100644 index 00000000..69fc2a01 --- /dev/null +++ b/fuzz/corpus/parse/005_update.sql @@ -0,0 +1 @@ +UPDATE users SET active = false WHERE last_login < NOW() - INTERVAL '90 days' diff --git a/fuzz/corpus/parse/006_delete.sql b/fuzz/corpus/parse/006_delete.sql new file mode 100644 index 00000000..16d5ce5e --- /dev/null +++ b/fuzz/corpus/parse/006_delete.sql @@ -0,0 +1 @@ +DELETE FROM sessions WHERE expires_at < NOW() diff --git a/fuzz/corpus/parse/007_cte.sql b/fuzz/corpus/parse/007_cte.sql new file mode 100644 index 00000000..9715c9df --- /dev/null +++ b/fuzz/corpus/parse/007_cte.sql @@ -0,0 +1 @@ +WITH recent AS (SELECT * FROM events WHERE created_at > NOW() - INTERVAL '1 hour') SELECT count(*) FROM recent diff --git a/fuzz/corpus/parse/008_subquery.sql b/fuzz/corpus/parse/008_subquery.sql new file mode 100644 index 00000000..aac833e7 --- /dev/null +++ b/fuzz/corpus/parse/008_subquery.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100) diff --git a/fuzz/corpus/parse/009_aggregate.sql b/fuzz/corpus/parse/009_aggregate.sql new file mode 100644 index 00000000..8a0835e5 --- /dev/null +++ b/fuzz/corpus/parse/009_aggregate.sql @@ -0,0 +1 @@ +SELECT department, count(*), avg(salary) FROM employees GROUP BY department HAVING count(*) > 5 diff --git a/fuzz/corpus/parse/010_window.sql b/fuzz/corpus/parse/010_window.sql new file mode 100644 index 00000000..c33e8983 --- /dev/null +++ b/fuzz/corpus/parse/010_window.sql @@ -0,0 +1 @@ +SELECT id, salary, rank() OVER (PARTITION BY department ORDER BY salary DESC) FROM employees diff --git a/fuzz/corpus/parse/011_cast.sql b/fuzz/corpus/parse/011_cast.sql new file mode 100644 index 00000000..96f456d8 --- /dev/null +++ b/fuzz/corpus/parse/011_cast.sql @@ -0,0 +1 @@ +SELECT id::text, created_at::date, price::numeric(10,2) FROM products diff --git a/fuzz/corpus/parse/012_case.sql b/fuzz/corpus/parse/012_case.sql new file mode 100644 index 00000000..98764cf7 --- /dev/null +++ b/fuzz/corpus/parse/012_case.sql @@ -0,0 +1 @@ +SELECT CASE WHEN status = 1 THEN 'active' WHEN status = 2 THEN 'pending' ELSE 'unknown' END FROM orders diff --git a/fuzz/corpus/parse/013_array.sql b/fuzz/corpus/parse/013_array.sql new file mode 100644 index 00000000..9b7a32e2 --- /dev/null +++ b/fuzz/corpus/parse/013_array.sql @@ -0,0 +1 @@ +SELECT ARRAY[1,2,3], unnest(tags) FROM posts diff --git a/fuzz/corpus/parse/014_jsonb.sql b/fuzz/corpus/parse/014_jsonb.sql new file mode 100644 index 00000000..70c65e9e --- /dev/null +++ b/fuzz/corpus/parse/014_jsonb.sql @@ -0,0 +1 @@ +SELECT data->>'name', data->'address'->>'city' FROM profiles WHERE data @> '{"active":true}' diff --git a/fuzz/corpus/parse/015_exists.sql b/fuzz/corpus/parse/015_exists.sql new file mode 100644 index 00000000..37f878d2 --- /dev/null +++ b/fuzz/corpus/parse/015_exists.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id) diff --git a/fuzz/corpus/parse/016_between.sql b/fuzz/corpus/parse/016_between.sql new file mode 100644 index 00000000..0fdf1141 --- /dev/null +++ b/fuzz/corpus/parse/016_between.sql @@ -0,0 +1 @@ +SELECT * FROM events WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31' diff --git a/fuzz/corpus/parse/017_like.sql b/fuzz/corpus/parse/017_like.sql new file mode 100644 index 00000000..3ad4f706 --- /dev/null +++ b/fuzz/corpus/parse/017_like.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE email ILIKE '%@example.com' AND name NOT LIKE 'test%' diff --git a/fuzz/corpus/parse/018_null.sql b/fuzz/corpus/parse/018_null.sql new file mode 100644 index 00000000..522d4047 --- /dev/null +++ b/fuzz/corpus/parse/018_null.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE deleted_at IS NULL AND parent_id IS NOT NULL diff --git a/fuzz/corpus/parse/019_param.sql b/fuzz/corpus/parse/019_param.sql new file mode 100644 index 00000000..1a96fd48 --- /dev/null +++ b/fuzz/corpus/parse/019_param.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE id = $1 AND status = $2 diff --git a/fuzz/corpus/parse/020_set_ops.sql b/fuzz/corpus/parse/020_set_ops.sql new file mode 100644 index 00000000..8a346e4d --- /dev/null +++ b/fuzz/corpus/parse/020_set_ops.sql @@ -0,0 +1 @@ +SELECT id FROM admins UNION ALL SELECT id FROM moderators EXCEPT SELECT id FROM banned_users diff --git a/fuzz/crashes/crash-original b/fuzz/crashes/crash-original new file mode 100644 index 00000000..79f98c63 --- /dev/null +++ b/fuzz/crashes/crash-original @@ -0,0 +1 @@ +& \ No newline at end of file diff --git a/fuzz/fuzz_deparse.c b/fuzz/fuzz_deparse.c new file mode 100644 index 00000000..7a29066c --- /dev/null +++ b/fuzz/fuzz_deparse.c @@ -0,0 +1,21 @@ +/* + * fuzz_deparse.c - LibFuzzer harness for pg_query_deparse_protobuf + * + * Feeds arbitrary bytes as a protobuf parse-tree to the deparse path. + * This is the highest-risk path: before our fix, a truncated/invalid + * protobuf caused a SEGV via NULL-dereference in pg_query_protobuf_to_nodes. + */ +#include +#include +#include +#include "pg_query.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + PgQueryProtobuf protobuf; + protobuf.data = (char *)data; + protobuf.len = size; + + PgQueryDeparseResult result = pg_query_deparse_protobuf(protobuf); + pg_query_free_deparse_result(result); + return 0; +} diff --git a/fuzz/fuzz_parse_protobuf.c b/fuzz/fuzz_parse_protobuf.c new file mode 100644 index 00000000..fdfbcd88 --- /dev/null +++ b/fuzz/fuzz_parse_protobuf.c @@ -0,0 +1,23 @@ +/* + * fuzz_parse_protobuf.c - LibFuzzer harness for pg_query_parse_protobuf + * + * Feeds arbitrary SQL strings to the parse path. + */ +#include +#include +#include +#include +#include "pg_query.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + /* Need a null-terminated string */ + char *sql = malloc(size + 1); + if (!sql) return 0; + memcpy(sql, data, size); + sql[size] = '\0'; + + PgQueryProtobufParseResult result = pg_query_parse_protobuf(sql); + pg_query_free_protobuf_parse_result(result); + free(sql); + return 0; +} diff --git a/fuzz/fuzz_roundtrip.c b/fuzz/fuzz_roundtrip.c new file mode 100644 index 00000000..a166cc62 --- /dev/null +++ b/fuzz/fuzz_roundtrip.c @@ -0,0 +1,29 @@ +/* + * fuzz_roundtrip.c - LibFuzzer harness for parse → deparse round-trip + * + * Parses arbitrary SQL then deparses the resulting protobuf. + * Verifies that any successfully parsed query can be deparsed without crashing. + */ +#include +#include +#include +#include +#include "pg_query.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *sql = malloc(size + 1); + if (!sql) return 0; + memcpy(sql, data, size); + sql[size] = '\0'; + + PgQueryProtobufParseResult parse_result = pg_query_parse_protobuf(sql); + free(sql); + + if (!parse_result.error) { + PgQueryDeparseResult deparse_result = pg_query_deparse_protobuf(parse_result.parse_tree); + pg_query_free_deparse_result(deparse_result); + } + + pg_query_free_protobuf_parse_result(parse_result); + return 0; +} diff --git a/fuzz/fuzz_scan.c b/fuzz/fuzz_scan.c new file mode 100644 index 00000000..adaacca1 --- /dev/null +++ b/fuzz/fuzz_scan.c @@ -0,0 +1,22 @@ +/* + * fuzz_scan.c - LibFuzzer harness for pg_query_scan + * + * Feeds arbitrary SQL strings to the scanner/tokenizer path. + */ +#include +#include +#include +#include +#include "pg_query.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *sql = malloc(size + 1); + if (!sql) return 0; + memcpy(sql, data, size); + sql[size] = '\0'; + + PgQueryScanResult result = pg_query_scan(sql); + pg_query_free_scan_result(result); + free(sql); + return 0; +} diff --git a/fuzz/gen_deparse_corpus.c b/fuzz/gen_deparse_corpus.c new file mode 100644 index 00000000..6aee0ddb --- /dev/null +++ b/fuzz/gen_deparse_corpus.c @@ -0,0 +1,48 @@ +/* + * gen_deparse_corpus.c - Generate binary protobuf seeds for fuzz_deparse + * + * Parses each SQL statement passed on argv and writes the raw protobuf + * bytes to a file in the output directory. + * + * Usage: + * ./gen_deparse_corpus [ ...] + */ +#include +#include +#include +#include "pg_query.h" + +int main(int argc, char **argv) { + if (argc < 3) { + fprintf(stderr, "Usage: %s [ ...]\n", argv[0]); + return 1; + } + + const char *outdir = argv[1]; + int ok = 0, fail = 0; + + for (int i = 2; i < argc; i++) { + PgQueryProtobufParseResult result = pg_query_parse_protobuf(argv[i]); + if (result.error) { + fprintf(stderr, " skip [%d]: parse error: %s\n", i - 1, result.error->message); + fail++; + } else { + char path[4096]; + snprintf(path, sizeof(path), "%s/%03d.pb", outdir, i - 1); + FILE *f = fopen(path, "wb"); + if (!f) { + perror(path); + pg_query_free_protobuf_parse_result(result); + return 1; + } + fwrite(result.parse_tree.data, 1, result.parse_tree.len, f); + fclose(f); + fprintf(stderr, " wrote %s (%zu bytes)\n", path, result.parse_tree.len); + ok++; + } + pg_query_free_protobuf_parse_result(result); + } + + fprintf(stderr, "Done: %d written, %d skipped\n", ok, fail); + return 0; +} diff --git a/lib/pg_query.ex b/lib/pg_query.ex index ffc551bb..6d6821bb 100644 --- a/lib/pg_query.ex +++ b/lib/pg_query.ex @@ -1,5 +1,8 @@ defmodule PgQuery do @type error() :: %{message: String.t(), cursorpos: non_neg_integer()} + + defdelegate max_query_size(), to: PgQuery.Parser + @doc """ Parses the binary statement `stmt` into a Protobuf AST. diff --git a/lib/pg_query/parser.ex b/lib/pg_query/parser.ex index 4f11fe6b..4db4c37d 100644 --- a/lib/pg_query/parser.ex +++ b/lib/pg_query/parser.ex @@ -33,8 +33,12 @@ defmodule PgQuery.Parser do end def protobuf_to_query(%PgQuery.ParseResult{} = parse_result) do - with {:ok, encoded, _byte_size} <- Protox.encode(parse_result) do - deparse_query(IO.iodata_to_binary(encoded)) + try do + with {:ok, encoded, _byte_size} <- Protox.encode(parse_result) do + deparse_query(IO.iodata_to_binary(encoded)) + end + rescue + e -> {:error, %{message: "protobuf encoding failed: #{Exception.message(e)}"}} end end @@ -67,4 +71,5 @@ defmodule PgQuery.Parser do def parse_query(_query), do: :erlang.nif_error(:nif_not_loaded) def deparse_query(_encoded_proto), do: :erlang.nif_error(:nif_not_loaded) def scan_query(_query), do: :erlang.nif_error(:nif_not_loaded) + def max_query_size, do: :erlang.nif_error(:nif_not_loaded) end diff --git a/lib/pg_query/proto/elixir_pg_query_a__array_expr.ex b/lib/pg_query/proto/pg_query_a__array_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__array_expr.ex rename to lib/pg_query/proto/pg_query_a__array_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_a__const.ex b/lib/pg_query/proto/pg_query_a__const.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__const.ex rename to lib/pg_query/proto/pg_query_a__const.ex diff --git a/lib/pg_query/proto/elixir_pg_query_a__expr.ex b/lib/pg_query/proto/pg_query_a__expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__expr.ex rename to lib/pg_query/proto/pg_query_a__expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_a__expr__kind.ex b/lib/pg_query/proto/pg_query_a__expr__kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__expr__kind.ex rename to lib/pg_query/proto/pg_query_a__expr__kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_a__indices.ex b/lib/pg_query/proto/pg_query_a__indices.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__indices.ex rename to lib/pg_query/proto/pg_query_a__indices.ex diff --git a/lib/pg_query/proto/elixir_pg_query_a__indirection.ex b/lib/pg_query/proto/pg_query_a__indirection.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__indirection.ex rename to lib/pg_query/proto/pg_query_a__indirection.ex diff --git a/lib/pg_query/proto/elixir_pg_query_a__star.ex b/lib/pg_query/proto/pg_query_a__star.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_a__star.ex rename to lib/pg_query/proto/pg_query_a__star.ex diff --git a/lib/pg_query/proto/elixir_pg_query_access_priv.ex b/lib/pg_query/proto/pg_query_access_priv.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_access_priv.ex rename to lib/pg_query/proto/pg_query_access_priv.ex diff --git a/lib/pg_query/proto/elixir_pg_query_agg_split.ex b/lib/pg_query/proto/pg_query_agg_split.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_agg_split.ex rename to lib/pg_query/proto/pg_query_agg_split.ex diff --git a/lib/pg_query/proto/elixir_pg_query_agg_strategy.ex b/lib/pg_query/proto/pg_query_agg_strategy.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_agg_strategy.ex rename to lib/pg_query/proto/pg_query_agg_strategy.ex diff --git a/lib/pg_query/proto/elixir_pg_query_aggref.ex b/lib/pg_query/proto/pg_query_aggref.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_aggref.ex rename to lib/pg_query/proto/pg_query_aggref.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alias.ex b/lib/pg_query/proto/pg_query_alias.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alias.ex rename to lib/pg_query/proto/pg_query_alias.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_collation_stmt.ex b/lib/pg_query/proto/pg_query_alter_collation_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_collation_stmt.ex rename to lib/pg_query/proto/pg_query_alter_collation_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_database_refresh_coll_stmt.ex b/lib/pg_query/proto/pg_query_alter_database_refresh_coll_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_database_refresh_coll_stmt.ex rename to lib/pg_query/proto/pg_query_alter_database_refresh_coll_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_database_set_stmt.ex b/lib/pg_query/proto/pg_query_alter_database_set_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_database_set_stmt.ex rename to lib/pg_query/proto/pg_query_alter_database_set_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_database_stmt.ex b/lib/pg_query/proto/pg_query_alter_database_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_database_stmt.ex rename to lib/pg_query/proto/pg_query_alter_database_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_default_privileges_stmt.ex b/lib/pg_query/proto/pg_query_alter_default_privileges_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_default_privileges_stmt.ex rename to lib/pg_query/proto/pg_query_alter_default_privileges_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_domain_stmt.ex b/lib/pg_query/proto/pg_query_alter_domain_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_domain_stmt.ex rename to lib/pg_query/proto/pg_query_alter_domain_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_enum_stmt.ex b/lib/pg_query/proto/pg_query_alter_enum_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_enum_stmt.ex rename to lib/pg_query/proto/pg_query_alter_enum_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_event_trig_stmt.ex b/lib/pg_query/proto/pg_query_alter_event_trig_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_event_trig_stmt.ex rename to lib/pg_query/proto/pg_query_alter_event_trig_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_extension_contents_stmt.ex b/lib/pg_query/proto/pg_query_alter_extension_contents_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_extension_contents_stmt.ex rename to lib/pg_query/proto/pg_query_alter_extension_contents_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_extension_stmt.ex b/lib/pg_query/proto/pg_query_alter_extension_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_extension_stmt.ex rename to lib/pg_query/proto/pg_query_alter_extension_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_fdw_stmt.ex b/lib/pg_query/proto/pg_query_alter_fdw_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_fdw_stmt.ex rename to lib/pg_query/proto/pg_query_alter_fdw_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_foreign_server_stmt.ex b/lib/pg_query/proto/pg_query_alter_foreign_server_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_foreign_server_stmt.ex rename to lib/pg_query/proto/pg_query_alter_foreign_server_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_function_stmt.ex b/lib/pg_query/proto/pg_query_alter_function_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_function_stmt.ex rename to lib/pg_query/proto/pg_query_alter_function_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_object_depends_stmt.ex b/lib/pg_query/proto/pg_query_alter_object_depends_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_object_depends_stmt.ex rename to lib/pg_query/proto/pg_query_alter_object_depends_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_object_schema_stmt.ex b/lib/pg_query/proto/pg_query_alter_object_schema_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_object_schema_stmt.ex rename to lib/pg_query/proto/pg_query_alter_object_schema_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_op_family_stmt.ex b/lib/pg_query/proto/pg_query_alter_op_family_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_op_family_stmt.ex rename to lib/pg_query/proto/pg_query_alter_op_family_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_operator_stmt.ex b/lib/pg_query/proto/pg_query_alter_operator_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_operator_stmt.ex rename to lib/pg_query/proto/pg_query_alter_operator_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_owner_stmt.ex b/lib/pg_query/proto/pg_query_alter_owner_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_owner_stmt.ex rename to lib/pg_query/proto/pg_query_alter_owner_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_policy_stmt.ex b/lib/pg_query/proto/pg_query_alter_policy_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_policy_stmt.ex rename to lib/pg_query/proto/pg_query_alter_policy_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_publication_action.ex b/lib/pg_query/proto/pg_query_alter_publication_action.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_publication_action.ex rename to lib/pg_query/proto/pg_query_alter_publication_action.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_publication_stmt.ex b/lib/pg_query/proto/pg_query_alter_publication_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_publication_stmt.ex rename to lib/pg_query/proto/pg_query_alter_publication_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_role_set_stmt.ex b/lib/pg_query/proto/pg_query_alter_role_set_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_role_set_stmt.ex rename to lib/pg_query/proto/pg_query_alter_role_set_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_role_stmt.ex b/lib/pg_query/proto/pg_query_alter_role_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_role_stmt.ex rename to lib/pg_query/proto/pg_query_alter_role_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_seq_stmt.ex b/lib/pg_query/proto/pg_query_alter_seq_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_seq_stmt.ex rename to lib/pg_query/proto/pg_query_alter_seq_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_stats_stmt.ex b/lib/pg_query/proto/pg_query_alter_stats_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_stats_stmt.ex rename to lib/pg_query/proto/pg_query_alter_stats_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_subscription_stmt.ex b/lib/pg_query/proto/pg_query_alter_subscription_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_subscription_stmt.ex rename to lib/pg_query/proto/pg_query_alter_subscription_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_subscription_type.ex b/lib/pg_query/proto/pg_query_alter_subscription_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_subscription_type.ex rename to lib/pg_query/proto/pg_query_alter_subscription_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_system_stmt.ex b/lib/pg_query/proto/pg_query_alter_system_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_system_stmt.ex rename to lib/pg_query/proto/pg_query_alter_system_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_table_cmd.ex b/lib/pg_query/proto/pg_query_alter_table_cmd.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_table_cmd.ex rename to lib/pg_query/proto/pg_query_alter_table_cmd.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_table_move_all_stmt.ex b/lib/pg_query/proto/pg_query_alter_table_move_all_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_table_move_all_stmt.ex rename to lib/pg_query/proto/pg_query_alter_table_move_all_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_table_space_options_stmt.ex b/lib/pg_query/proto/pg_query_alter_table_space_options_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_table_space_options_stmt.ex rename to lib/pg_query/proto/pg_query_alter_table_space_options_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_table_stmt.ex b/lib/pg_query/proto/pg_query_alter_table_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_table_stmt.ex rename to lib/pg_query/proto/pg_query_alter_table_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_table_type.ex b/lib/pg_query/proto/pg_query_alter_table_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_table_type.ex rename to lib/pg_query/proto/pg_query_alter_table_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_ts_config_type.ex b/lib/pg_query/proto/pg_query_alter_ts_config_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_ts_config_type.ex rename to lib/pg_query/proto/pg_query_alter_ts_config_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_ts_configuration_stmt.ex b/lib/pg_query/proto/pg_query_alter_ts_configuration_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_ts_configuration_stmt.ex rename to lib/pg_query/proto/pg_query_alter_ts_configuration_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_ts_dictionary_stmt.ex b/lib/pg_query/proto/pg_query_alter_ts_dictionary_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_ts_dictionary_stmt.ex rename to lib/pg_query/proto/pg_query_alter_ts_dictionary_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_type_stmt.ex b/lib/pg_query/proto/pg_query_alter_type_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_type_stmt.ex rename to lib/pg_query/proto/pg_query_alter_type_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alter_user_mapping_stmt.ex b/lib/pg_query/proto/pg_query_alter_user_mapping_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alter_user_mapping_stmt.ex rename to lib/pg_query/proto/pg_query_alter_user_mapping_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_alternative_sub_plan.ex b/lib/pg_query/proto/pg_query_alternative_sub_plan.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_alternative_sub_plan.ex rename to lib/pg_query/proto/pg_query_alternative_sub_plan.ex diff --git a/lib/pg_query/proto/elixir_pg_query_array_coerce_expr.ex b/lib/pg_query/proto/pg_query_array_coerce_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_array_coerce_expr.ex rename to lib/pg_query/proto/pg_query_array_coerce_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_array_expr.ex b/lib/pg_query/proto/pg_query_array_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_array_expr.ex rename to lib/pg_query/proto/pg_query_array_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_bit_string.ex b/lib/pg_query/proto/pg_query_bit_string.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_bit_string.ex rename to lib/pg_query/proto/pg_query_bit_string.ex diff --git a/lib/pg_query/proto/elixir_pg_query_bool_expr.ex b/lib/pg_query/proto/pg_query_bool_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_bool_expr.ex rename to lib/pg_query/proto/pg_query_bool_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_bool_expr_type.ex b/lib/pg_query/proto/pg_query_bool_expr_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_bool_expr_type.ex rename to lib/pg_query/proto/pg_query_bool_expr_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_bool_test_type.ex b/lib/pg_query/proto/pg_query_bool_test_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_bool_test_type.ex rename to lib/pg_query/proto/pg_query_bool_test_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_boolean.ex b/lib/pg_query/proto/pg_query_boolean.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_boolean.ex rename to lib/pg_query/proto/pg_query_boolean.ex diff --git a/lib/pg_query/proto/elixir_pg_query_boolean_test.ex b/lib/pg_query/proto/pg_query_boolean_test.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_boolean_test.ex rename to lib/pg_query/proto/pg_query_boolean_test.ex diff --git a/lib/pg_query/proto/elixir_pg_query_call_context.ex b/lib/pg_query/proto/pg_query_call_context.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_call_context.ex rename to lib/pg_query/proto/pg_query_call_context.ex diff --git a/lib/pg_query/proto/elixir_pg_query_call_stmt.ex b/lib/pg_query/proto/pg_query_call_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_call_stmt.ex rename to lib/pg_query/proto/pg_query_call_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_case_expr.ex b/lib/pg_query/proto/pg_query_case_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_case_expr.ex rename to lib/pg_query/proto/pg_query_case_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_case_test_expr.ex b/lib/pg_query/proto/pg_query_case_test_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_case_test_expr.ex rename to lib/pg_query/proto/pg_query_case_test_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_case_when.ex b/lib/pg_query/proto/pg_query_case_when.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_case_when.ex rename to lib/pg_query/proto/pg_query_case_when.ex diff --git a/lib/pg_query/proto/elixir_pg_query_check_point_stmt.ex b/lib/pg_query/proto/pg_query_check_point_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_check_point_stmt.ex rename to lib/pg_query/proto/pg_query_check_point_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_close_portal_stmt.ex b/lib/pg_query/proto/pg_query_close_portal_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_close_portal_stmt.ex rename to lib/pg_query/proto/pg_query_close_portal_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_cluster_stmt.ex b/lib/pg_query/proto/pg_query_cluster_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_cluster_stmt.ex rename to lib/pg_query/proto/pg_query_cluster_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_cmd_type.ex b/lib/pg_query/proto/pg_query_cmd_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_cmd_type.ex rename to lib/pg_query/proto/pg_query_cmd_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_coalesce_expr.ex b/lib/pg_query/proto/pg_query_coalesce_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_coalesce_expr.ex rename to lib/pg_query/proto/pg_query_coalesce_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_coerce_to_domain.ex b/lib/pg_query/proto/pg_query_coerce_to_domain.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_coerce_to_domain.ex rename to lib/pg_query/proto/pg_query_coerce_to_domain.ex diff --git a/lib/pg_query/proto/elixir_pg_query_coerce_to_domain_value.ex b/lib/pg_query/proto/pg_query_coerce_to_domain_value.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_coerce_to_domain_value.ex rename to lib/pg_query/proto/pg_query_coerce_to_domain_value.ex diff --git a/lib/pg_query/proto/elixir_pg_query_coerce_via_io.ex b/lib/pg_query/proto/pg_query_coerce_via_io.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_coerce_via_io.ex rename to lib/pg_query/proto/pg_query_coerce_via_io.ex diff --git a/lib/pg_query/proto/elixir_pg_query_coercion_context.ex b/lib/pg_query/proto/pg_query_coercion_context.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_coercion_context.ex rename to lib/pg_query/proto/pg_query_coercion_context.ex diff --git a/lib/pg_query/proto/elixir_pg_query_coercion_form.ex b/lib/pg_query/proto/pg_query_coercion_form.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_coercion_form.ex rename to lib/pg_query/proto/pg_query_coercion_form.ex diff --git a/lib/pg_query/proto/elixir_pg_query_collate_clause.ex b/lib/pg_query/proto/pg_query_collate_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_collate_clause.ex rename to lib/pg_query/proto/pg_query_collate_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_collate_expr.ex b/lib/pg_query/proto/pg_query_collate_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_collate_expr.ex rename to lib/pg_query/proto/pg_query_collate_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_column_def.ex b/lib/pg_query/proto/pg_query_column_def.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_column_def.ex rename to lib/pg_query/proto/pg_query_column_def.ex diff --git a/lib/pg_query/proto/elixir_pg_query_column_ref.ex b/lib/pg_query/proto/pg_query_column_ref.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_column_ref.ex rename to lib/pg_query/proto/pg_query_column_ref.ex diff --git a/lib/pg_query/proto/elixir_pg_query_comment_stmt.ex b/lib/pg_query/proto/pg_query_comment_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_comment_stmt.ex rename to lib/pg_query/proto/pg_query_comment_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_common_table_expr.ex b/lib/pg_query/proto/pg_query_common_table_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_common_table_expr.ex rename to lib/pg_query/proto/pg_query_common_table_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_composite_type_stmt.ex b/lib/pg_query/proto/pg_query_composite_type_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_composite_type_stmt.ex rename to lib/pg_query/proto/pg_query_composite_type_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_constr_type.ex b/lib/pg_query/proto/pg_query_constr_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_constr_type.ex rename to lib/pg_query/proto/pg_query_constr_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_constraint.ex b/lib/pg_query/proto/pg_query_constraint.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_constraint.ex rename to lib/pg_query/proto/pg_query_constraint.ex diff --git a/lib/pg_query/proto/elixir_pg_query_constraints_set_stmt.ex b/lib/pg_query/proto/pg_query_constraints_set_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_constraints_set_stmt.ex rename to lib/pg_query/proto/pg_query_constraints_set_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_convert_rowtype_expr.ex b/lib/pg_query/proto/pg_query_convert_rowtype_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_convert_rowtype_expr.ex rename to lib/pg_query/proto/pg_query_convert_rowtype_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_copy_stmt.ex b/lib/pg_query/proto/pg_query_copy_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_copy_stmt.ex rename to lib/pg_query/proto/pg_query_copy_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_am_stmt.ex b/lib/pg_query/proto/pg_query_create_am_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_am_stmt.ex rename to lib/pg_query/proto/pg_query_create_am_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_cast_stmt.ex b/lib/pg_query/proto/pg_query_create_cast_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_cast_stmt.ex rename to lib/pg_query/proto/pg_query_create_cast_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_conversion_stmt.ex b/lib/pg_query/proto/pg_query_create_conversion_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_conversion_stmt.ex rename to lib/pg_query/proto/pg_query_create_conversion_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_domain_stmt.ex b/lib/pg_query/proto/pg_query_create_domain_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_domain_stmt.ex rename to lib/pg_query/proto/pg_query_create_domain_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_enum_stmt.ex b/lib/pg_query/proto/pg_query_create_enum_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_enum_stmt.ex rename to lib/pg_query/proto/pg_query_create_enum_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_event_trig_stmt.ex b/lib/pg_query/proto/pg_query_create_event_trig_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_event_trig_stmt.ex rename to lib/pg_query/proto/pg_query_create_event_trig_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_extension_stmt.ex b/lib/pg_query/proto/pg_query_create_extension_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_extension_stmt.ex rename to lib/pg_query/proto/pg_query_create_extension_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_fdw_stmt.ex b/lib/pg_query/proto/pg_query_create_fdw_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_fdw_stmt.ex rename to lib/pg_query/proto/pg_query_create_fdw_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_foreign_server_stmt.ex b/lib/pg_query/proto/pg_query_create_foreign_server_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_foreign_server_stmt.ex rename to lib/pg_query/proto/pg_query_create_foreign_server_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_foreign_table_stmt.ex b/lib/pg_query/proto/pg_query_create_foreign_table_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_foreign_table_stmt.ex rename to lib/pg_query/proto/pg_query_create_foreign_table_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_function_stmt.ex b/lib/pg_query/proto/pg_query_create_function_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_function_stmt.ex rename to lib/pg_query/proto/pg_query_create_function_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_op_class_item.ex b/lib/pg_query/proto/pg_query_create_op_class_item.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_op_class_item.ex rename to lib/pg_query/proto/pg_query_create_op_class_item.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_op_class_stmt.ex b/lib/pg_query/proto/pg_query_create_op_class_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_op_class_stmt.ex rename to lib/pg_query/proto/pg_query_create_op_class_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_op_family_stmt.ex b/lib/pg_query/proto/pg_query_create_op_family_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_op_family_stmt.ex rename to lib/pg_query/proto/pg_query_create_op_family_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_p_lang_stmt.ex b/lib/pg_query/proto/pg_query_create_p_lang_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_p_lang_stmt.ex rename to lib/pg_query/proto/pg_query_create_p_lang_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_policy_stmt.ex b/lib/pg_query/proto/pg_query_create_policy_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_policy_stmt.ex rename to lib/pg_query/proto/pg_query_create_policy_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_publication_stmt.ex b/lib/pg_query/proto/pg_query_create_publication_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_publication_stmt.ex rename to lib/pg_query/proto/pg_query_create_publication_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_range_stmt.ex b/lib/pg_query/proto/pg_query_create_range_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_range_stmt.ex rename to lib/pg_query/proto/pg_query_create_range_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_role_stmt.ex b/lib/pg_query/proto/pg_query_create_role_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_role_stmt.ex rename to lib/pg_query/proto/pg_query_create_role_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_schema_stmt.ex b/lib/pg_query/proto/pg_query_create_schema_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_schema_stmt.ex rename to lib/pg_query/proto/pg_query_create_schema_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_seq_stmt.ex b/lib/pg_query/proto/pg_query_create_seq_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_seq_stmt.ex rename to lib/pg_query/proto/pg_query_create_seq_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_stats_stmt.ex b/lib/pg_query/proto/pg_query_create_stats_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_stats_stmt.ex rename to lib/pg_query/proto/pg_query_create_stats_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_stmt.ex b/lib/pg_query/proto/pg_query_create_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_stmt.ex rename to lib/pg_query/proto/pg_query_create_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_subscription_stmt.ex b/lib/pg_query/proto/pg_query_create_subscription_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_subscription_stmt.ex rename to lib/pg_query/proto/pg_query_create_subscription_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_table_as_stmt.ex b/lib/pg_query/proto/pg_query_create_table_as_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_table_as_stmt.ex rename to lib/pg_query/proto/pg_query_create_table_as_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_table_space_stmt.ex b/lib/pg_query/proto/pg_query_create_table_space_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_table_space_stmt.ex rename to lib/pg_query/proto/pg_query_create_table_space_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_transform_stmt.ex b/lib/pg_query/proto/pg_query_create_transform_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_transform_stmt.ex rename to lib/pg_query/proto/pg_query_create_transform_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_trig_stmt.ex b/lib/pg_query/proto/pg_query_create_trig_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_trig_stmt.ex rename to lib/pg_query/proto/pg_query_create_trig_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_create_user_mapping_stmt.ex b/lib/pg_query/proto/pg_query_create_user_mapping_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_create_user_mapping_stmt.ex rename to lib/pg_query/proto/pg_query_create_user_mapping_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_createdb_stmt.ex b/lib/pg_query/proto/pg_query_createdb_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_createdb_stmt.ex rename to lib/pg_query/proto/pg_query_createdb_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_cte_cycle_clause.ex b/lib/pg_query/proto/pg_query_cte_cycle_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_cte_cycle_clause.ex rename to lib/pg_query/proto/pg_query_cte_cycle_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_cte_materialize.ex b/lib/pg_query/proto/pg_query_cte_materialize.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_cte_materialize.ex rename to lib/pg_query/proto/pg_query_cte_materialize.ex diff --git a/lib/pg_query/proto/elixir_pg_query_cte_search_clause.ex b/lib/pg_query/proto/pg_query_cte_search_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_cte_search_clause.ex rename to lib/pg_query/proto/pg_query_cte_search_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_current_of_expr.ex b/lib/pg_query/proto/pg_query_current_of_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_current_of_expr.ex rename to lib/pg_query/proto/pg_query_current_of_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_deallocate_stmt.ex b/lib/pg_query/proto/pg_query_deallocate_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_deallocate_stmt.ex rename to lib/pg_query/proto/pg_query_deallocate_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_declare_cursor_stmt.ex b/lib/pg_query/proto/pg_query_declare_cursor_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_declare_cursor_stmt.ex rename to lib/pg_query/proto/pg_query_declare_cursor_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_def_elem.ex b/lib/pg_query/proto/pg_query_def_elem.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_def_elem.ex rename to lib/pg_query/proto/pg_query_def_elem.ex diff --git a/lib/pg_query/proto/elixir_pg_query_def_elem_action.ex b/lib/pg_query/proto/pg_query_def_elem_action.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_def_elem_action.ex rename to lib/pg_query/proto/pg_query_def_elem_action.ex diff --git a/lib/pg_query/proto/elixir_pg_query_define_stmt.ex b/lib/pg_query/proto/pg_query_define_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_define_stmt.ex rename to lib/pg_query/proto/pg_query_define_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_delete_stmt.ex b/lib/pg_query/proto/pg_query_delete_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_delete_stmt.ex rename to lib/pg_query/proto/pg_query_delete_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_discard_mode.ex b/lib/pg_query/proto/pg_query_discard_mode.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_discard_mode.ex rename to lib/pg_query/proto/pg_query_discard_mode.ex diff --git a/lib/pg_query/proto/elixir_pg_query_discard_stmt.ex b/lib/pg_query/proto/pg_query_discard_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_discard_stmt.ex rename to lib/pg_query/proto/pg_query_discard_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_distinct_expr.ex b/lib/pg_query/proto/pg_query_distinct_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_distinct_expr.ex rename to lib/pg_query/proto/pg_query_distinct_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_do_stmt.ex b/lib/pg_query/proto/pg_query_do_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_do_stmt.ex rename to lib/pg_query/proto/pg_query_do_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_behavior.ex b/lib/pg_query/proto/pg_query_drop_behavior.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_behavior.ex rename to lib/pg_query/proto/pg_query_drop_behavior.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_owned_stmt.ex b/lib/pg_query/proto/pg_query_drop_owned_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_owned_stmt.ex rename to lib/pg_query/proto/pg_query_drop_owned_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_role_stmt.ex b/lib/pg_query/proto/pg_query_drop_role_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_role_stmt.ex rename to lib/pg_query/proto/pg_query_drop_role_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_stmt.ex b/lib/pg_query/proto/pg_query_drop_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_stmt.ex rename to lib/pg_query/proto/pg_query_drop_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_subscription_stmt.ex b/lib/pg_query/proto/pg_query_drop_subscription_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_subscription_stmt.ex rename to lib/pg_query/proto/pg_query_drop_subscription_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_table_space_stmt.ex b/lib/pg_query/proto/pg_query_drop_table_space_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_table_space_stmt.ex rename to lib/pg_query/proto/pg_query_drop_table_space_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_drop_user_mapping_stmt.ex b/lib/pg_query/proto/pg_query_drop_user_mapping_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_drop_user_mapping_stmt.ex rename to lib/pg_query/proto/pg_query_drop_user_mapping_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_dropdb_stmt.ex b/lib/pg_query/proto/pg_query_dropdb_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_dropdb_stmt.ex rename to lib/pg_query/proto/pg_query_dropdb_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_execute_stmt.ex b/lib/pg_query/proto/pg_query_execute_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_execute_stmt.ex rename to lib/pg_query/proto/pg_query_execute_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_explain_stmt.ex b/lib/pg_query/proto/pg_query_explain_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_explain_stmt.ex rename to lib/pg_query/proto/pg_query_explain_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_fetch_direction.ex b/lib/pg_query/proto/pg_query_fetch_direction.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_fetch_direction.ex rename to lib/pg_query/proto/pg_query_fetch_direction.ex diff --git a/lib/pg_query/proto/elixir_pg_query_fetch_stmt.ex b/lib/pg_query/proto/pg_query_fetch_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_fetch_stmt.ex rename to lib/pg_query/proto/pg_query_fetch_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_field_select.ex b/lib/pg_query/proto/pg_query_field_select.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_field_select.ex rename to lib/pg_query/proto/pg_query_field_select.ex diff --git a/lib/pg_query/proto/elixir_pg_query_field_store.ex b/lib/pg_query/proto/pg_query_field_store.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_field_store.ex rename to lib/pg_query/proto/pg_query_field_store.ex diff --git a/lib/pg_query/proto/elixir_pg_query_float.ex b/lib/pg_query/proto/pg_query_float.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_float.ex rename to lib/pg_query/proto/pg_query_float.ex diff --git a/lib/pg_query/proto/elixir_pg_query_from_expr.ex b/lib/pg_query/proto/pg_query_from_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_from_expr.ex rename to lib/pg_query/proto/pg_query_from_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_func_call.ex b/lib/pg_query/proto/pg_query_func_call.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_func_call.ex rename to lib/pg_query/proto/pg_query_func_call.ex diff --git a/lib/pg_query/proto/elixir_pg_query_func_expr.ex b/lib/pg_query/proto/pg_query_func_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_func_expr.ex rename to lib/pg_query/proto/pg_query_func_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_function_parameter.ex b/lib/pg_query/proto/pg_query_function_parameter.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_function_parameter.ex rename to lib/pg_query/proto/pg_query_function_parameter.ex diff --git a/lib/pg_query/proto/elixir_pg_query_function_parameter_mode.ex b/lib/pg_query/proto/pg_query_function_parameter_mode.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_function_parameter_mode.ex rename to lib/pg_query/proto/pg_query_function_parameter_mode.ex diff --git a/lib/pg_query/proto/elixir_pg_query_grant_role_stmt.ex b/lib/pg_query/proto/pg_query_grant_role_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_grant_role_stmt.ex rename to lib/pg_query/proto/pg_query_grant_role_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_grant_stmt.ex b/lib/pg_query/proto/pg_query_grant_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_grant_stmt.ex rename to lib/pg_query/proto/pg_query_grant_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_grant_target_type.ex b/lib/pg_query/proto/pg_query_grant_target_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_grant_target_type.ex rename to lib/pg_query/proto/pg_query_grant_target_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_grouping_func.ex b/lib/pg_query/proto/pg_query_grouping_func.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_grouping_func.ex rename to lib/pg_query/proto/pg_query_grouping_func.ex diff --git a/lib/pg_query/proto/elixir_pg_query_grouping_set.ex b/lib/pg_query/proto/pg_query_grouping_set.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_grouping_set.ex rename to lib/pg_query/proto/pg_query_grouping_set.ex diff --git a/lib/pg_query/proto/elixir_pg_query_grouping_set_kind.ex b/lib/pg_query/proto/pg_query_grouping_set_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_grouping_set_kind.ex rename to lib/pg_query/proto/pg_query_grouping_set_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_import_foreign_schema_stmt.ex b/lib/pg_query/proto/pg_query_import_foreign_schema_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_import_foreign_schema_stmt.ex rename to lib/pg_query/proto/pg_query_import_foreign_schema_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_import_foreign_schema_type.ex b/lib/pg_query/proto/pg_query_import_foreign_schema_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_import_foreign_schema_type.ex rename to lib/pg_query/proto/pg_query_import_foreign_schema_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_index_elem.ex b/lib/pg_query/proto/pg_query_index_elem.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_index_elem.ex rename to lib/pg_query/proto/pg_query_index_elem.ex diff --git a/lib/pg_query/proto/elixir_pg_query_index_stmt.ex b/lib/pg_query/proto/pg_query_index_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_index_stmt.ex rename to lib/pg_query/proto/pg_query_index_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_infer_clause.ex b/lib/pg_query/proto/pg_query_infer_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_infer_clause.ex rename to lib/pg_query/proto/pg_query_infer_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_inference_elem.ex b/lib/pg_query/proto/pg_query_inference_elem.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_inference_elem.ex rename to lib/pg_query/proto/pg_query_inference_elem.ex diff --git a/lib/pg_query/proto/elixir_pg_query_inline_code_block.ex b/lib/pg_query/proto/pg_query_inline_code_block.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_inline_code_block.ex rename to lib/pg_query/proto/pg_query_inline_code_block.ex diff --git a/lib/pg_query/proto/elixir_pg_query_insert_stmt.ex b/lib/pg_query/proto/pg_query_insert_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_insert_stmt.ex rename to lib/pg_query/proto/pg_query_insert_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_int_list.ex b/lib/pg_query/proto/pg_query_int_list.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_int_list.ex rename to lib/pg_query/proto/pg_query_int_list.ex diff --git a/lib/pg_query/proto/elixir_pg_query_integer.ex b/lib/pg_query/proto/pg_query_integer.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_integer.ex rename to lib/pg_query/proto/pg_query_integer.ex diff --git a/lib/pg_query/proto/elixir_pg_query_into_clause.ex b/lib/pg_query/proto/pg_query_into_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_into_clause.ex rename to lib/pg_query/proto/pg_query_into_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_join_expr.ex b/lib/pg_query/proto/pg_query_join_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_join_expr.ex rename to lib/pg_query/proto/pg_query_join_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_join_type.ex b/lib/pg_query/proto/pg_query_join_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_join_type.ex rename to lib/pg_query/proto/pg_query_join_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_agg_constructor.ex b/lib/pg_query/proto/pg_query_json_agg_constructor.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_agg_constructor.ex rename to lib/pg_query/proto/pg_query_json_agg_constructor.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_argument.ex b/lib/pg_query/proto/pg_query_json_argument.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_argument.ex rename to lib/pg_query/proto/pg_query_json_argument.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_array_agg.ex b/lib/pg_query/proto/pg_query_json_array_agg.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_array_agg.ex rename to lib/pg_query/proto/pg_query_json_array_agg.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_array_constructor.ex b/lib/pg_query/proto/pg_query_json_array_constructor.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_array_constructor.ex rename to lib/pg_query/proto/pg_query_json_array_constructor.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_array_query_constructor.ex b/lib/pg_query/proto/pg_query_json_array_query_constructor.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_array_query_constructor.ex rename to lib/pg_query/proto/pg_query_json_array_query_constructor.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_behavior.ex b/lib/pg_query/proto/pg_query_json_behavior.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_behavior.ex rename to lib/pg_query/proto/pg_query_json_behavior.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_behavior_type.ex b/lib/pg_query/proto/pg_query_json_behavior_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_behavior_type.ex rename to lib/pg_query/proto/pg_query_json_behavior_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_constructor_expr.ex b/lib/pg_query/proto/pg_query_json_constructor_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_constructor_expr.ex rename to lib/pg_query/proto/pg_query_json_constructor_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_constructor_type.ex b/lib/pg_query/proto/pg_query_json_constructor_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_constructor_type.ex rename to lib/pg_query/proto/pg_query_json_constructor_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_encoding.ex b/lib/pg_query/proto/pg_query_json_encoding.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_encoding.ex rename to lib/pg_query/proto/pg_query_json_encoding.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_expr.ex b/lib/pg_query/proto/pg_query_json_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_expr.ex rename to lib/pg_query/proto/pg_query_json_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_expr_op.ex b/lib/pg_query/proto/pg_query_json_expr_op.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_expr_op.ex rename to lib/pg_query/proto/pg_query_json_expr_op.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_format.ex b/lib/pg_query/proto/pg_query_json_format.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_format.ex rename to lib/pg_query/proto/pg_query_json_format.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_format_type.ex b/lib/pg_query/proto/pg_query_json_format_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_format_type.ex rename to lib/pg_query/proto/pg_query_json_format_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_func_expr.ex b/lib/pg_query/proto/pg_query_json_func_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_func_expr.ex rename to lib/pg_query/proto/pg_query_json_func_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_is_predicate.ex b/lib/pg_query/proto/pg_query_json_is_predicate.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_is_predicate.ex rename to lib/pg_query/proto/pg_query_json_is_predicate.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_key_value.ex b/lib/pg_query/proto/pg_query_json_key_value.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_key_value.ex rename to lib/pg_query/proto/pg_query_json_key_value.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_object_agg.ex b/lib/pg_query/proto/pg_query_json_object_agg.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_object_agg.ex rename to lib/pg_query/proto/pg_query_json_object_agg.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_object_constructor.ex b/lib/pg_query/proto/pg_query_json_object_constructor.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_object_constructor.ex rename to lib/pg_query/proto/pg_query_json_object_constructor.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_output.ex b/lib/pg_query/proto/pg_query_json_output.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_output.ex rename to lib/pg_query/proto/pg_query_json_output.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_parse_expr.ex b/lib/pg_query/proto/pg_query_json_parse_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_parse_expr.ex rename to lib/pg_query/proto/pg_query_json_parse_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_quotes.ex b/lib/pg_query/proto/pg_query_json_quotes.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_quotes.ex rename to lib/pg_query/proto/pg_query_json_quotes.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_returning.ex b/lib/pg_query/proto/pg_query_json_returning.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_returning.ex rename to lib/pg_query/proto/pg_query_json_returning.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_scalar_expr.ex b/lib/pg_query/proto/pg_query_json_scalar_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_scalar_expr.ex rename to lib/pg_query/proto/pg_query_json_scalar_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_serialize_expr.ex b/lib/pg_query/proto/pg_query_json_serialize_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_serialize_expr.ex rename to lib/pg_query/proto/pg_query_json_serialize_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table.ex b/lib/pg_query/proto/pg_query_json_table.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table.ex rename to lib/pg_query/proto/pg_query_json_table.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table_column.ex b/lib/pg_query/proto/pg_query_json_table_column.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table_column.ex rename to lib/pg_query/proto/pg_query_json_table_column.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table_column_type.ex b/lib/pg_query/proto/pg_query_json_table_column_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table_column_type.ex rename to lib/pg_query/proto/pg_query_json_table_column_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table_path.ex b/lib/pg_query/proto/pg_query_json_table_path.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table_path.ex rename to lib/pg_query/proto/pg_query_json_table_path.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table_path_scan.ex b/lib/pg_query/proto/pg_query_json_table_path_scan.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table_path_scan.ex rename to lib/pg_query/proto/pg_query_json_table_path_scan.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table_path_spec.ex b/lib/pg_query/proto/pg_query_json_table_path_spec.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table_path_spec.ex rename to lib/pg_query/proto/pg_query_json_table_path_spec.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_table_sibling_join.ex b/lib/pg_query/proto/pg_query_json_table_sibling_join.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_table_sibling_join.ex rename to lib/pg_query/proto/pg_query_json_table_sibling_join.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_value_expr.ex b/lib/pg_query/proto/pg_query_json_value_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_value_expr.ex rename to lib/pg_query/proto/pg_query_json_value_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_value_type.ex b/lib/pg_query/proto/pg_query_json_value_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_value_type.ex rename to lib/pg_query/proto/pg_query_json_value_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_json_wrapper.ex b/lib/pg_query/proto/pg_query_json_wrapper.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_json_wrapper.ex rename to lib/pg_query/proto/pg_query_json_wrapper.ex diff --git a/lib/pg_query/proto/elixir_pg_query_keyword_kind.ex b/lib/pg_query/proto/pg_query_keyword_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_keyword_kind.ex rename to lib/pg_query/proto/pg_query_keyword_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_limit_option.ex b/lib/pg_query/proto/pg_query_limit_option.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_limit_option.ex rename to lib/pg_query/proto/pg_query_limit_option.ex diff --git a/lib/pg_query/proto/elixir_pg_query_list.ex b/lib/pg_query/proto/pg_query_list.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_list.ex rename to lib/pg_query/proto/pg_query_list.ex diff --git a/lib/pg_query/proto/elixir_pg_query_listen_stmt.ex b/lib/pg_query/proto/pg_query_listen_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_listen_stmt.ex rename to lib/pg_query/proto/pg_query_listen_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_load_stmt.ex b/lib/pg_query/proto/pg_query_load_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_load_stmt.ex rename to lib/pg_query/proto/pg_query_load_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_lock_clause_strength.ex b/lib/pg_query/proto/pg_query_lock_clause_strength.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_lock_clause_strength.ex rename to lib/pg_query/proto/pg_query_lock_clause_strength.ex diff --git a/lib/pg_query/proto/elixir_pg_query_lock_stmt.ex b/lib/pg_query/proto/pg_query_lock_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_lock_stmt.ex rename to lib/pg_query/proto/pg_query_lock_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_lock_tuple_mode.ex b/lib/pg_query/proto/pg_query_lock_tuple_mode.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_lock_tuple_mode.ex rename to lib/pg_query/proto/pg_query_lock_tuple_mode.ex diff --git a/lib/pg_query/proto/elixir_pg_query_lock_wait_policy.ex b/lib/pg_query/proto/pg_query_lock_wait_policy.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_lock_wait_policy.ex rename to lib/pg_query/proto/pg_query_lock_wait_policy.ex diff --git a/lib/pg_query/proto/elixir_pg_query_locking_clause.ex b/lib/pg_query/proto/pg_query_locking_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_locking_clause.ex rename to lib/pg_query/proto/pg_query_locking_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_merge_action.ex b/lib/pg_query/proto/pg_query_merge_action.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_merge_action.ex rename to lib/pg_query/proto/pg_query_merge_action.ex diff --git a/lib/pg_query/proto/elixir_pg_query_merge_match_kind.ex b/lib/pg_query/proto/pg_query_merge_match_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_merge_match_kind.ex rename to lib/pg_query/proto/pg_query_merge_match_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_merge_stmt.ex b/lib/pg_query/proto/pg_query_merge_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_merge_stmt.ex rename to lib/pg_query/proto/pg_query_merge_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_merge_support_func.ex b/lib/pg_query/proto/pg_query_merge_support_func.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_merge_support_func.ex rename to lib/pg_query/proto/pg_query_merge_support_func.ex diff --git a/lib/pg_query/proto/elixir_pg_query_merge_when_clause.ex b/lib/pg_query/proto/pg_query_merge_when_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_merge_when_clause.ex rename to lib/pg_query/proto/pg_query_merge_when_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_min_max_expr.ex b/lib/pg_query/proto/pg_query_min_max_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_min_max_expr.ex rename to lib/pg_query/proto/pg_query_min_max_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_min_max_op.ex b/lib/pg_query/proto/pg_query_min_max_op.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_min_max_op.ex rename to lib/pg_query/proto/pg_query_min_max_op.ex diff --git a/lib/pg_query/proto/elixir_pg_query_multi_assign_ref.ex b/lib/pg_query/proto/pg_query_multi_assign_ref.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_multi_assign_ref.ex rename to lib/pg_query/proto/pg_query_multi_assign_ref.ex diff --git a/lib/pg_query/proto/elixir_pg_query_named_arg_expr.ex b/lib/pg_query/proto/pg_query_named_arg_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_named_arg_expr.ex rename to lib/pg_query/proto/pg_query_named_arg_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_next_value_expr.ex b/lib/pg_query/proto/pg_query_next_value_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_next_value_expr.ex rename to lib/pg_query/proto/pg_query_next_value_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_node.ex b/lib/pg_query/proto/pg_query_node.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_node.ex rename to lib/pg_query/proto/pg_query_node.ex diff --git a/lib/pg_query/proto/elixir_pg_query_notify_stmt.ex b/lib/pg_query/proto/pg_query_notify_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_notify_stmt.ex rename to lib/pg_query/proto/pg_query_notify_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_null_if_expr.ex b/lib/pg_query/proto/pg_query_null_if_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_null_if_expr.ex rename to lib/pg_query/proto/pg_query_null_if_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_null_test.ex b/lib/pg_query/proto/pg_query_null_test.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_null_test.ex rename to lib/pg_query/proto/pg_query_null_test.ex diff --git a/lib/pg_query/proto/elixir_pg_query_null_test_type.ex b/lib/pg_query/proto/pg_query_null_test_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_null_test_type.ex rename to lib/pg_query/proto/pg_query_null_test_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_object_type.ex b/lib/pg_query/proto/pg_query_object_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_object_type.ex rename to lib/pg_query/proto/pg_query_object_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_object_with_args.ex b/lib/pg_query/proto/pg_query_object_with_args.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_object_with_args.ex rename to lib/pg_query/proto/pg_query_object_with_args.ex diff --git a/lib/pg_query/proto/elixir_pg_query_oid_list.ex b/lib/pg_query/proto/pg_query_oid_list.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_oid_list.ex rename to lib/pg_query/proto/pg_query_oid_list.ex diff --git a/lib/pg_query/proto/elixir_pg_query_on_commit_action.ex b/lib/pg_query/proto/pg_query_on_commit_action.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_on_commit_action.ex rename to lib/pg_query/proto/pg_query_on_commit_action.ex diff --git a/lib/pg_query/proto/elixir_pg_query_on_conflict_action.ex b/lib/pg_query/proto/pg_query_on_conflict_action.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_on_conflict_action.ex rename to lib/pg_query/proto/pg_query_on_conflict_action.ex diff --git a/lib/pg_query/proto/elixir_pg_query_on_conflict_clause.ex b/lib/pg_query/proto/pg_query_on_conflict_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_on_conflict_clause.ex rename to lib/pg_query/proto/pg_query_on_conflict_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_on_conflict_expr.ex b/lib/pg_query/proto/pg_query_on_conflict_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_on_conflict_expr.ex rename to lib/pg_query/proto/pg_query_on_conflict_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_op_expr.ex b/lib/pg_query/proto/pg_query_op_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_op_expr.ex rename to lib/pg_query/proto/pg_query_op_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_overriding_kind.ex b/lib/pg_query/proto/pg_query_overriding_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_overriding_kind.ex rename to lib/pg_query/proto/pg_query_overriding_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_param.ex b/lib/pg_query/proto/pg_query_param.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_param.ex rename to lib/pg_query/proto/pg_query_param.ex diff --git a/lib/pg_query/proto/elixir_pg_query_param_kind.ex b/lib/pg_query/proto/pg_query_param_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_param_kind.ex rename to lib/pg_query/proto/pg_query_param_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_param_ref.ex b/lib/pg_query/proto/pg_query_param_ref.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_param_ref.ex rename to lib/pg_query/proto/pg_query_param_ref.ex diff --git a/lib/pg_query/proto/elixir_pg_query_parse_result.ex b/lib/pg_query/proto/pg_query_parse_result.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_parse_result.ex rename to lib/pg_query/proto/pg_query_parse_result.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_bound_spec.ex b/lib/pg_query/proto/pg_query_partition_bound_spec.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_bound_spec.ex rename to lib/pg_query/proto/pg_query_partition_bound_spec.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_cmd.ex b/lib/pg_query/proto/pg_query_partition_cmd.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_cmd.ex rename to lib/pg_query/proto/pg_query_partition_cmd.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_elem.ex b/lib/pg_query/proto/pg_query_partition_elem.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_elem.ex rename to lib/pg_query/proto/pg_query_partition_elem.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_range_datum.ex b/lib/pg_query/proto/pg_query_partition_range_datum.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_range_datum.ex rename to lib/pg_query/proto/pg_query_partition_range_datum.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_range_datum_kind.ex b/lib/pg_query/proto/pg_query_partition_range_datum_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_range_datum_kind.ex rename to lib/pg_query/proto/pg_query_partition_range_datum_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_spec.ex b/lib/pg_query/proto/pg_query_partition_spec.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_spec.ex rename to lib/pg_query/proto/pg_query_partition_spec.ex diff --git a/lib/pg_query/proto/elixir_pg_query_partition_strategy.ex b/lib/pg_query/proto/pg_query_partition_strategy.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_partition_strategy.ex rename to lib/pg_query/proto/pg_query_partition_strategy.ex diff --git a/lib/pg_query/proto/elixir_pg_query_pl_assign_stmt.ex b/lib/pg_query/proto/pg_query_pl_assign_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_pl_assign_stmt.ex rename to lib/pg_query/proto/pg_query_pl_assign_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_prepare_stmt.ex b/lib/pg_query/proto/pg_query_prepare_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_prepare_stmt.ex rename to lib/pg_query/proto/pg_query_prepare_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_publication_obj_spec.ex b/lib/pg_query/proto/pg_query_publication_obj_spec.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_publication_obj_spec.ex rename to lib/pg_query/proto/pg_query_publication_obj_spec.ex diff --git a/lib/pg_query/proto/elixir_pg_query_publication_obj_spec_type.ex b/lib/pg_query/proto/pg_query_publication_obj_spec_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_publication_obj_spec_type.ex rename to lib/pg_query/proto/pg_query_publication_obj_spec_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_publication_table.ex b/lib/pg_query/proto/pg_query_publication_table.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_publication_table.ex rename to lib/pg_query/proto/pg_query_publication_table.ex diff --git a/lib/pg_query/proto/elixir_pg_query_query.ex b/lib/pg_query/proto/pg_query_query.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_query.ex rename to lib/pg_query/proto/pg_query_query.ex diff --git a/lib/pg_query/proto/elixir_pg_query_query_source.ex b/lib/pg_query/proto/pg_query_query_source.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_query_source.ex rename to lib/pg_query/proto/pg_query_query_source.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_function.ex b/lib/pg_query/proto/pg_query_range_function.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_function.ex rename to lib/pg_query/proto/pg_query_range_function.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_subselect.ex b/lib/pg_query/proto/pg_query_range_subselect.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_subselect.ex rename to lib/pg_query/proto/pg_query_range_subselect.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_table_func.ex b/lib/pg_query/proto/pg_query_range_table_func.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_table_func.ex rename to lib/pg_query/proto/pg_query_range_table_func.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_table_func_col.ex b/lib/pg_query/proto/pg_query_range_table_func_col.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_table_func_col.ex rename to lib/pg_query/proto/pg_query_range_table_func_col.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_table_sample.ex b/lib/pg_query/proto/pg_query_range_table_sample.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_table_sample.ex rename to lib/pg_query/proto/pg_query_range_table_sample.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_tbl_entry.ex b/lib/pg_query/proto/pg_query_range_tbl_entry.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_tbl_entry.ex rename to lib/pg_query/proto/pg_query_range_tbl_entry.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_tbl_function.ex b/lib/pg_query/proto/pg_query_range_tbl_function.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_tbl_function.ex rename to lib/pg_query/proto/pg_query_range_tbl_function.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_tbl_ref.ex b/lib/pg_query/proto/pg_query_range_tbl_ref.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_tbl_ref.ex rename to lib/pg_query/proto/pg_query_range_tbl_ref.ex diff --git a/lib/pg_query/proto/elixir_pg_query_range_var.ex b/lib/pg_query/proto/pg_query_range_var.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_range_var.ex rename to lib/pg_query/proto/pg_query_range_var.ex diff --git a/lib/pg_query/proto/elixir_pg_query_raw_stmt.ex b/lib/pg_query/proto/pg_query_raw_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_raw_stmt.ex rename to lib/pg_query/proto/pg_query_raw_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_reassign_owned_stmt.ex b/lib/pg_query/proto/pg_query_reassign_owned_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_reassign_owned_stmt.ex rename to lib/pg_query/proto/pg_query_reassign_owned_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_refresh_mat_view_stmt.ex b/lib/pg_query/proto/pg_query_refresh_mat_view_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_refresh_mat_view_stmt.ex rename to lib/pg_query/proto/pg_query_refresh_mat_view_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_reindex_object_type.ex b/lib/pg_query/proto/pg_query_reindex_object_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_reindex_object_type.ex rename to lib/pg_query/proto/pg_query_reindex_object_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_reindex_stmt.ex b/lib/pg_query/proto/pg_query_reindex_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_reindex_stmt.ex rename to lib/pg_query/proto/pg_query_reindex_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_relabel_type.ex b/lib/pg_query/proto/pg_query_relabel_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_relabel_type.ex rename to lib/pg_query/proto/pg_query_relabel_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_rename_stmt.ex b/lib/pg_query/proto/pg_query_rename_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_rename_stmt.ex rename to lib/pg_query/proto/pg_query_rename_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_replica_identity_stmt.ex b/lib/pg_query/proto/pg_query_replica_identity_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_replica_identity_stmt.ex rename to lib/pg_query/proto/pg_query_replica_identity_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_res_target.ex b/lib/pg_query/proto/pg_query_res_target.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_res_target.ex rename to lib/pg_query/proto/pg_query_res_target.ex diff --git a/lib/pg_query/proto/elixir_pg_query_return_stmt.ex b/lib/pg_query/proto/pg_query_return_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_return_stmt.ex rename to lib/pg_query/proto/pg_query_return_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_role_spec.ex b/lib/pg_query/proto/pg_query_role_spec.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_role_spec.ex rename to lib/pg_query/proto/pg_query_role_spec.ex diff --git a/lib/pg_query/proto/elixir_pg_query_role_spec_type.ex b/lib/pg_query/proto/pg_query_role_spec_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_role_spec_type.ex rename to lib/pg_query/proto/pg_query_role_spec_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_role_stmt_type.ex b/lib/pg_query/proto/pg_query_role_stmt_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_role_stmt_type.ex rename to lib/pg_query/proto/pg_query_role_stmt_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_row_compare_expr.ex b/lib/pg_query/proto/pg_query_row_compare_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_row_compare_expr.ex rename to lib/pg_query/proto/pg_query_row_compare_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_row_compare_type.ex b/lib/pg_query/proto/pg_query_row_compare_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_row_compare_type.ex rename to lib/pg_query/proto/pg_query_row_compare_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_row_expr.ex b/lib/pg_query/proto/pg_query_row_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_row_expr.ex rename to lib/pg_query/proto/pg_query_row_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_row_mark_clause.ex b/lib/pg_query/proto/pg_query_row_mark_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_row_mark_clause.ex rename to lib/pg_query/proto/pg_query_row_mark_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_rte_kind.ex b/lib/pg_query/proto/pg_query_rte_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_rte_kind.ex rename to lib/pg_query/proto/pg_query_rte_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_rte_permission_info.ex b/lib/pg_query/proto/pg_query_rte_permission_info.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_rte_permission_info.ex rename to lib/pg_query/proto/pg_query_rte_permission_info.ex diff --git a/lib/pg_query/proto/elixir_pg_query_rule_stmt.ex b/lib/pg_query/proto/pg_query_rule_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_rule_stmt.ex rename to lib/pg_query/proto/pg_query_rule_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_scalar_array_op_expr.ex b/lib/pg_query/proto/pg_query_scalar_array_op_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_scalar_array_op_expr.ex rename to lib/pg_query/proto/pg_query_scalar_array_op_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_scan_result.ex b/lib/pg_query/proto/pg_query_scan_result.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_scan_result.ex rename to lib/pg_query/proto/pg_query_scan_result.ex diff --git a/lib/pg_query/proto/elixir_pg_query_scan_token.ex b/lib/pg_query/proto/pg_query_scan_token.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_scan_token.ex rename to lib/pg_query/proto/pg_query_scan_token.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sec_label_stmt.ex b/lib/pg_query/proto/pg_query_sec_label_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sec_label_stmt.ex rename to lib/pg_query/proto/pg_query_sec_label_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_select_stmt.ex b/lib/pg_query/proto/pg_query_select_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_select_stmt.ex rename to lib/pg_query/proto/pg_query_select_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_set_op_cmd.ex b/lib/pg_query/proto/pg_query_set_op_cmd.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_set_op_cmd.ex rename to lib/pg_query/proto/pg_query_set_op_cmd.ex diff --git a/lib/pg_query/proto/elixir_pg_query_set_op_strategy.ex b/lib/pg_query/proto/pg_query_set_op_strategy.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_set_op_strategy.ex rename to lib/pg_query/proto/pg_query_set_op_strategy.ex diff --git a/lib/pg_query/proto/elixir_pg_query_set_operation.ex b/lib/pg_query/proto/pg_query_set_operation.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_set_operation.ex rename to lib/pg_query/proto/pg_query_set_operation.ex diff --git a/lib/pg_query/proto/elixir_pg_query_set_operation_stmt.ex b/lib/pg_query/proto/pg_query_set_operation_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_set_operation_stmt.ex rename to lib/pg_query/proto/pg_query_set_operation_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_set_quantifier.ex b/lib/pg_query/proto/pg_query_set_quantifier.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_set_quantifier.ex rename to lib/pg_query/proto/pg_query_set_quantifier.ex diff --git a/lib/pg_query/proto/elixir_pg_query_set_to_default.ex b/lib/pg_query/proto/pg_query_set_to_default.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_set_to_default.ex rename to lib/pg_query/proto/pg_query_set_to_default.ex diff --git a/lib/pg_query/proto/elixir_pg_query_single_partition_spec.ex b/lib/pg_query/proto/pg_query_single_partition_spec.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_single_partition_spec.ex rename to lib/pg_query/proto/pg_query_single_partition_spec.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sort_by.ex b/lib/pg_query/proto/pg_query_sort_by.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sort_by.ex rename to lib/pg_query/proto/pg_query_sort_by.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sort_by_dir.ex b/lib/pg_query/proto/pg_query_sort_by_dir.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sort_by_dir.ex rename to lib/pg_query/proto/pg_query_sort_by_dir.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sort_by_nulls.ex b/lib/pg_query/proto/pg_query_sort_by_nulls.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sort_by_nulls.ex rename to lib/pg_query/proto/pg_query_sort_by_nulls.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sort_group_clause.ex b/lib/pg_query/proto/pg_query_sort_group_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sort_group_clause.ex rename to lib/pg_query/proto/pg_query_sort_group_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sql_value_function.ex b/lib/pg_query/proto/pg_query_sql_value_function.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sql_value_function.ex rename to lib/pg_query/proto/pg_query_sql_value_function.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sql_value_function_op.ex b/lib/pg_query/proto/pg_query_sql_value_function_op.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sql_value_function_op.ex rename to lib/pg_query/proto/pg_query_sql_value_function_op.ex diff --git a/lib/pg_query/proto/elixir_pg_query_stats_elem.ex b/lib/pg_query/proto/pg_query_stats_elem.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_stats_elem.ex rename to lib/pg_query/proto/pg_query_stats_elem.ex diff --git a/lib/pg_query/proto/elixir_pg_query_string.ex b/lib/pg_query/proto/pg_query_string.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_string.ex rename to lib/pg_query/proto/pg_query_string.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sub_link.ex b/lib/pg_query/proto/pg_query_sub_link.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sub_link.ex rename to lib/pg_query/proto/pg_query_sub_link.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sub_link_type.ex b/lib/pg_query/proto/pg_query_sub_link_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sub_link_type.ex rename to lib/pg_query/proto/pg_query_sub_link_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_sub_plan.ex b/lib/pg_query/proto/pg_query_sub_plan.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_sub_plan.ex rename to lib/pg_query/proto/pg_query_sub_plan.ex diff --git a/lib/pg_query/proto/elixir_pg_query_subscripting_ref.ex b/lib/pg_query/proto/pg_query_subscripting_ref.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_subscripting_ref.ex rename to lib/pg_query/proto/pg_query_subscripting_ref.ex diff --git a/lib/pg_query/proto/pg_query_summary_result.ex b/lib/pg_query/proto/pg_query_summary_result.ex new file mode 100644 index 00000000..9c06094c --- /dev/null +++ b/lib/pg_query/proto/pg_query_summary_result.ex @@ -0,0 +1,529 @@ +# Code generated by protox. Don't edit. +# credo:disable-for-this-file +defmodule PgQuery.SummaryResult do + @moduledoc false + if function_exported?(Protox, :check_generator_version, 1) do + Protox.check_generator_version(1) + else + raise "This code was generated with protox 2 but the runtime is using an older version of protox." + end + + @type t :: %__MODULE__{ + truncated_query: String.t(), + statement_types: [String.t()], + filter_columns: [PgQuery.SummaryResult.FilterColumn.t()], + functions: [PgQuery.SummaryResult.Function.t()], + cte_names: [String.t()], + aliases: %{String.t() => String.t()}, + tables: [PgQuery.SummaryResult.Table.t()], + __uf__: [{non_neg_integer(), Protox.Types.tag(), binary()}] + } + defstruct truncated_query: "", + statement_types: [], + filter_columns: [], + functions: [], + cte_names: [], + aliases: %{}, + tables: [], + __uf__: [] + + ( + ( + @spec encode(t()) :: {:ok, iodata(), non_neg_integer()} | {:error, any()} + def encode(msg) do + msg |> encode!() |> Tuple.insert_at(0, :ok) + rescue + e in [Protox.EncodingError, Protox.RequiredFieldsError] -> {:error, e} + end + + @spec encode!(t()) :: {iodata(), non_neg_integer()} | no_return() + def encode!(msg) do + {_acc = [], _acc_size = 0} + |> encode_truncated_query(msg) + |> encode_statement_types(msg) + |> encode_filter_columns(msg) + |> encode_functions(msg) + |> encode_cte_names(msg) + |> encode_aliases(msg) + |> encode_tables(msg) + |> encode_unknown_fields(msg) + end + ) + + defp encode_truncated_query({acc, acc_size}, msg) do + if msg.truncated_query == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.truncated_query) + {[":", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:truncated_query, "invalid field value"), __STACKTRACE__ + end + + defp encode_statement_types({acc, acc_size}, msg) do + case msg.statement_types do + [] -> + {acc, acc_size} + + values -> + {value_bytes, value_size} = + ( + {value_bytes, value_size} = + Enum.reduce(values, {_local_acc = [], _local_acc_size = 0}, fn value, + {local_acc, + local_acc_size} -> + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(value) + {[value_bytes, "2" | local_acc], local_acc_size + 1 + value_bytes_size} + end) + + {Enum.reverse(value_bytes), value_size} + ) + + {[value_bytes | acc], acc_size + value_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:statement_types, "invalid field value"), __STACKTRACE__ + end + + defp encode_filter_columns({acc, acc_size}, msg) do + case msg.filter_columns do + [] -> + {acc, acc_size} + + values -> + {value_bytes, value_size} = + ( + {value_bytes, value_size} = + Enum.reduce(values, {_local_acc = [], _local_acc_size = 0}, fn value, + {local_acc, + local_acc_size} -> + {value_bytes, value_bytes_size} = Protox.Encode.encode_message(value) + {[value_bytes, "*" | local_acc], local_acc_size + 1 + value_bytes_size} + end) + + {Enum.reverse(value_bytes), value_size} + ) + + {[value_bytes | acc], acc_size + value_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:filter_columns, "invalid field value"), __STACKTRACE__ + end + + defp encode_functions({acc, acc_size}, msg) do + case msg.functions do + [] -> + {acc, acc_size} + + values -> + {value_bytes, value_size} = + ( + {value_bytes, value_size} = + Enum.reduce(values, {_local_acc = [], _local_acc_size = 0}, fn value, + {local_acc, + local_acc_size} -> + {value_bytes, value_bytes_size} = Protox.Encode.encode_message(value) + {[value_bytes, "\"" | local_acc], local_acc_size + 1 + value_bytes_size} + end) + + {Enum.reverse(value_bytes), value_size} + ) + + {[value_bytes | acc], acc_size + value_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:functions, "invalid field value"), __STACKTRACE__ + end + + defp encode_cte_names({acc, acc_size}, msg) do + case msg.cte_names do + [] -> + {acc, acc_size} + + values -> + {value_bytes, value_size} = + ( + {value_bytes, value_size} = + Enum.reduce(values, {_local_acc = [], _local_acc_size = 0}, fn value, + {local_acc, + local_acc_size} -> + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(value) + {[value_bytes, "\x1A" | local_acc], local_acc_size + 1 + value_bytes_size} + end) + + {Enum.reverse(value_bytes), value_size} + ) + + {[value_bytes | acc], acc_size + value_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:cte_names, "invalid field value"), __STACKTRACE__ + end + + defp encode_aliases({acc, acc_size}, msg) do + map = Map.fetch!(msg, :aliases) + + if map_size(map) == 0 do + {acc, acc_size} + else + Enum.reduce(map, {acc, acc_size}, fn {k, v}, {acc, acc_size} -> + {k_value_bytes, k_value_len} = Protox.Encode.encode_string(k) + {v_value_bytes, v_value_len} = Protox.Encode.encode_string(v) + len = 2 + k_value_len + v_value_len + {len_varint, len_varint_size} = Protox.Varint.encode(len) + acc = [<<"\x12", len_varint::binary, "\n">>, k_value_bytes, "\x12", v_value_bytes | acc] + {acc, acc_size + 3 + k_value_len + v_value_len + len_varint_size} + end) + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:aliases, "invalid field value"), __STACKTRACE__ + end + + defp encode_tables({acc, acc_size}, msg) do + case msg.tables do + [] -> + {acc, acc_size} + + values -> + {value_bytes, value_size} = + ( + {value_bytes, value_size} = + Enum.reduce(values, {_local_acc = [], _local_acc_size = 0}, fn value, + {local_acc, + local_acc_size} -> + {value_bytes, value_bytes_size} = Protox.Encode.encode_message(value) + {[value_bytes, "\n" | local_acc], local_acc_size + 1 + value_bytes_size} + end) + + {Enum.reverse(value_bytes), value_size} + ) + + {[value_bytes | acc], acc_size + value_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:tables, "invalid field value"), __STACKTRACE__ + end + + defp encode_unknown_fields({acc, acc_size}, msg) do + Enum.reduce(msg.__uf__, {acc, acc_size}, fn {tag, wire_type, bytes}, {acc, acc_size} -> + case wire_type do + 0 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :int32) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 1 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :double) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 2 -> + {len_bytes, len_size} = bytes |> byte_size() |> Protox.Varint.encode() + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :packed) + + {[acc, <>], + acc_size + key_size + len_size + byte_size(bytes)} + + 5 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :float) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + end + end) + end + ) + + ( + ( + @spec decode(binary()) :: {:ok, t()} | {:error, any()} + def decode(bytes) do + {:ok, decode!(bytes)} + rescue + e in [Protox.DecodingError, Protox.IllegalTagError, Protox.RequiredFieldsError] -> + {:error, e} + end + + ( + @spec decode!(binary()) :: t() | no_return() + def decode!(bytes) do + parse_key_value(bytes, struct(PgQuery.SummaryResult)) + end + ) + ) + + ( + @spec parse_key_value(binary(), struct()) :: struct() + defp parse_key_value(<<>>, msg) do + msg + end + + defp parse_key_value(bytes, msg) do + {field, rest} = + case bytes do + <<_::5, 3::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 3") + + <<_::5, 4::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 4") + + <<_::5, 6::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 6") + + <<_::5, 7::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 7") + + <<0::5, _::3, _rest::binary>> -> + raise %Protox.IllegalTagError{} + + <<7::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[truncated_query: Protox.Decode.validate_string!(delimited)], rest} + + <<6::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + + {[ + statement_types: + msg.statement_types ++ [Protox.Decode.validate_string!(delimited)] + ], rest} + + <<5::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + + {[ + filter_columns: + msg.filter_columns ++ [PgQuery.SummaryResult.FilterColumn.decode!(delimited)] + ], rest} + + <<4::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + + {[functions: msg.functions ++ [PgQuery.SummaryResult.Function.decode!(delimited)]], + rest} + + <<3::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[cte_names: msg.cte_names ++ [Protox.Decode.validate_string!(delimited)]], rest} + + <<2::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + + {[ + ( + {entry_key, entry_value} = + ( + {map_key, map_value} = parse_string_string({:unset, :unset}, delimited) + + map_key = + case map_key do + :unset -> Protox.Default.default(:string) + _ -> map_key + end + + map_value = + case map_value do + :unset -> Protox.Default.default(:string) + _ -> map_value + end + + {map_key, map_value} + ) + + {:aliases, Map.put(msg.aliases, entry_key, entry_value)} + ) + ], rest} + + <<1::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[tables: msg.tables ++ [PgQuery.SummaryResult.Table.decode!(delimited)]], rest} + + <> -> + {tag, wire_type, rest} = Protox.Decode.parse_key(bytes) + {value, rest} = Protox.Decode.parse_unknown(tag, wire_type, rest) + {[__uf__: msg.__uf__ ++ [value]], rest} + end + + msg_updated = struct(msg, field) + parse_key_value(rest, msg_updated) + end + ) + + ( + defp parse_string_string(map_entry, <<>>) do + map_entry + end + + defp parse_string_string({entry_key, entry_value}, bytes) do + {map_entry, rest} = + case Protox.Decode.parse_key(bytes) do + {1, _, rest} -> + {res, rest} = + ( + {len, new_rest} = Protox.Varint.decode(rest) + {delimited, new_rest} = Protox.Decode.parse_delimited(new_rest, len) + {Protox.Decode.validate_string!(delimited), new_rest} + ) + + {{res, entry_value}, rest} + + {2, _, rest} -> + {res, rest} = + ( + {len, new_rest} = Protox.Varint.decode(rest) + {delimited, new_rest} = Protox.Decode.parse_delimited(new_rest, len) + {Protox.Decode.validate_string!(delimited), new_rest} + ) + + {{entry_key, res}, rest} + + {tag, wire_type, rest} -> + {_, rest} = Protox.Decode.parse_unknown(tag, wire_type, rest) + {{entry_key, entry_value}, rest} + end + + parse_string_string(map_entry, rest) + end + ) + ) + + ( + @spec unknown_fields(struct()) :: [{non_neg_integer(), Protox.Types.tag(), binary()}] + def unknown_fields(msg) do + msg.__uf__ + end + + @spec unknown_fields_name() :: :__uf__ + def unknown_fields_name() do + :__uf__ + end + + @spec clear_unknown_fields(struct) :: struct + def clear_unknown_fields(msg) do + struct!(msg, __uf__: []) + end + ) + + ( + @spec default(atom()) :: + {:ok, boolean() | integer() | String.t() | float()} + | {:error, :no_such_field | :no_default_value} + def default(:truncated_query) do + {:ok, ""} + end + + def default(:statement_types) do + {:error, :no_default_value} + end + + def default(:filter_columns) do + {:error, :no_default_value} + end + + def default(:functions) do + {:error, :no_default_value} + end + + def default(:cte_names) do + {:error, :no_default_value} + end + + def default(:aliases) do + {:error, :no_default_value} + end + + def default(:tables) do + {:error, :no_default_value} + end + + def default(_) do + {:error, :no_such_field} + end + ) + + @spec schema() :: Protox.MessageSchema.t() + def schema() do + %{ + __struct__: Protox.MessageSchema, + fields: %{ + aliases: %{ + __struct__: Protox.Field, + extender: nil, + kind: :map, + label: nil, + name: :aliases, + tag: 2, + type: {:string, :string} + }, + cte_names: %{ + __struct__: Protox.Field, + extender: nil, + kind: :unpacked, + label: :repeated, + name: :cte_names, + tag: 3, + type: :string + }, + filter_columns: %{ + __struct__: Protox.Field, + extender: nil, + kind: :unpacked, + label: :repeated, + name: :filter_columns, + tag: 5, + type: {:message, PgQuery.SummaryResult.FilterColumn} + }, + functions: %{ + __struct__: Protox.Field, + extender: nil, + kind: :unpacked, + label: :repeated, + name: :functions, + tag: 4, + type: {:message, PgQuery.SummaryResult.Function} + }, + statement_types: %{ + __struct__: Protox.Field, + extender: nil, + kind: :unpacked, + label: :repeated, + name: :statement_types, + tag: 6, + type: :string + }, + tables: %{ + __struct__: Protox.Field, + extender: nil, + kind: :unpacked, + label: :repeated, + name: :tables, + tag: 1, + type: {:message, PgQuery.SummaryResult.Table} + }, + truncated_query: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :truncated_query, + tag: 7, + type: :string + } + }, + file_options: nil, + name: PgQuery.SummaryResult, + syntax: :proto3 + } + end +end diff --git a/lib/pg_query/proto/pg_query_summary_result_context.ex b/lib/pg_query/proto/pg_query_summary_result_context.ex new file mode 100644 index 00000000..0737780c --- /dev/null +++ b/lib/pg_query/proto/pg_query_summary_result_context.ex @@ -0,0 +1,96 @@ +# Code generated by protox. Don't edit. +# credo:disable-for-this-file +defmodule PgQuery.SummaryResult.Context do + @moduledoc false + @type t :: %__MODULE__{} + defstruct [] + + ( + @spec default() :: :None + def default() do + :None + end + ) + + @spec encode(atom() | String.t()) :: integer() | atom() + def encode(:None) do + 0 + end + + def encode(:Select) do + 1 + end + + def encode(:DML) do + 2 + end + + def encode(:DDL) do + 3 + end + + def encode(:Call) do + 4 + end + + def encode(x) do + x + end + + @spec decode(integer()) :: atom() | integer() + def decode(0) do + :None + end + + def decode(1) do + :Select + end + + def decode(2) do + :DML + end + + def decode(3) do + :DDL + end + + def decode(4) do + :Call + end + + def decode(x) do + x + end + + @spec constants() :: [{integer(), atom()}] + def constants() do + [{0, :None}, {1, :Select}, {2, :DML}, {3, :DDL}, {4, :Call}] + end + + @spec has_constant?(any()) :: boolean() + ( + def has_constant?(:None) do + true + end + + def has_constant?(:Select) do + true + end + + def has_constant?(:DML) do + true + end + + def has_constant?(:DDL) do + true + end + + def has_constant?(:Call) do + true + end + + def has_constant?(_) do + false + end + ) +end diff --git a/lib/pg_query/proto/pg_query_summary_result_filter_column.ex b/lib/pg_query/proto/pg_query_summary_result_filter_column.ex new file mode 100644 index 00000000..3c6ec030 --- /dev/null +++ b/lib/pg_query/proto/pg_query_summary_result_filter_column.ex @@ -0,0 +1,245 @@ +# Code generated by protox. Don't edit. +# credo:disable-for-this-file +defmodule PgQuery.SummaryResult.FilterColumn do + @moduledoc false + if function_exported?(Protox, :check_generator_version, 1) do + Protox.check_generator_version(1) + else + raise "This code was generated with protox 2 but the runtime is using an older version of protox." + end + + @type t :: %__MODULE__{ + column: String.t(), + table_name: String.t(), + schema_name: String.t(), + __uf__: [{non_neg_integer(), Protox.Types.tag(), binary()}] + } + defstruct column: "", table_name: "", schema_name: "", __uf__: [] + + ( + ( + @spec encode(t()) :: {:ok, iodata(), non_neg_integer()} | {:error, any()} + def encode(msg) do + msg |> encode!() |> Tuple.insert_at(0, :ok) + rescue + e in [Protox.EncodingError, Protox.RequiredFieldsError] -> {:error, e} + end + + @spec encode!(t()) :: {iodata(), non_neg_integer()} | no_return() + def encode!(msg) do + {_acc = [], _acc_size = 0} + |> encode_column(msg) + |> encode_table_name(msg) + |> encode_schema_name(msg) + |> encode_unknown_fields(msg) + end + ) + + defp encode_column({acc, acc_size}, msg) do + if msg.column == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.column) + {["\x1A", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:column, "invalid field value"), __STACKTRACE__ + end + + defp encode_table_name({acc, acc_size}, msg) do + if msg.table_name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.table_name) + {["\x12", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:table_name, "invalid field value"), __STACKTRACE__ + end + + defp encode_schema_name({acc, acc_size}, msg) do + if msg.schema_name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.schema_name) + {["\n", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:schema_name, "invalid field value"), __STACKTRACE__ + end + + defp encode_unknown_fields({acc, acc_size}, msg) do + Enum.reduce(msg.__uf__, {acc, acc_size}, fn {tag, wire_type, bytes}, {acc, acc_size} -> + case wire_type do + 0 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :int32) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 1 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :double) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 2 -> + {len_bytes, len_size} = bytes |> byte_size() |> Protox.Varint.encode() + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :packed) + + {[acc, <>], + acc_size + key_size + len_size + byte_size(bytes)} + + 5 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :float) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + end + end) + end + ) + + ( + ( + @spec decode(binary()) :: {:ok, t()} | {:error, any()} + def decode(bytes) do + {:ok, decode!(bytes)} + rescue + e in [Protox.DecodingError, Protox.IllegalTagError, Protox.RequiredFieldsError] -> + {:error, e} + end + + ( + @spec decode!(binary()) :: t() | no_return() + def decode!(bytes) do + parse_key_value(bytes, struct(PgQuery.SummaryResult.FilterColumn)) + end + ) + ) + + ( + @spec parse_key_value(binary(), struct()) :: struct() + defp parse_key_value(<<>>, msg) do + msg + end + + defp parse_key_value(bytes, msg) do + {field, rest} = + case bytes do + <<_::5, 3::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 3") + + <<_::5, 4::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 4") + + <<_::5, 6::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 6") + + <<_::5, 7::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 7") + + <<0::5, _::3, _rest::binary>> -> + raise %Protox.IllegalTagError{} + + <<3::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[column: Protox.Decode.validate_string!(delimited)], rest} + + <<2::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[table_name: Protox.Decode.validate_string!(delimited)], rest} + + <<1::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[schema_name: Protox.Decode.validate_string!(delimited)], rest} + + <> -> + {tag, wire_type, rest} = Protox.Decode.parse_key(bytes) + {value, rest} = Protox.Decode.parse_unknown(tag, wire_type, rest) + {[__uf__: msg.__uf__ ++ [value]], rest} + end + + msg_updated = struct(msg, field) + parse_key_value(rest, msg_updated) + end + ) + ) + + ( + @spec unknown_fields(struct()) :: [{non_neg_integer(), Protox.Types.tag(), binary()}] + def unknown_fields(msg) do + msg.__uf__ + end + + @spec unknown_fields_name() :: :__uf__ + def unknown_fields_name() do + :__uf__ + end + + @spec clear_unknown_fields(struct) :: struct + def clear_unknown_fields(msg) do + struct!(msg, __uf__: []) + end + ) + + ( + @spec default(atom()) :: + {:ok, boolean() | integer() | String.t() | float()} + | {:error, :no_such_field | :no_default_value} + def default(:column) do + {:ok, ""} + end + + def default(:table_name) do + {:ok, ""} + end + + def default(:schema_name) do + {:ok, ""} + end + + def default(_) do + {:error, :no_such_field} + end + ) + + @spec schema() :: Protox.MessageSchema.t() + def schema() do + %{ + __struct__: Protox.MessageSchema, + fields: %{ + column: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :column, + tag: 3, + type: :string + }, + schema_name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :schema_name, + tag: 1, + type: :string + }, + table_name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :table_name, + tag: 2, + type: :string + } + }, + file_options: nil, + name: PgQuery.SummaryResult.FilterColumn, + syntax: :proto3 + } + end +end diff --git a/lib/pg_query/proto/pg_query_summary_result_function.ex b/lib/pg_query/proto/pg_query_summary_result_function.ex new file mode 100644 index 00000000..e7fd9337 --- /dev/null +++ b/lib/pg_query/proto/pg_query_summary_result_function.ex @@ -0,0 +1,278 @@ +# Code generated by protox. Don't edit. +# credo:disable-for-this-file +defmodule PgQuery.SummaryResult.Function do + @moduledoc false + if function_exported?(Protox, :check_generator_version, 1) do + Protox.check_generator_version(1) + else + raise "This code was generated with protox 2 but the runtime is using an older version of protox." + end + + @type t :: %__MODULE__{ + context: atom(), + schema_name: String.t(), + function_name: String.t(), + name: String.t(), + __uf__: [{non_neg_integer(), Protox.Types.tag(), binary()}] + } + defstruct context: :None, schema_name: "", function_name: "", name: "", __uf__: [] + + ( + ( + @spec encode(t()) :: {:ok, iodata(), non_neg_integer()} | {:error, any()} + def encode(msg) do + msg |> encode!() |> Tuple.insert_at(0, :ok) + rescue + e in [Protox.EncodingError, Protox.RequiredFieldsError] -> {:error, e} + end + + @spec encode!(t()) :: {iodata(), non_neg_integer()} | no_return() + def encode!(msg) do + {_acc = [], _acc_size = 0} + |> encode_context(msg) + |> encode_schema_name(msg) + |> encode_function_name(msg) + |> encode_name(msg) + |> encode_unknown_fields(msg) + end + ) + + defp encode_context({acc, acc_size}, msg) do + if msg.context == :None do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = + msg.context |> PgQuery.SummaryResult.Context.encode() |> Protox.Encode.encode_enum() + + {[" ", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:context, "invalid field value"), __STACKTRACE__ + end + + defp encode_schema_name({acc, acc_size}, msg) do + if msg.schema_name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.schema_name) + {["\x1A", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:schema_name, "invalid field value"), __STACKTRACE__ + end + + defp encode_function_name({acc, acc_size}, msg) do + if msg.function_name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.function_name) + {["\x12", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:function_name, "invalid field value"), __STACKTRACE__ + end + + defp encode_name({acc, acc_size}, msg) do + if msg.name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.name) + {["\n", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:name, "invalid field value"), __STACKTRACE__ + end + + defp encode_unknown_fields({acc, acc_size}, msg) do + Enum.reduce(msg.__uf__, {acc, acc_size}, fn {tag, wire_type, bytes}, {acc, acc_size} -> + case wire_type do + 0 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :int32) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 1 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :double) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 2 -> + {len_bytes, len_size} = bytes |> byte_size() |> Protox.Varint.encode() + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :packed) + + {[acc, <>], + acc_size + key_size + len_size + byte_size(bytes)} + + 5 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :float) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + end + end) + end + ) + + ( + ( + @spec decode(binary()) :: {:ok, t()} | {:error, any()} + def decode(bytes) do + {:ok, decode!(bytes)} + rescue + e in [Protox.DecodingError, Protox.IllegalTagError, Protox.RequiredFieldsError] -> + {:error, e} + end + + ( + @spec decode!(binary()) :: t() | no_return() + def decode!(bytes) do + parse_key_value(bytes, struct(PgQuery.SummaryResult.Function)) + end + ) + ) + + ( + @spec parse_key_value(binary(), struct()) :: struct() + defp parse_key_value(<<>>, msg) do + msg + end + + defp parse_key_value(bytes, msg) do + {field, rest} = + case bytes do + <<_::5, 3::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 3") + + <<_::5, 4::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 4") + + <<_::5, 6::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 6") + + <<_::5, 7::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 7") + + <<0::5, _::3, _rest::binary>> -> + raise %Protox.IllegalTagError{} + + <<4::5, _wire_type::3, bytes::binary>> -> + {value, rest} = Protox.Decode.parse_enum(bytes, PgQuery.SummaryResult.Context) + {[context: value], rest} + + <<3::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[schema_name: Protox.Decode.validate_string!(delimited)], rest} + + <<2::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[function_name: Protox.Decode.validate_string!(delimited)], rest} + + <<1::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[name: Protox.Decode.validate_string!(delimited)], rest} + + <> -> + {tag, wire_type, rest} = Protox.Decode.parse_key(bytes) + {value, rest} = Protox.Decode.parse_unknown(tag, wire_type, rest) + {[__uf__: msg.__uf__ ++ [value]], rest} + end + + msg_updated = struct(msg, field) + parse_key_value(rest, msg_updated) + end + ) + ) + + ( + @spec unknown_fields(struct()) :: [{non_neg_integer(), Protox.Types.tag(), binary()}] + def unknown_fields(msg) do + msg.__uf__ + end + + @spec unknown_fields_name() :: :__uf__ + def unknown_fields_name() do + :__uf__ + end + + @spec clear_unknown_fields(struct) :: struct + def clear_unknown_fields(msg) do + struct!(msg, __uf__: []) + end + ) + + ( + @spec default(atom()) :: + {:ok, boolean() | integer() | String.t() | float()} + | {:error, :no_such_field | :no_default_value} + def default(:context) do + {:ok, :None} + end + + def default(:schema_name) do + {:ok, ""} + end + + def default(:function_name) do + {:ok, ""} + end + + def default(:name) do + {:ok, ""} + end + + def default(_) do + {:error, :no_such_field} + end + ) + + @spec schema() :: Protox.MessageSchema.t() + def schema() do + %{ + __struct__: Protox.MessageSchema, + fields: %{ + context: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: :None}, + label: :optional, + name: :context, + tag: 4, + type: {:enum, PgQuery.SummaryResult.Context} + }, + function_name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :function_name, + tag: 2, + type: :string + }, + name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :name, + tag: 1, + type: :string + }, + schema_name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :schema_name, + tag: 3, + type: :string + } + }, + file_options: nil, + name: PgQuery.SummaryResult.Function, + syntax: :proto3 + } + end +end diff --git a/lib/pg_query/proto/pg_query_summary_result_table.ex b/lib/pg_query/proto/pg_query_summary_result_table.ex new file mode 100644 index 00000000..e0804861 --- /dev/null +++ b/lib/pg_query/proto/pg_query_summary_result_table.ex @@ -0,0 +1,278 @@ +# Code generated by protox. Don't edit. +# credo:disable-for-this-file +defmodule PgQuery.SummaryResult.Table do + @moduledoc false + if function_exported?(Protox, :check_generator_version, 1) do + Protox.check_generator_version(1) + else + raise "This code was generated with protox 2 but the runtime is using an older version of protox." + end + + @type t :: %__MODULE__{ + context: atom(), + table_name: String.t(), + schema_name: String.t(), + name: String.t(), + __uf__: [{non_neg_integer(), Protox.Types.tag(), binary()}] + } + defstruct context: :None, table_name: "", schema_name: "", name: "", __uf__: [] + + ( + ( + @spec encode(t()) :: {:ok, iodata(), non_neg_integer()} | {:error, any()} + def encode(msg) do + msg |> encode!() |> Tuple.insert_at(0, :ok) + rescue + e in [Protox.EncodingError, Protox.RequiredFieldsError] -> {:error, e} + end + + @spec encode!(t()) :: {iodata(), non_neg_integer()} | no_return() + def encode!(msg) do + {_acc = [], _acc_size = 0} + |> encode_context(msg) + |> encode_table_name(msg) + |> encode_schema_name(msg) + |> encode_name(msg) + |> encode_unknown_fields(msg) + end + ) + + defp encode_context({acc, acc_size}, msg) do + if msg.context == :None do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = + msg.context |> PgQuery.SummaryResult.Context.encode() |> Protox.Encode.encode_enum() + + {[" ", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:context, "invalid field value"), __STACKTRACE__ + end + + defp encode_table_name({acc, acc_size}, msg) do + if msg.table_name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.table_name) + {["\x1A", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:table_name, "invalid field value"), __STACKTRACE__ + end + + defp encode_schema_name({acc, acc_size}, msg) do + if msg.schema_name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.schema_name) + {["\x12", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:schema_name, "invalid field value"), __STACKTRACE__ + end + + defp encode_name({acc, acc_size}, msg) do + if msg.name == "" do + {acc, acc_size} + else + {value_bytes, value_bytes_size} = Protox.Encode.encode_string(msg.name) + {["\n", value_bytes | acc], acc_size + 1 + value_bytes_size} + end + rescue + ArgumentError -> + reraise Protox.EncodingError.new(:name, "invalid field value"), __STACKTRACE__ + end + + defp encode_unknown_fields({acc, acc_size}, msg) do + Enum.reduce(msg.__uf__, {acc, acc_size}, fn {tag, wire_type, bytes}, {acc, acc_size} -> + case wire_type do + 0 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :int32) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 1 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :double) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + + 2 -> + {len_bytes, len_size} = bytes |> byte_size() |> Protox.Varint.encode() + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :packed) + + {[acc, <>], + acc_size + key_size + len_size + byte_size(bytes)} + + 5 -> + {key_bytes, key_size} = Protox.Encode.make_key_bytes(tag, :float) + {[acc, <>], acc_size + key_size + byte_size(bytes)} + end + end) + end + ) + + ( + ( + @spec decode(binary()) :: {:ok, t()} | {:error, any()} + def decode(bytes) do + {:ok, decode!(bytes)} + rescue + e in [Protox.DecodingError, Protox.IllegalTagError, Protox.RequiredFieldsError] -> + {:error, e} + end + + ( + @spec decode!(binary()) :: t() | no_return() + def decode!(bytes) do + parse_key_value(bytes, struct(PgQuery.SummaryResult.Table)) + end + ) + ) + + ( + @spec parse_key_value(binary(), struct()) :: struct() + defp parse_key_value(<<>>, msg) do + msg + end + + defp parse_key_value(bytes, msg) do + {field, rest} = + case bytes do + <<_::5, 3::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 3") + + <<_::5, 4::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 4") + + <<_::5, 6::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 6") + + <<_::5, 7::3, _rest::binary>> -> + raise Protox.DecodingError.new(bytes, "invalid wire type 7") + + <<0::5, _::3, _rest::binary>> -> + raise %Protox.IllegalTagError{} + + <<4::5, _wire_type::3, bytes::binary>> -> + {value, rest} = Protox.Decode.parse_enum(bytes, PgQuery.SummaryResult.Context) + {[context: value], rest} + + <<3::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[table_name: Protox.Decode.validate_string!(delimited)], rest} + + <<2::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[schema_name: Protox.Decode.validate_string!(delimited)], rest} + + <<1::5, _wire_type::3, bytes::binary>> -> + {len, bytes} = Protox.Varint.decode(bytes) + {delimited, rest} = Protox.Decode.parse_delimited(bytes, len) + {[name: Protox.Decode.validate_string!(delimited)], rest} + + <> -> + {tag, wire_type, rest} = Protox.Decode.parse_key(bytes) + {value, rest} = Protox.Decode.parse_unknown(tag, wire_type, rest) + {[__uf__: msg.__uf__ ++ [value]], rest} + end + + msg_updated = struct(msg, field) + parse_key_value(rest, msg_updated) + end + ) + ) + + ( + @spec unknown_fields(struct()) :: [{non_neg_integer(), Protox.Types.tag(), binary()}] + def unknown_fields(msg) do + msg.__uf__ + end + + @spec unknown_fields_name() :: :__uf__ + def unknown_fields_name() do + :__uf__ + end + + @spec clear_unknown_fields(struct) :: struct + def clear_unknown_fields(msg) do + struct!(msg, __uf__: []) + end + ) + + ( + @spec default(atom()) :: + {:ok, boolean() | integer() | String.t() | float()} + | {:error, :no_such_field | :no_default_value} + def default(:context) do + {:ok, :None} + end + + def default(:table_name) do + {:ok, ""} + end + + def default(:schema_name) do + {:ok, ""} + end + + def default(:name) do + {:ok, ""} + end + + def default(_) do + {:error, :no_such_field} + end + ) + + @spec schema() :: Protox.MessageSchema.t() + def schema() do + %{ + __struct__: Protox.MessageSchema, + fields: %{ + context: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: :None}, + label: :optional, + name: :context, + tag: 4, + type: {:enum, PgQuery.SummaryResult.Context} + }, + name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :name, + tag: 1, + type: :string + }, + schema_name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :schema_name, + tag: 2, + type: :string + }, + table_name: %{ + __struct__: Protox.Field, + extender: nil, + kind: %{__struct__: Protox.Scalar, default_value: ""}, + label: :optional, + name: :table_name, + tag: 3, + type: :string + } + }, + file_options: nil, + name: PgQuery.SummaryResult.Table, + syntax: :proto3 + } + end +end diff --git a/lib/pg_query/proto/elixir_pg_query_table_func.ex b/lib/pg_query/proto/pg_query_table_func.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_table_func.ex rename to lib/pg_query/proto/pg_query_table_func.ex diff --git a/lib/pg_query/proto/elixir_pg_query_table_func_type.ex b/lib/pg_query/proto/pg_query_table_func_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_table_func_type.ex rename to lib/pg_query/proto/pg_query_table_func_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_table_like_clause.ex b/lib/pg_query/proto/pg_query_table_like_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_table_like_clause.ex rename to lib/pg_query/proto/pg_query_table_like_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_table_like_option.ex b/lib/pg_query/proto/pg_query_table_like_option.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_table_like_option.ex rename to lib/pg_query/proto/pg_query_table_like_option.ex diff --git a/lib/pg_query/proto/elixir_pg_query_table_sample_clause.ex b/lib/pg_query/proto/pg_query_table_sample_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_table_sample_clause.ex rename to lib/pg_query/proto/pg_query_table_sample_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_target_entry.ex b/lib/pg_query/proto/pg_query_target_entry.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_target_entry.ex rename to lib/pg_query/proto/pg_query_target_entry.ex diff --git a/lib/pg_query/proto/elixir_pg_query_token.ex b/lib/pg_query/proto/pg_query_token.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_token.ex rename to lib/pg_query/proto/pg_query_token.ex diff --git a/lib/pg_query/proto/elixir_pg_query_transaction_stmt.ex b/lib/pg_query/proto/pg_query_transaction_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_transaction_stmt.ex rename to lib/pg_query/proto/pg_query_transaction_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_transaction_stmt_kind.ex b/lib/pg_query/proto/pg_query_transaction_stmt_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_transaction_stmt_kind.ex rename to lib/pg_query/proto/pg_query_transaction_stmt_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_trigger_transition.ex b/lib/pg_query/proto/pg_query_trigger_transition.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_trigger_transition.ex rename to lib/pg_query/proto/pg_query_trigger_transition.ex diff --git a/lib/pg_query/proto/elixir_pg_query_truncate_stmt.ex b/lib/pg_query/proto/pg_query_truncate_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_truncate_stmt.ex rename to lib/pg_query/proto/pg_query_truncate_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_type_cast.ex b/lib/pg_query/proto/pg_query_type_cast.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_type_cast.ex rename to lib/pg_query/proto/pg_query_type_cast.ex diff --git a/lib/pg_query/proto/elixir_pg_query_type_name.ex b/lib/pg_query/proto/pg_query_type_name.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_type_name.ex rename to lib/pg_query/proto/pg_query_type_name.ex diff --git a/lib/pg_query/proto/elixir_pg_query_unlisten_stmt.ex b/lib/pg_query/proto/pg_query_unlisten_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_unlisten_stmt.ex rename to lib/pg_query/proto/pg_query_unlisten_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_update_stmt.ex b/lib/pg_query/proto/pg_query_update_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_update_stmt.ex rename to lib/pg_query/proto/pg_query_update_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_vacuum_relation.ex b/lib/pg_query/proto/pg_query_vacuum_relation.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_vacuum_relation.ex rename to lib/pg_query/proto/pg_query_vacuum_relation.ex diff --git a/lib/pg_query/proto/elixir_pg_query_vacuum_stmt.ex b/lib/pg_query/proto/pg_query_vacuum_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_vacuum_stmt.ex rename to lib/pg_query/proto/pg_query_vacuum_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_var.ex b/lib/pg_query/proto/pg_query_var.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_var.ex rename to lib/pg_query/proto/pg_query_var.ex diff --git a/lib/pg_query/proto/elixir_pg_query_variable_set_kind.ex b/lib/pg_query/proto/pg_query_variable_set_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_variable_set_kind.ex rename to lib/pg_query/proto/pg_query_variable_set_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_variable_set_stmt.ex b/lib/pg_query/proto/pg_query_variable_set_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_variable_set_stmt.ex rename to lib/pg_query/proto/pg_query_variable_set_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_variable_show_stmt.ex b/lib/pg_query/proto/pg_query_variable_show_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_variable_show_stmt.ex rename to lib/pg_query/proto/pg_query_variable_show_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_view_check_option.ex b/lib/pg_query/proto/pg_query_view_check_option.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_view_check_option.ex rename to lib/pg_query/proto/pg_query_view_check_option.ex diff --git a/lib/pg_query/proto/elixir_pg_query_view_stmt.ex b/lib/pg_query/proto/pg_query_view_stmt.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_view_stmt.ex rename to lib/pg_query/proto/pg_query_view_stmt.ex diff --git a/lib/pg_query/proto/elixir_pg_query_wco_kind.ex b/lib/pg_query/proto/pg_query_wco_kind.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_wco_kind.ex rename to lib/pg_query/proto/pg_query_wco_kind.ex diff --git a/lib/pg_query/proto/elixir_pg_query_window_clause.ex b/lib/pg_query/proto/pg_query_window_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_window_clause.ex rename to lib/pg_query/proto/pg_query_window_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_window_def.ex b/lib/pg_query/proto/pg_query_window_def.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_window_def.ex rename to lib/pg_query/proto/pg_query_window_def.ex diff --git a/lib/pg_query/proto/elixir_pg_query_window_func.ex b/lib/pg_query/proto/pg_query_window_func.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_window_func.ex rename to lib/pg_query/proto/pg_query_window_func.ex diff --git a/lib/pg_query/proto/elixir_pg_query_window_func_run_condition.ex b/lib/pg_query/proto/pg_query_window_func_run_condition.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_window_func_run_condition.ex rename to lib/pg_query/proto/pg_query_window_func_run_condition.ex diff --git a/lib/pg_query/proto/elixir_pg_query_with_check_option.ex b/lib/pg_query/proto/pg_query_with_check_option.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_with_check_option.ex rename to lib/pg_query/proto/pg_query_with_check_option.ex diff --git a/lib/pg_query/proto/elixir_pg_query_with_clause.ex b/lib/pg_query/proto/pg_query_with_clause.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_with_clause.ex rename to lib/pg_query/proto/pg_query_with_clause.ex diff --git a/lib/pg_query/proto/elixir_pg_query_xml_expr.ex b/lib/pg_query/proto/pg_query_xml_expr.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_xml_expr.ex rename to lib/pg_query/proto/pg_query_xml_expr.ex diff --git a/lib/pg_query/proto/elixir_pg_query_xml_expr_op.ex b/lib/pg_query/proto/pg_query_xml_expr_op.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_xml_expr_op.ex rename to lib/pg_query/proto/pg_query_xml_expr_op.ex diff --git a/lib/pg_query/proto/elixir_pg_query_xml_option_type.ex b/lib/pg_query/proto/pg_query_xml_option_type.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_xml_option_type.ex rename to lib/pg_query/proto/pg_query_xml_option_type.ex diff --git a/lib/pg_query/proto/elixir_pg_query_xml_serialize.ex b/lib/pg_query/proto/pg_query_xml_serialize.ex similarity index 100% rename from lib/pg_query/proto/elixir_pg_query_xml_serialize.ex rename to lib/pg_query/proto/pg_query_xml_serialize.ex diff --git a/patches/0001-fix-null-deref-in-protobuf-deparse.patch b/patches/0001-fix-null-deref-in-protobuf-deparse.patch new file mode 100644 index 00000000..03e1e876 --- /dev/null +++ b/patches/0001-fix-null-deref-in-protobuf-deparse.patch @@ -0,0 +1,28 @@ +diff --git a/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c b/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c +index d0a7e21..c3c30fa 100644 +--- a/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c ++++ b/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c +@@ -160,11 +160,19 @@ List * pg_query_protobuf_to_nodes(PgQueryProtobuf protobuf) + + result = pg_query__parse_result__unpack(NULL, protobuf.len, (const uint8_t *) protobuf.data); + +- // TODO: Handle this by returning an error instead +- Assert(result != NULL); ++ if (result == NULL) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("failed to unpack protobuf parse result: invalid or truncated input"))); + +- // TODO: Handle this by returning an error instead +- Assert(result->version == PG_VERSION_NUM); ++ if (result->version != PG_VERSION_NUM) ++ { ++ pg_query__parse_result__free_unpacked(result, NULL); ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("protobuf parse result version mismatch: expected %d, got %d", ++ PG_VERSION_NUM, result->version))); ++ } + + if (result->n_stmts > 0) + list = list_make1(_readRawStmt(result->stmts[0])); diff --git a/patches/0002-guard-nil-nodes-in-readfuncs-and-deparse.patch b/patches/0002-guard-nil-nodes-in-readfuncs-and-deparse.patch new file mode 100644 index 00000000..fc3df61c --- /dev/null +++ b/patches/0002-guard-nil-nodes-in-readfuncs-and-deparse.patch @@ -0,0 +1,92 @@ +diff --git a/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c b/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c +index c3c30fa..3e6f7cf 100644 +--- a/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c ++++ b/c_src/libpg_query/src/pg_query_readfuncs_protobuf.c +@@ -96,8 +96,28 @@ static List * _readList(PgQuery__List *msg) + + static Node * _readNode(PgQuery__Node *msg) + { ++ if (msg == NULL) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("unexpected NULL node in protobuf input"))); ++ + switch (msg->node_case) + { ++ /* ++ * Redefine READ_COND to guard against NULL inner struct pointers. ++ * When Elixir passes a tagged oneof value like {:column_ref, nil}, ++ * Protox may encode an empty sub-message, causing protobuf-c to set ++ * the inner pointer to a zeroed struct or NULL. Either way we must ++ * error cleanly rather than segfault inside the per-type reader. ++ */ ++#undef READ_COND ++#define READ_COND(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, outname) \ ++ case PG_QUERY__NODE__NODE_##typename_underscore_upcase: \ ++ if (msg->outname == NULL) \ ++ ereport(ERROR, \ ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ ++ errmsg("unexpected NULL inner struct in protobuf node"))); \ ++ return (Node *) _read##typename_c(msg->outname); + #include "pg_query_readfuncs_conds.c" + + case PG_QUERY__NODE__NODE_INTEGER: +@@ -145,7 +165,10 @@ static Node * _readNode(PgQuery__Node *msg) + case PG_QUERY__NODE__NODE_LIST: + return (Node *) _readList(msg->list); + case PG_QUERY__NODE__NODE__NOT_SET: +- return NULL; ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("unexpected unset node type in protobuf input"))); ++ return NULL; /* unreachable */ + default: + elog(ERROR, "unsupported protobuf node type: %d", + (int) msg->node_case); +diff --git a/c_src/libpg_query/src/postgres_deparse.c b/c_src/libpg_query/src/postgres_deparse.c +index 9d8e1ea..79f8c47 100644 +--- a/c_src/libpg_query/src/postgres_deparse.c ++++ b/c_src/libpg_query/src/postgres_deparse.c +@@ -2730,6 +2730,11 @@ static void deparseUtilityOptionList(DeparseState *state, List *options) + + static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context) + { ++ if (stmt == NULL) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("unexpected NULL SelectStmt in protobuf input"))); ++ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + bool need_parens = context == DEPARSE_NODE_CONTEXT_SELECT_SETOP && ( +@@ -4272,9 +4277,16 @@ static void deparseRowExpr(DeparseState *state, RowExpr *row_expr) + + static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context) + { +- bool need_parens = needsParensAsBExpr(type_cast->arg); ++ if (type_cast->arg == NULL) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("unexpected NULL arg in TypeCast"))); ++ if (type_cast->typeName == NULL) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("unexpected NULL typeName in TypeCast"))); + +- Assert(type_cast->typeName != NULL); ++ bool need_parens = needsParensAsBExpr(type_cast->arg); + + if (context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) + { +@@ -4356,6 +4368,11 @@ static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNod + + static void deparseTypeName(DeparseState *state, TypeName *type_name) + { ++ if (type_name == NULL) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ++ errmsg("unexpected NULL TypeName in protobuf input"))); ++ + ListCell *lc; + bool skip_typmods = false; + diff --git a/test/pg_query_test.exs b/test/pg_query_test.exs index 3a224e92..bb99fa20 100644 --- a/test/pg_query_test.exs +++ b/test/pg_query_test.exs @@ -5,7 +5,7 @@ defmodule PgQueryTest do assert {:ok, ast} = PgQuery.parse("create table a (id int8 primary key)") assert %PgQuery.ParseResult{ - version: 170_004, + version: 170_007, stmts: [ %PgQuery.RawStmt{ stmt: %PgQuery.Node{ @@ -47,6 +47,17 @@ defmodule PgQueryTest do assert query == query2 end + test "raises on oversized query" do + # The NIF rejects queries >= 65536 bytes (MAX_QUERY_SIZE) via enif_make_badarg, + # which raises ArgumentError rather than crashing the VM. + small_query = "SELECT '" <> String.duplicate("a", 16 * 1024) <> "'" + assert {:ok, _} = PgQuery.parse(small_query) + + oversized = "SELECT '" <> String.duplicate("a", 65_536) <> "'" + assert {:error, %{message: m}} = PgQuery.parse(oversized) + assert m == "cannot parse query: query size 65545 is bigger than maximum size 65536" + end + test "scans a query" do query = "SELECT * FROM users WHERE id = 1" assert {:ok, scan_result} = PgQuery.scan(query) @@ -65,4 +76,14 @@ defmodule PgQueryTest do token.token == :FROM end) end + + test "errors when scanning an overlarge query" do + oversized = "SELECT '" <> String.duplicate("a", 65_536) <> "'" + assert {:error, %{message: m}} = PgQuery.scan(oversized) + assert m == "cannot parse query: query size 65545 is bigger than maximum size 65536" + end + + test "max_query_size/0" do + assert 65536 = PgQuery.max_query_size() + end end