diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config/pool_config.l | 4 | ||||
| -rw-r--r-- | src/config/pool_config_variables.c | 134 | ||||
| -rw-r--r-- | src/context/pool_query_context.c | 2 | ||||
| -rw-r--r-- | src/include/main/health_check.h | 4 | ||||
| -rw-r--r-- | src/include/parser/gramparse.h | 4 | ||||
| -rw-r--r-- | src/include/parser/keywords.h | 4 | ||||
| -rw-r--r-- | src/include/parser/kwlist.h | 9 | ||||
| -rw-r--r-- | src/include/parser/kwlist_d.h | 894 | ||||
| -rw-r--r-- | src/include/parser/makefuncs.h | 5 | ||||
| -rw-r--r-- | src/include/parser/miscnodes.h | 53 | ||||
| -rw-r--r-- | src/include/parser/nodes.h | 24 | ||||
| -rw-r--r-- | src/include/parser/nodetags.h | 801 | ||||
| -rw-r--r-- | src/include/parser/parsenodes.h | 177 | ||||
| -rw-r--r-- | src/include/parser/parser.h | 4 | ||||
| -rw-r--r-- | src/include/parser/pg_class.h | 9 | ||||
| -rw-r--r-- | src/include/parser/pg_config_manual.h | 72 | ||||
| -rw-r--r-- | src/include/parser/pg_list.h | 74 | ||||
| -rw-r--r-- | src/include/parser/pg_trigger.h | 6 | ||||
| -rw-r--r-- | src/include/parser/pg_wchar.h | 13 | ||||
| -rw-r--r-- | src/include/parser/pool_parser.h | 23 | ||||
| -rw-r--r-- | src/include/parser/primnodes.h | 120 | ||||
| -rw-r--r-- | src/include/parser/scanner.h | 6 | ||||
| -rw-r--r-- | src/include/parser/scansup.h | 4 | ||||
| -rw-r--r-- | src/include/parser/stringinfo.h | 33 | ||||
| -rw-r--r-- | src/include/parser/unicode_east_asian_fw_table.h | 126 | ||||
| -rw-r--r-- | src/include/parser/unicode_nonspacing_table.h | 338 | ||||
| -rw-r--r-- | src/include/parser/value.h | 4 | ||||
| -rw-r--r-- | src/include/pool.h | 6 | ||||
| -rw-r--r-- | src/include/pool_config.h | 16 | ||||
| -rw-r--r-- | src/include/pool_type.h | 42 | ||||
| -rw-r--r-- | src/include/utils/json.h | 2 | ||||
| -rw-r--r-- | src/include/utils/pool_relcache.h | 10 | ||||
| -rw-r--r-- | src/include/utils/pool_select_walker.h | 7 | ||||
| -rw-r--r-- | src/include/version.h | 2 | ||||
| -rw-r--r-- | src/include/watchdog/wd_commands.h | 2 | ||||
| -rw-r--r-- | src/include/watchdog/wd_json_data.h | 4 | ||||
| -rw-r--r-- | src/include/watchdog/wd_utils.h | 3 | ||||
| -rw-r--r-- | src/libs/pcp/Makefile.am | 2 | ||||
| -rw-r--r-- | src/libs/pcp/pcp.c | 4 | ||||
| -rw-r--r-- | src/main/health_check.c | 38 | ||||
| -rw-r--r-- | src/main/pgpool_logger.c | 4 | ||||
| -rw-r--r-- | src/main/pgpool_main.c | 40 | ||||
| -rw-r--r-- | src/parser/copyfuncs.c | 180 | ||||
| -rw-r--r-- | src/parser/gram.y | 725 | ||||
| -rw-r--r-- | src/parser/gram_minimal.y | 737 | ||||
| -rw-r--r-- | src/parser/gram_template.y | 739 | ||||
| -rw-r--r-- | src/parser/keywords.c | 4 | ||||
| -rw-r--r-- | src/parser/kwlookup.c | 4 | ||||
| -rw-r--r-- | src/parser/list.c | 4 | ||||
| -rw-r--r-- | src/parser/makefuncs.c | 93 | ||||
| -rw-r--r-- | src/parser/outfuncs.c | 144 | ||||
| -rw-r--r-- | src/parser/parser.c | 4 | ||||
| -rw-r--r-- | src/parser/scan.l | 72 | ||||
| -rw-r--r-- | src/parser/scansup.c | 4 | ||||
| -rw-r--r-- | src/parser/snprintf.c | 108 | ||||
| -rw-r--r-- | src/parser/stringinfo.c | 79 | ||||
| -rw-r--r-- | src/parser/value.c | 4 | ||||
| -rw-r--r-- | src/parser/wchar.c | 554 | ||||
| -rw-r--r-- | src/pcp_con/pcp_worker.c | 4 | ||||
| -rw-r--r-- | src/pcp_con/recovery.c | 2 | ||||
| -rw-r--r-- | src/pgpool.spec | 15 | ||||
| -rw-r--r-- | src/protocol/CommandComplete.c | 4 | ||||
| -rw-r--r-- | src/protocol/child.c | 52 | ||||
| -rw-r--r-- | src/protocol/pool_connection_pool.c | 12 | ||||
| -rw-r--r-- | src/protocol/pool_process_query.c | 20 | ||||
| -rw-r--r-- | src/protocol/pool_proto_modules.c | 33 | ||||
| -rw-r--r-- | src/query_cache/pool_memqcache.c | 14 | ||||
| -rw-r--r-- | src/redhat/pcp_unix_domain_path.patch | 12 | ||||
| -rw-r--r-- | src/redhat/pgpool.conf.sample.patch | 46 | ||||
| -rw-r--r-- | src/redhat/pgpool_log.patch | 24 | ||||
| -rw-r--r-- | src/redhat/pgpool_socket_dir.patch | 8 | ||||
| -rw-r--r-- | src/rewrite/pool_timestamp.c | 230 | ||||
| -rw-r--r-- | src/sample/pgpool.conf.sample-stream | 10 | ||||
| -rwxr-xr-x | src/sample/scripts/recovery_1st_stage.sample | 2 | ||||
| -rw-r--r-- | src/sql/pgpool_adm/Makefile | 2 | ||||
| -rw-r--r-- | src/streaming_replication/pool_worker_child.c | 2 | ||||
| -rw-r--r-- | src/test/pgpool_setup.in | 38 | ||||
| -rwxr-xr-x | src/test/regression/regress.sh | 4 | ||||
| -rw-r--r-- | src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c | 4 | ||||
| -rwxr-xr-x | src/test/regression/tests/010.rewrite_timestamp/timestamp/run-test | 6 | ||||
| -rwxr-xr-x | src/test/regression/tests/011.watchdog_quorum_failover/test.sh | 4 | ||||
| -rwxr-xr-x | src/test/regression/tests/012.watchdog_failover_when_quorum_exists/test.sh | 4 | ||||
| -rwxr-xr-x | src/test/regression/tests/013.watchdog_failover_require_consensus/test.sh | 4 | ||||
| -rwxr-xr-x | src/test/regression/tests/015.watchdog_master_and_backend_fail/test.sh | 4 | ||||
| -rwxr-xr-x | src/test/regression/tests/023.ssl_connection/test.sh | 63 | ||||
| -rwxr-xr-x | src/test/regression/tests/034.promote_node/test.sh | 2 | ||||
| -rwxr-xr-x | src/test/regression/tests/037.failover_session/test.sh | 2 | ||||
| -rwxr-xr-x | src/test/regression/tests/039.log_backend_messages/test.sh | 10 | ||||
| -rwxr-xr-x | src/test/regression/tests/040.client_auth/test.sh | 4 | ||||
| -rw-r--r-- | src/test/regression/tests/100.bug58/.gitignore (renamed from src/test/regression/tests/050.bug58/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/100.bug58/test.sh (renamed from src/test/regression/tests/050.bug58/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/101.bug60/.gitignore (renamed from src/test/regression/tests/051.bug60/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/101.bug60/bug.sql (renamed from src/test/regression/tests/051.bug60/bug.sql) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/101.bug60/database-clean.sql (renamed from src/test/regression/tests/051.bug60/database-clean.sql) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/101.bug60/database-setup.sql (renamed from src/test/regression/tests/051.bug60/database-setup.sql) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/101.bug60/test.sh (renamed from src/test/regression/tests/051.bug60/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/102.do_query/.gitignore (renamed from src/test/regression/tests/052.do_query/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/102.do_query/test.sh (renamed from src/test/regression/tests/052.do_query/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/103.insert_lock_hangs/.gitignore (renamed from src/test/regression/tests/053.insert_lock_hangs/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/103.insert_lock_hangs/test.sh (renamed from src/test/regression/tests/053.insert_lock_hangs/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/104.postgres_fdw/.gitignore (renamed from src/test/regression/tests/054.postgres_fdw/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/104.postgres_fdw/test.sh (renamed from src/test/regression/tests/054.postgres_fdw/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/105.backend_all_down/.gitignore (renamed from src/test/regression/tests/055.backend_all_down/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/105.backend_all_down/test.sh (renamed from src/test/regression/tests/055.backend_all_down/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/106.bug63/.gitignore (renamed from src/test/regression/tests/056.bug63/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/106.bug63/jdbctest2.java (renamed from src/test/regression/tests/056.bug63/jdbctest2.java) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/106.bug63/test.sh (renamed from src/test/regression/tests/056.bug63/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/107.bug61/.gitignore (renamed from src/test/regression/tests/057.bug61/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/107.bug61/test.sh (renamed from src/test/regression/tests/057.bug61/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/108.bug68/.gitignore (renamed from src/test/regression/tests/058.bug68/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/108.bug68/jdbctest3.java (renamed from src/test/regression/tests/058.bug68/jdbctest3.java) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/108.bug68/test.sh (renamed from src/test/regression/tests/058.bug68/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/109.bug92/.gitignore (renamed from src/test/regression/tests/059.bug92/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/109.bug92/jdbctest.java (renamed from src/test/regression/tests/059.bug92/jdbctest.java) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/109.bug92/test.sh (renamed from src/test/regression/tests/059.bug92/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/110.memory_leak/.gitignore (renamed from src/test/regression/tests/060.memory_leak/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/110.memory_leak/test.sh (renamed from src/test/regression/tests/060.memory_leak/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/111.cancel_query/.gitignore (renamed from src/test/regression/tests/061.cancel_query/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/111.cancel_query/test.sh (renamed from src/test/regression/tests/061.cancel_query/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/112.select_error_hangs/.gitignore (renamed from src/test/regression/tests/062.select_error_hangs/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/112.select_error_hangs/test.sh (renamed from src/test/regression/tests/062.select_error_hangs/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/113.tables_with_space/.gitignore (renamed from src/test/regression/tests/063.tables_with_space/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/113.tables_with_space/test.sh (renamed from src/test/regression/tests/063.tables_with_space/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/114.bug153/.gitignore (renamed from src/test/regression/tests/064.bug153/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/114.bug153/test.sh (renamed from src/test/regression/tests/064.bug153/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/115.bug152/.gitignore (renamed from src/test/regression/tests/065.bug152/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/115.bug152/Main.java (renamed from src/test/regression/tests/065.bug152/Main.java) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/115.bug152/run.sh (renamed from src/test/regression/tests/065.bug152/run.sh) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/115.bug152/test.sh (renamed from src/test/regression/tests/065.bug152/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/116.bug230/.gitignore (renamed from src/test/regression/tests/066.bug230/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/116.bug230/Sample.java (renamed from src/test/regression/tests/066.bug230/Sample.java) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/116.bug230/test.sh (renamed from src/test/regression/tests/066.bug230/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/117.bug231/.gitignore (renamed from src/test/regression/tests/067.bug231/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/117.bug231/TestReplGap.java (renamed from src/test/regression/tests/067.bug231/TestReplGap.java) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/117.bug231/test.sh (renamed from src/test/regression/tests/067.bug231/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/118.memqcache_bug/.gitignore (renamed from src/test/regression/tests/068.memqcache_bug/.gitignore) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/118.memqcache_bug/Sample.java (renamed from src/test/regression/tests/068.memqcache_bug/Sample.java) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/118.memqcache_bug/test.sh (renamed from src/test/regression/tests/068.memqcache_bug/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/119.memory_leak_extended/.gitignore (renamed from src/test/regression/tests/069.memory_leak_extended/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/119.memory_leak_extended/test.sh (renamed from src/test/regression/tests/069.memory_leak_extended/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/120.memory_leak_extended_memqcache/.gitignore (renamed from src/test/regression/tests/070.memory_leak_extended_memqcache/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/120.memory_leak_extended_memqcache/test.sh (renamed from src/test/regression/tests/070.memory_leak_extended_memqcache/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/121.execute_and_deallocate/.gitignore (renamed from src/test/regression/tests/071.execute_and_deallocate/.gitignore) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/121.execute_and_deallocate/test.sh (renamed from src/test/regression/tests/071.execute_and_deallocate/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/122.meqcache_bug2/extended_query_test.data (renamed from src/test/regression/tests/072.meqcache_bug2/extended_query_test.data) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/122.meqcache_bug2/test.sh (renamed from src/test/regression/tests/072.meqcache_bug2/test.sh) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/123.pg_terminate_backend/test.sh (renamed from src/test/regression/tests/073.pg_terminate_backend/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/124.bug700_memqcache_segfault/expected.txt (renamed from src/test/regression/tests/074.bug700_memqcache_segfault/expected.txt) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/124.bug700_memqcache_segfault/pgproto.data (renamed from src/test/regression/tests/074.bug700_memqcache_segfault/pgproto.data) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/124.bug700_memqcache_segfault/test.sh (renamed from src/test/regression/tests/074.bug700_memqcache_segfault/test.sh) | 2 | ||||
| -rwxr-xr-x | src/test/regression/tests/125.detach_primary_left_down_node/test.sh (renamed from src/test/regression/tests/075.detach_primary_left_down_node/test.sh) | 2 | ||||
| -rw-r--r-- | src/test/regression/tests/126.copy_hang/copy-out-expected | 37 | ||||
| -rw-r--r-- | src/test/regression/tests/126.copy_hang/pgproto-copy-out.data | 9 | ||||
| -rw-r--r-- | src/test/regression/tests/126.copy_hang/pgproto.data (renamed from src/test/regression/tests/076.copy_hang/pgproto.data) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/126.copy_hang/test.sh (renamed from src/test/regression/tests/076.copy_hang/test.sh) | 16 | ||||
| -rwxr-xr-x | src/test/regression/tests/127.invalid_failover_node/test.sh (renamed from src/test/regression/tests/077.invalid_failover_node/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/128.aborted_transaction/expected.txt (renamed from src/test/regression/tests/078.aborted_transaction/expected.txt) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/128.aborted_transaction/test.sh (renamed from src/test/regression/tests/078.aborted_transaction/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/129.multi_prepare/expected.txt (renamed from src/test/regression/tests/079.multi_prepare/expected.txt) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/129.multi_prepare/pgproto.data (renamed from src/test/regression/tests/079.multi_prepare/pgproto.data) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/129.multi_prepare/test.sh (renamed from src/test/regression/tests/079.multi_prepare/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/130.declare/expected.txt (renamed from src/test/regression/tests/080.declare/expected.txt) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/130.declare/pgproto.data (renamed from src/test/regression/tests/080.declare/pgproto.data) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/130.declare/test.sh (renamed from src/test/regression/tests/080.declare/test.sh) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/131.detach_primary_all_down/test.sh (renamed from src/test/regression/tests/081.detach_primary_all_down/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/132.guard_against_bad_protocol/pgproto.data (renamed from src/test/regression/tests/082.guard_against_bad_protocol/pgproto.data) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/132.guard_against_bad_protocol/pgproto2.data (renamed from src/test/regression/tests/082.guard_against_bad_protocol/pgproto2.data) | 0 | ||||
| -rwxr-xr-x | src/test/regression/tests/132.guard_against_bad_protocol/test.sh (renamed from src/test/regression/tests/082.guard_against_bad_protocol/test.sh) | 0 | ||||
| -rw-r--r-- | src/test/regression/tests/README | 6 | ||||
| -rw-r--r-- | src/test/watchdog_setup.in | 36 | ||||
| -rw-r--r-- | src/tools/pgenc/pg_enc.c | 5 | ||||
| -rw-r--r-- | src/tools/pgindent/README.pgpool | 10 | ||||
| -rw-r--r-- | src/tools/pgindent/enums.list | 2 | ||||
| -rw-r--r-- | src/tools/pgindent/typedefs.list | 34 | ||||
| -rw-r--r-- | src/utils/json.c | 2 | ||||
| -rw-r--r-- | src/utils/pool_process_reporting.c | 10 | ||||
| -rw-r--r-- | src/utils/pool_relcache.c | 6 | ||||
| -rw-r--r-- | src/utils/pool_stream.c | 49 | ||||
| -rw-r--r-- | src/watchdog/watchdog.c | 59 | ||||
| -rw-r--r-- | src/watchdog/wd_commands.c | 4 | ||||
| -rw-r--r-- | src/watchdog/wd_heartbeat.c | 12 | ||||
| -rw-r--r-- | src/watchdog/wd_json_data.c | 20 | ||||
| -rw-r--r-- | src/watchdog/wd_lifecheck.c | 53 | ||||
| -rw-r--r-- | src/watchdog/wd_ping.c | 8 |
184 files changed, 4685 insertions, 2922 deletions
diff --git a/src/config/pool_config.l b/src/config/pool_config.l index b16130293..a75cedb16 100644 --- a/src/config/pool_config.l +++ b/src/config/pool_config.l @@ -6,7 +6,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2024 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -654,7 +654,7 @@ char *pool_flag_to_str(unsigned short flag) if (*buf == '\0') snprintf(buf, sizeof(buf), "ALWAYS_PRIMARY"); else - snprintf(buf+strlen(buf), sizeof(buf), "|ALWAYS_PRIMARY"); + strncat(buf, "|ALWAYS_PRIMARY", 16); } return buf; diff --git a/src/config/pool_config_variables.c b/src/config/pool_config_variables.c index 31f42caa9..0a0e48314 100644 --- a/src/config/pool_config_variables.c +++ b/src/config/pool_config_variables.c @@ -4,7 +4,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2024 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -142,6 +142,7 @@ static bool BackendSlotEmptyCheckFunc(int index); /*variable custom assign functions */ static bool FailOverOnBackendErrorAssignMessage(ConfigContext scontext, bool newval, int elevel); static bool DelegateIPAssignMessage(ConfigContext scontext, char *newval, int elevel); +static bool LogDirAssignMessage(ConfigContext scontext, char *newval, int elevel); static bool BackendPortAssignFunc(ConfigContext context, int newval, int index, int elevel); static bool BackendHostAssignFunc(ConfigContext context, char *newval, int index, int elevel); static bool BackendDataDirAssignFunc(ConfigContext context, char *newval, int index, int elevel); @@ -231,7 +232,6 @@ static const struct config_enum_entry backend_clustering_mode_options[] = { {"streaming_replication", CM_STREAMING_REPLICATION, false}, {"native_replication", CM_NATIVE_REPLICATION, false}, {"logical_replication", CM_LOGICAL_REPLICATION, false}, - {"slony", CM_SLONY, false}, {"raw", CM_RAW, false}, {"snapshot_isolation", CM_SNAPSHOT_ISOLATION, false}, {NULL, 0, false} @@ -480,7 +480,7 @@ static struct config_bool ConfigureNamesBool[] = CONFIG_VAR_TYPE_BOOL, false, 0 }, &g_pool_config.log_pcp_processes, - true, + false, NULL, NULL, NULL }, @@ -1353,13 +1353,24 @@ static struct config_string ConfigureNamesString[] = { {"logdir", CFGCXT_INIT, LOGGING_CONFIG, - "PgPool status file logging directory.", + "Old config parameter for work_dir.", + CONFIG_VAR_TYPE_STRING, false, VAR_HIDDEN_IN_SHOW_ALL + }, + NULL, + "", + LogDirAssignMessage, NULL, NULL, NULL + }, + + { + {"work_dir", CFGCXT_INIT, LOGGING_CONFIG, + "directory to create pgpool_status and lock files.", CONFIG_VAR_TYPE_STRING, false, 0 }, - &g_pool_config.logdir, + &g_pool_config.work_dir, DEFAULT_LOGDIR, NULL, NULL, NULL, NULL }, + { {"log_directory", CFGCXT_RELOAD, LOGGING_CONFIG, "directory where log files are written.", @@ -4540,25 +4551,8 @@ BackendDataDirShowFunc(int index) static const char * BackendFlagsShowFunc(int index) { - static char buffer[1024]; - unsigned short flag = g_pool_config.backend_desc->backend_info[index].flag; - - *buffer = '\0'; - - if (POOL_ALLOW_TO_FAILOVER(flag)) - snprintf(buffer, sizeof(buffer), "ALLOW_TO_FAILOVER"); - else if (POOL_DISALLOW_TO_FAILOVER(flag)) - snprintf(buffer, sizeof(buffer), "DISALLOW_TO_FAILOVER"); - - if (POOL_ALWAYS_PRIMARY & flag) - { - if (*buffer == '\0') - snprintf(buffer, sizeof(buffer), "ALWAYS_PRIMARY"); - else - snprintf(buffer + strlen(buffer), sizeof(buffer), "|ALWAYS_PRIMARY"); - } - return buffer; + return pool_flag_to_str(flag); } static const char * @@ -4826,7 +4820,32 @@ DelegateIPAssignMessage(ConfigContext scontext, char *newval, int elevel) ereport(WARNING, (errmsg("delegate_IP is changed to delegate_ip"), errdetail("if delegate_IP is specified, the value will be set to delegate_ip"))); - g_pool_config.delegate_ip = newval; + if (g_pool_config.delegate_ip) + pfree(g_pool_config.delegate_ip); + if (newval) + g_pool_config.delegate_ip = pstrdup(newval); + else + g_pool_config.delegate_ip = NULL; + return true; +} + +/* + * Throws warning for if someone uses the removed logdir + * configuration parameter and set the value to work_dir + */ +static bool +LogDirAssignMessage(ConfigContext scontext, char *newval, int elevel) +{ + if (scontext != CFGCXT_BOOT) + ereport(WARNING, + (errmsg("logdir is changed to work_dir"), + errdetail("if logdir is specified, the value will be set to work_dir"))); + if (g_pool_config.work_dir) + pfree(g_pool_config.work_dir); + if (newval) + g_pool_config.work_dir = pstrdup(newval); + else + g_pool_config.work_dir = NULL; return true; } @@ -5335,14 +5354,17 @@ SetPgpoolNodeId(int elevel) static bool SetHBDestIfFunc(int elevel) { - int idx = 0; + int dest_if_idx = 0; + int local_if_idx = 0; char **addrs; char **if_names; int i, j, + k, n_addr, n_if_name; + g_pool_config.num_hb_local_if = 0; g_pool_config.num_hb_dest_if = 0; if (g_pool_config.wd_lifecheck_method != LIFECHECK_BY_HB) @@ -5352,22 +5374,14 @@ SetHBDestIfFunc(int elevel) /* * g_pool_config.hb_ifs is the information for sending/receiving heartbeat - * for all nodes specified in pgpool.conf. If it is local pgpool node - * information, set dest_port to g_pool_config.wd_heartbeat_port and - * ignore addr and if_name. g_pool_config.hb_dest_if is the heartbeat + * for all nodes specified in pgpool.conf. g_pool_config.hb_local_if is + * the local node information. g_pool_config.hb_dest_if is the heartbeat * destination information. */ for (i = 0; i < WD_MAX_IF_NUM; i++) { if (g_pool_config.hb_ifs[i].dest_port > 0) { - /* Ignore local pgpool node */ - if (i == g_pool_config.pgpool_node_id) - { - g_pool_config.wd_heartbeat_port = g_pool_config.hb_ifs[i].dest_port; - continue; - } - WdHbIf *hbNodeInfo = &g_pool_config.hb_ifs[i]; addrs = get_list_from_string(hbNodeInfo->addr, ";", &n_addr); @@ -5375,7 +5389,10 @@ SetHBDestIfFunc(int elevel) if (!addrs || n_addr < 0) { - g_pool_config.hb_dest_if[idx].addr[0] = '\0'; + if (i == g_pool_config.pgpool_node_id) + g_pool_config.hb_local_if[local_if_idx].addr[0] = '\0'; + else + g_pool_config.hb_dest_if[dest_if_idx].addr[0] = '\0'; if (addrs) pfree(addrs); @@ -5391,19 +5408,46 @@ SetHBDestIfFunc(int elevel) for (j = 0; j < n_addr; j++) { - strlcpy(g_pool_config.hb_dest_if[idx].addr, addrs[j], WD_MAX_HOST_NAMELEN - 1); - g_pool_config.hb_dest_if[idx].dest_port = hbNodeInfo->dest_port; - if (n_if_name > j) + /* local pgpool node */ + if (i == g_pool_config.pgpool_node_id) { - strlcpy(g_pool_config.hb_dest_if[idx].if_name, if_names[j], WD_MAX_IF_NAME_LEN - 1); - pfree(if_names[j]); + for (k = 0; k < g_pool_config.wd_nodes.num_wd - 1; k++) + { + strlcpy(g_pool_config.hb_local_if[local_if_idx].addr, addrs[j], WD_MAX_HOST_NAMELEN - 1); + g_pool_config.hb_local_if[local_if_idx].dest_port = hbNodeInfo->dest_port; + + if (n_if_name > j) + strlcpy(g_pool_config.hb_local_if[local_if_idx].if_name, if_names[j], WD_MAX_IF_NAME_LEN - 1); + else + g_pool_config.hb_local_if[local_if_idx].if_name[0] = '\0'; + + g_pool_config.num_hb_local_if = local_if_idx + 1; + local_if_idx++; + } + + if (n_if_name > j) + pfree(if_names[j]); + + pfree(addrs[j]); + } + /* destination pgpool node */ else - g_pool_config.hb_dest_if[idx].if_name[0] = '\0'; + { + strlcpy(g_pool_config.hb_dest_if[dest_if_idx].addr, addrs[j], WD_MAX_HOST_NAMELEN - 1); + g_pool_config.hb_dest_if[dest_if_idx].dest_port = hbNodeInfo->dest_port; + if (n_if_name > j) + { + strlcpy(g_pool_config.hb_dest_if[dest_if_idx].if_name, if_names[j], WD_MAX_IF_NAME_LEN - 1); + pfree(if_names[j]); + } + else + g_pool_config.hb_dest_if[dest_if_idx].if_name[0] = '\0'; - g_pool_config.num_hb_dest_if = idx + 1; - idx++; - pfree(addrs[j]); + g_pool_config.num_hb_dest_if = dest_if_idx + 1; + dest_if_idx++; + pfree(addrs[j]); + } } if (addrs) diff --git a/src/context/pool_query_context.c b/src/context/pool_query_context.c index a4800d94b..1a13168c6 100644 --- a/src/context/pool_query_context.c +++ b/src/context/pool_query_context.c @@ -1983,7 +1983,7 @@ dml_adaptive(Node *node, char *query) /* * Decide the backend node to be sent in streaming replication mode, logical - * replication mode and slony mode. Called by pool_where_to_send. + * replication mode. Called by pool_where_to_send. */ static void where_to_send_main_replica(POOL_QUERY_CONTEXT *query_context, char *query, Node *node) diff --git a/src/include/main/health_check.h b/src/include/main/health_check.h index 29f59b7fd..f8369aa1e 100644 --- a/src/include/main/health_check.h +++ b/src/include/main/health_check.h @@ -3,7 +3,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2020 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -53,7 +53,7 @@ typedef struct extern volatile POOL_HEALTH_CHECK_STATISTICS *health_check_stats; /* health check stats * area in shared memory */ -extern void do_health_check_child(int *node_id); +extern void do_health_check_child(void *params); extern size_t health_check_stats_shared_memory_size(void); extern void health_check_stats_init(POOL_HEALTH_CHECK_STATISTICS *addr); diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h index 9571a5ee3..c375cb860 100644 --- a/src/include/parser/gramparse.h +++ b/src/include/parser/gramparse.h @@ -8,8 +8,8 @@ * Definitions that are needed outside the core parser should be in parser.h. * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/gramparse.h diff --git a/src/include/parser/keywords.h b/src/include/parser/keywords.h index 9a989763f..a56380499 100644 --- a/src/include/parser/keywords.h +++ b/src/include/parser/keywords.h @@ -4,8 +4,8 @@ * PostgreSQL's list of SQL keywords * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/keywords.h diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index bbf22fb52..098738447 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -7,8 +7,8 @@ * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -154,6 +154,7 @@ PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("enforced", ENFORCED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("error", ERROR_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) @@ -308,6 +309,7 @@ PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("objects", OBJECTS_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, AS_LABEL) @@ -339,6 +341,7 @@ PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("path", PATH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("period", PERIOD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("pgpool", PGPOOL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, BARE_LABEL) @@ -364,7 +367,6 @@ PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("ref", REF_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE_LABEL) @@ -492,6 +494,7 @@ PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("virtual", VIRTUAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, AS_LABEL) diff --git a/src/include/parser/kwlist_d.h b/src/include/parser/kwlist_d.h index 7c917a89a..023a3432a 100644 --- a/src/include/parser/kwlist_d.h +++ b/src/include/parser/kwlist_d.h @@ -3,7 +3,7 @@ * kwlist_d.h * List of keywords represented as a ScanKeywordList. * - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -150,6 +150,7 @@ static const char ScanKeywords_kw_string[] = "encoding\0" "encrypted\0" "end\0" + "enforced\0" "enum\0" "error\0" "escape\0" @@ -304,6 +305,7 @@ static const char ScanKeywords_kw_string[] = "nulls\0" "numeric\0" "object\0" + "objects\0" "of\0" "off\0" "offset\0" @@ -335,6 +337,7 @@ static const char ScanKeywords_kw_string[] = "passing\0" "password\0" "path\0" + "period\0" "pgpool\0" "placing\0" "plan\0" @@ -360,7 +363,6 @@ static const char ScanKeywords_kw_string[] = "read\0" "real\0" "reassign\0" - "recheck\0" "recursive\0" "ref\0" "references\0" @@ -488,6 +490,7 @@ static const char ScanKeywords_kw_string[] = "version\0" "view\0" "views\0" + "virtual\0" "volatile\0" "when\0" "where\0" @@ -645,515 +648,518 @@ static const uint16 ScanKeywords_kw_offsets[] = { 1003, 1013, 1017, - 1022, - 1028, - 1035, - 1041, - 1048, - 1056, - 1066, - 1076, - 1084, - 1091, - 1099, - 1110, - 1120, + 1026, + 1031, + 1037, + 1044, + 1050, + 1057, + 1065, + 1075, + 1085, + 1093, + 1100, + 1108, + 1119, 1129, - 1137, - 1143, - 1150, - 1156, - 1163, + 1138, + 1146, + 1152, + 1159, + 1165, 1172, - 1178, - 1184, - 1194, - 1198, - 1204, - 1212, - 1219, - 1227, - 1234, - 1239, - 1244, + 1181, + 1187, + 1193, + 1203, + 1207, + 1213, + 1221, + 1228, + 1236, + 1243, + 1248, 1253, - 1263, - 1273, - 1280, - 1286, - 1294, + 1262, + 1272, + 1282, + 1289, + 1295, 1303, - 1309, + 1312, 1318, - 1325, - 1333, - 1340, - 1347, - 1352, - 1357, + 1327, + 1334, + 1342, + 1349, + 1356, + 1361, 1366, - 1369, 1375, - 1385, - 1395, + 1378, + 1384, + 1394, 1404, - 1411, - 1414, - 1422, - 1432, - 1442, - 1449, - 1455, - 1463, - 1471, + 1413, + 1420, + 1423, + 1431, + 1441, + 1451, + 1458, + 1464, + 1472, 1480, - 1490, - 1497, - 1503, - 1509, - 1515, - 1527, - 1534, - 1542, - 1546, - 1554, - 1564, + 1489, + 1499, + 1506, + 1512, + 1518, + 1524, + 1536, + 1543, + 1551, + 1555, + 1563, 1573, - 1578, - 1586, - 1589, - 1596, - 1606, - 1611, - 1616, - 1627, - 1641, - 1653, - 1665, - 1680, - 1691, - 1703, - 1718, - 1729, - 1740, - 1745, + 1582, + 1587, + 1595, + 1598, + 1605, + 1615, + 1620, + 1625, + 1636, + 1650, + 1662, + 1674, + 1689, + 1700, + 1712, + 1727, + 1738, 1749, 1754, - 1760, + 1758, + 1763, 1769, - 1775, - 1780, - 1788, - 1796, - 1806, - 1812, - 1817, - 1823, - 1828, - 1834, - 1841, - 1846, - 1852, - 1862, - 1877, + 1778, + 1784, + 1789, + 1797, + 1805, + 1815, + 1821, + 1826, + 1832, + 1837, + 1843, + 1850, + 1855, + 1861, + 1871, 1886, - 1891, - 1898, - 1905, - 1913, - 1919, - 1927, - 1940, + 1895, + 1900, + 1907, + 1914, + 1922, + 1928, + 1936, 1949, - 1955, - 1968, - 1975, - 1982, + 1958, + 1964, + 1977, + 1984, 1991, - 1996, - 2002, - 2007, - 2012, - 2018, + 2000, + 2005, + 2011, + 2016, + 2021, 2027, - 2035, - 2041, - 2048, - 2052, + 2036, + 2044, + 2050, 2057, 2061, - 2065, + 2066, 2070, - 2075, - 2078, - 2083, - 2093, - 2104, - 2108, - 2116, - 2123, - 2131, - 2138, - 2143, - 2150, - 2156, - 2164, - 2171, - 2174, - 2178, - 2185, - 2190, - 2194, - 2199, + 2074, + 2079, + 2084, + 2087, + 2092, + 2102, + 2113, + 2117, + 2125, + 2132, + 2140, + 2147, + 2152, + 2159, + 2165, + 2173, + 2180, + 2188, + 2191, + 2195, 2202, 2207, + 2211, 2216, - 2223, - 2231, - 2234, + 2219, + 2224, + 2233, 2240, + 2248, 2251, - 2258, - 2262, + 2257, 2268, - 2273, - 2282, + 2275, + 2279, + 2285, 2290, - 2301, + 2299, 2307, - 2313, - 2322, - 2332, + 2318, + 2324, + 2330, 2339, - 2347, - 2357, - 2365, + 2349, + 2356, + 2364, 2374, - 2379, - 2386, - 2394, - 2399, - 2405, - 2412, - 2421, - 2431, - 2441, - 2449, - 2458, - 2467, - 2475, - 2481, - 2492, - 2503, - 2513, - 2524, - 2532, - 2544, - 2550, - 2557, - 2563, + 2382, + 2391, + 2396, + 2403, + 2410, + 2418, + 2423, + 2429, + 2436, + 2445, + 2455, + 2465, + 2473, + 2482, + 2491, + 2499, + 2505, + 2516, + 2527, + 2537, + 2548, + 2556, 2568, - 2573, - 2582, - 2590, - 2600, - 2604, - 2615, - 2627, - 2635, + 2574, + 2581, + 2587, + 2592, + 2597, + 2606, + 2616, + 2620, + 2631, 2643, - 2652, - 2660, - 2667, - 2678, - 2686, + 2651, + 2659, + 2668, + 2676, + 2683, 2694, - 2700, - 2708, - 2717, + 2702, + 2710, + 2716, 2724, - 2734, - 2742, - 2749, - 2755, - 2760, - 2769, + 2733, + 2740, + 2750, + 2758, + 2765, + 2771, 2776, - 2784, - 2793, - 2797, - 2802, - 2807, - 2817, - 2824, - 2831, - 2839, - 2846, - 2853, - 2860, + 2785, + 2792, + 2800, + 2809, + 2813, + 2818, + 2823, + 2833, + 2840, + 2847, + 2855, + 2862, 2869, 2876, 2885, - 2895, - 2908, - 2915, - 2923, - 2936, - 2940, - 2946, - 2951, - 2957, + 2892, + 2901, + 2911, + 2924, + 2931, + 2939, + 2952, + 2956, 2962, - 2970, - 2977, - 2982, - 2991, - 3000, - 3005, - 3012, + 2967, + 2973, + 2978, + 2986, + 2993, + 2998, + 3007, 3016, - 3023, - 3034, - 3040, + 3021, + 3028, + 3032, + 3039, 3050, - 3061, - 3067, - 3074, - 3082, - 3089, - 3096, - 3103, - 3109, - 3122, - 3132, - 3140, - 3150, + 3056, + 3066, + 3077, + 3083, + 3090, + 3098, + 3105, + 3112, + 3119, + 3125, + 3138, + 3148, 3156, - 3163, - 3175, - 3181, - 3188, - 3200, - 3211, - 3218, - 3223, - 3232, - 3242, - 3247, - 3252, - 3257, - 3262, - 3272, - 3275, - 3284, - 3296, - 3306, + 3166, + 3172, + 3179, + 3191, + 3197, + 3204, + 3216, + 3227, + 3234, + 3239, + 3248, + 3258, + 3263, + 3268, + 3273, + 3278, + 3288, + 3291, + 3300, 3312, - 3320, - 3325, - 3330, - 3339, - 3347, - 3352, - 3358, - 3366, - 3376, - 3388, - 3402, - 3414, - 3420, - 3427, - 3435, - 3444, - 3453, - 3459, - 3466, - 3471, - 3477, - 3484, - 3490, - 3499, - 3509, + 3322, + 3328, + 3336, + 3341, + 3346, + 3355, + 3363, + 3368, + 3374, + 3382, + 3392, + 3404, + 3418, + 3430, + 3436, + 3443, + 3451, + 3460, + 3469, + 3475, + 3482, + 3487, + 3493, + 3500, + 3506, 3515, - 3522, - 3530, - 3539, - 3547, + 3525, + 3531, + 3538, + 3546, 3555, 3563, - 3568, - 3574, - 3583, - 3588, - 3594, - 3605, + 3571, + 3579, + 3584, + 3590, + 3598, + 3607, 3612, - 3617, - 3624, - 3632, - 3637, - 3645, - 3651, - 3655, + 3618, + 3629, + 3636, + 3641, + 3648, + 3656, + 3661, 3669, + 3675, 3679, - 3690, - 3700, - 3710, + 3693, + 3703, + 3714, 3724, - 3733, - 3739, - 3747, - 3760, - 3769, - 3774, - 3778, + 3734, + 3748, + 3757, + 3763, + 3771, + 3784, + 3793, + 3798, + 3802, }; -#define SCANKEYWORDS_NUM_KEYWORDS 492 +#define SCANKEYWORDS_NUM_KEYWORDS 495 static int ScanKeywords_hash_func(const void *key, size_t keylen) { - static const int16 h[985] = { - -2, 143, 32767, 200, 0, 0, 448, 302, - 769, -52, 32767, 0, 32767, 0, 32767, 0, - 281, 253, 248, 612, 32767, 8, -436, 0, - 32767, 0, 32767, 354, -267, 362, 32767, 32767, - 568, 32767, 0, 32767, 289, 32767, 75, 32767, - 32767, 33, 32767, 165, 0, 32767, 32767, 32767, - 32767, -97, 32767, 358, 78, -272, 73, 339, - 2, 386, 43, 32767, 0, 32767, 508, -93, - -589, -159, -10, 0, -8, 32767, -359, 32767, - 288, -224, 58, 32767, -226, -10, 201, 32767, - 347, 32767, 255, 0, 464, -8, 0, 32767, - 225, 32767, -118, 32767, -658, 305, 297, -235, - 32767, 177, -393, 0, -43, 136, 32767, 32767, - 32767, 0, 270, -106, 190, 32767, 65, 32767, - 32767, 32767, 32767, -77, 32767, 148, -179, 334, - 0, 32767, 0, 32767, 32767, 280, 477, 346, - 32767, 148, 335, 66, 265, -204, 32767, 9, - -158, 32767, 372, 16, 32767, 227, -247, 0, - 228, -598, 32767, 257, 32767, 32767, 32767, 32767, - 32767, 402, 32767, 32767, 332, -42, 603, 32767, - 32767, 32767, 971, -38, 32767, 242, 0, 221, - -109, 459, 310, 126, 32767, 32767, 114, -410, - 130, 0, 32767, 312, 32767, 313, 32767, 392, - 516, 217, 32767, 0, 70, 32767, 478, 33, - 32767, 303, 32767, 0, 59, 194, 32767, 32767, - 0, 116, 0, 32767, 0, 32767, 32767, -325, - 81, -325, 32767, 0, -204, 0, 0, 32767, - 460, 32767, 0, 379, 375, 32767, 303, 159, - 32767, -24, 32767, 32767, 32767, 511, 32767, -185, - -622, 32767, 32767, 32767, 304, 1204, 0, 520, - 542, 593, -52, 32767, 32767, 291, 32767, 344, - 0, 31, -121, 0, 32767, 32767, 32767, 347, - 0, 32767, 32767, -1259, 0, 32767, 32767, 32767, - 480, 40, 153, 35, 582, 32767, 34, 115, - 32767, -83, 32767, 32767, 36, 324, -434, 32767, - 430, -24, -95, 32767, 32767, 32767, 172, -1264, - -236, -110, 32767, 87, -227, 179, 305, 0, - 32767, 32767, 32767, 32767, 32767, 32767, 0, 134, - 32767, 299, 32767, 32767, 25, 0, 14, -38, - 32767, 105, 392, 32767, 32767, 437, 32767, 32767, - 446, 32767, 358, 264, 209, 32767, 238, 596, - 156, -689, 32767, 435, 32767, 85, -9, -155, - 414, 0, 65, 32767, 32767, -94, 354, 46, - 69, -119, 185, 275, 1727, 32767, 32767, -99, - 32767, 445, 32767, -975, -183, 32767, 32767, 479, - 78, 32767, 0, 32767, 32767, 32767, 452, 252, - 32767, 0, 378, 32767, 32767, -34, 88, 13, - 32767, 32767, 32767, 32767, 107, 32767, 32767, -86, - 298, 1307, 180, 32767, 32767, 32767, 32767, -150, - 95, 0, 32767, 377, 32767, 182, 32767, -1192, - 287, 32767, 0, 554, -1011, 32767, 346, 26, - 0, 32767, 338, 426, 32767, 652, 240, -244, - 0, 118, 32767, -203, 133, 32767, 79, 0, - 94, 32767, 456, 32767, -657, 462, 32767, 266, - 158, 781, 32767, -273, 32767, 351, 0, 32767, - 392, 0, 89, 32767, 41, 370, 32767, 61, - -148, 32767, 32767, -37, 32767, -76, 315, 32767, - 32767, 32767, 358, 139, 56, 458, 32767, 415, - 32767, 32767, 653, 32767, 32767, 32767, -236, 32767, - 0, 0, 615, 32767, 0, 32767, 55, -912, - 32767, 113, 206, 32767, 32767, 32767, 32767, 0, - 32767, 96, 32767, 396, 175, 129, 32767, 32767, - 138, -147, 32767, 32767, -157, 270, 32767, -460, - 263, 448, 32767, 32767, 0, 371, 32767, 32767, - 32767, 32767, -283, 32767, 32767, 197, 0, 32767, - 374, 581, -549, 32767, 32767, 56, 32767, 0, - 234, -115, 32767, -439, 466, 32767, 32767, 0, - 388, 184, 32767, 32767, 83, 32767, 32767, 120, - -277, 0, 32767, 0, 180, 32767, 0, 205, - 32767, 32767, 219, 0, 32767, 32767, -32, 159, - 32767, 204, 0, 826, 495, 32767, 190, 0, - 400, 379, 32767, 32767, -108, 72, 459, 32767, - 32767, 0, 92, 32767, 276, 133, 32767, 32767, - 160, -36, 32767, 70, 871, 32767, 32767, -436, - 32767, 32767, 980, 385, 0, 9, 32767, 327, - 519, 0, 32767, 0, -31, 0, 11, 0, - 32767, 412, 124, -121, 377, 0, 32767, 32767, - 0, 137, 32767, 66, -123, 264, -50, 3, - -190, 21, 32767, 267, 32767, 0, 0, 32767, - 32767, 32767, 221, 32767, 32767, -301, 38, -319, - 389, 32767, 32767, 275, 964, -30, 330, 172, - 32767, 329, -299, 32767, 524, 341, 32767, 32767, - 123, -76, 415, 151, 32767, 179, 0, -365, - 32767, -268, 32767, -425, 203, 0, 146, 32767, - 290, 32767, 259, 32767, 0, 1, 32767, 239, - 160, 914, 39, 32767, -194, 104, 0, 0, - 32767, 32767, 32767, 0, 32767, 32767, 10, 487, - 0, 279, 32767, 223, 32767, 32767, 0, -286, - -510, 151, 429, 32767, 0, 115, 32767, -66, - 647, 291, 32767, -290, 32767, 0, -433, 0, - 180, 32767, 116, 32767, 301, 32767, 282, 294, - 0, 32767, -126, 0, -412, 0, 315, 32767, - 400, 0, 32767, 32767, 32767, 109, -227, 0, - -352, 32767, 112, 0, 471, 0, 32767, 32767, - 461, 32767, 32767, 233, 32767, 32767, 406, 32767, - 464, 32767, 118, 382, 0, 32767, 0, 32767, - 32767, 541, -305, 814, 0, 268, 0, 403, - 268, 372, 84, 32767, -91, 32767, 0, 32767, - 208, 467, 0, 32767, 32767, 32767, -236, 32767, - 32767, -53, -317, 32767, 338, 0, 0, 646, - 32767, 78, 32767, 158, 399, 0, 32767, 0, - -269, 32767, 32767, -213, -786, 32767, 162, 32767, - 32767, -259, 401, 383, 453, 0, 32767, 0, - -232, -159, 322, 32767, 32767, 203, 0, 32767, - 183, 314, 32767, -86, 32767, 377, 195, 878, - 93, -80, 212, 32767, 49, 32767, 614, 337, - 32767, 318, -59, 285, 32767, 0, 32767, 0, - 98, 17, 32767, 0, -192, 482, 0, 32767, - 102, 32767, 331, 366, 0, -325, -143, 438, - 465, 35, 472, 32767, 670, 32767, 0, 0, - 32767, 32767, 32767, 0, 109, 226, 32767, 32767, - 25, -227, 0, 0, 768, 32767, -363, 32767, - 245, 129, 32767, 405, 95, 407, 345, 1494, - 32767, 0, 473, 32767, 32767, 32767, 32767, 0, - 0, 32767, 32767, 244, 32767, 82, 32767, 38, - 32767, 97, -39, 397, 32767, 32767, 32767, 32767, - 32767, 90, 605, 105, 32767, 0, 0, 0, - 250, 32767, 372, 32767, 32767, 0, -434, 0, - 32767, 216, 32767, 443, 32767, 185, 51, 367, - 32767, 87, 0, 560, 0, 0, 0, 0, - 349, -120, 32767, 32767, 408, 32767, 32767, 0, - 32767, 0, 32767, 32767, 32767, 744, 250, -146, - 32767, 142, 0, -492, 32767, 334, 441, 32767, - 0 + static const int16 h[991] = { + 32767, -121, 32767, -21, 32767, 32767, 32767, -435, + 391, 32767, 32767, 487, 377, 213, 32767, 32767, + 32767, 32767, 32767, 20, 32767, 32767, 1, -114, + 458, 375, 88, 535, 32767, 32767, 319, 387, + -180, 0, 0, 32767, -473, 163, 105, 0, + 32767, 32767, 32767, 21, 173, -212, 32767, 371, + 65, 125, 32767, 455, 32767, 370, -342, 830, + 32767, 176, 1114, -78, -161, 32767, 239, -903, + 32767, -653, 32767, -412, 149, 32767, 1137, 32767, + -618, 32767, 919, -333, 237, 20, 32767, 380, + 195, 32767, 152, 135, 264, 115, 95, 0, + 32767, 876, -342, 32767, 32767, 374, 956, 108, + -41, 0, -760, 32767, 32767, 0, 32767, 422, + 328, 32767, 32767, 32767, 60, -183, 32767, -630, + 32767, 266, -353, 503, 32767, -111, 32767, 32767, + 480, 171, -264, 32767, 193, 482, 73, 194, + 32767, 288, 32767, 176, 370, 32767, 32767, 0, + 234, 32767, 62, 229, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 32767, 466, 32767, 56, 32767, + -77, 407, 395, 86, 0, 32767, 201, 562, + 0, -460, 0, 32767, 32767, 32767, 290, 32767, + 35, 32767, 1, 32767, 396, 70, 0, 97, + 434, 420, 272, 178, 32767, 32767, 29, 346, + 0, 382, 32767, 32767, 423, -1086, 32767, 378, + 32767, 429, 32767, -210, 0, 32767, 32767, 369, + -652, 328, 64, 418, 1112, 32767, 32767, 0, + 0, 216, 32767, 32767, -339, -659, 32767, 289, + 419, 47, 32767, 767, -622, 0, -293, 0, + 32767, 32767, -257, 0, 0, 32767, 0, 32767, + 32767, 441, 32767, 0, -279, 0, 38, -433, + 32767, 470, 32767, 0, 32767, 245, -162, 32767, + 32767, -238, 32767, 0, 32767, 32767, 77, 32767, + 32767, 103, 32767, 32767, 181, 342, 32767, 150, + 440, 12, 32767, 244, 32767, 0, -149, 835, + 32767, 390, 423, 189, 32767, 32767, 32767, 32767, + 32767, 0, 0, -138, 32767, 255, 32767, 282, + 32767, -740, -639, 48, -126, 32767, 32767, 32767, + 32767, 32767, 32767, 647, 46, 369, 32767, 0, + 32767, 32767, -206, 32767, 32767, -130, 32767, 96, + 32767, 0, -27, 32767, 356, 32767, 32767, -311, + 314, 13, -158, 32767, 32767, 0, 486, 52, + 32767, 437, -3, 308, -314, -94, 32767, 32767, + 32767, 32767, 0, 32767, 765, 270, 32767, 205, + 32767, 32767, 240, -328, -50, 70, 57, -99, + 95, 32767, 32767, 464, 32767, 32767, 32767, 203, + 445, 32767, 391, 32767, 141, -210, 172, -125, + 0, 32767, 130, 32767, -66, 32767, 32767, 0, + 393, 32767, 32767, 185, 0, 32767, 258, 40, + -799, 32767, 23, 32767, 87, 32767, 119, 32767, + 32767, -227, 138, 32767, 32767, 32767, 206, 344, + 1, 71, 32767, 0, 421, 32767, 32767, 32767, + -625, 32767, 32767, 38, 491, 32767, 32767, -984, + 198, 0, 455, -16, 56, 0, -717, 411, + 200, 0, 32767, 0, 32767, 188, 82, 32767, + 32767, 0, 32767, -80, 80, 32767, -675, 32767, + 378, 26, 0, 32767, 32767, 57, 0, 32767, + 633, 32767, 0, 32767, 307, 32767, 132, 32767, + 320, 220, 32767, 0, 264, 32767, 499, -7, + 139, 271, 32767, 357, 532, 168, 32767, 258, + 32767, 17, 219, -178, 299, 32767, 32767, -27, + 382, 32767, 32767, 32767, 32767, 32767, 637, 32767, + 32767, 329, -364, 32767, -16, 355, -197, 127, + 340, -434, 224, -3, -186, 0, 176, 156, + 32767, 32767, 105, 32767, 435, 34, 32767, 32767, + 568, -176, 0, -471, 333, 32767, 0, -218, + 32767, 254, 283, 0, 326, 32767, 32767, 32767, + 0, 32767, 32767, 99, -142, 0, 318, 303, + 360, 267, 32767, 344, 0, 32767, 32767, 32767, + 547, 32767, 32767, 334, 0, -59, 446, -366, + -253, 32767, -165, 32767, 32767, 32767, 427, -152, + 15, 32767, 32767, 0, 51, 32767, 98, 599, + 169, 31, 0, -116, 0, 0, 32767, -402, + 32767, 32767, 263, 32767, 32767, -205, -94, 0, + 280, 260, 32767, 32767, 1124, 32767, -543, 0, + 0, 32767, 32767, 32767, 32767, 32767, 773, 7, + 930, 288, -620, 32767, 132, 32767, 0, 0, + 58, 32767, 373, 848, 228, 112, -4, 32767, + 32767, -152, 651, 32767, 32767, 1013, -685, 240, + 242, -117, 38, 110, 32767, 0, 32767, -48, + 32767, -113, 32767, 0, 92, 1228, 0, 760, + 32767, 0, 32767, 0, 457, -144, 774, 198, + 32767, 32767, 32767, 351, 329, 292, 32767, 32767, + 118, 32767, 32767, 331, 80, 117, 815, 32767, + 0, 32767, 370, 32767, 32767, 0, 32767, -419, + 32767, 32767, 32767, 0, 32767, 32767, 32767, 193, + 0, 32767, 0, 32767, 32767, 32767, 870, 0, + 32767, -52, 454, 0, 32767, 64, 0, 310, + 0, -338, 32767, 119, 32767, 32767, -366, 32767, + 0, 159, 32767, 362, 66, 32767, 32767, 32767, + 0, -122, -39, 425, 361, 32767, -160, 420, + 163, 210, 32767, 32767, 32767, 32767, -642, 0, + -287, 0, 32767, 0, 401, 0, 221, 32767, + 238, 0, 525, 0, 91, 32767, 325, 32767, + 32767, -651, 129, 463, 0, 0, 32767, 172, + 287, 32767, 32767, -122, 0, 32767, 32767, 798, + 492, 109, -52, 0, 0, 6, 32767, 32767, + 32767, 474, 32767, 87, 32767, 32767, 31, 32767, + 451, 7, 252, 69, 32767, 6, -276, 97, + 32767, 32767, 32767, 32767, 32767, 141, 524, 32767, + 83, -304, 32767, 32767, 32767, 941, 32767, 32767, + 32767, 32767, 107, 32767, 32767, 32767, 32767, 32767, + 32767, 535, -733, 493, 32767, 554, -257, 18, + 173, -370, 191, 528, 406, 0, 468, 292, + 32767, -142, 417, 179, -27, 322, 32767, 504, + 32767, 433, 153, 182, 394, 32767, 32767, 32767, + 0, 32767, 177, 118, 32767, 32767, 83, 194, + 18, -781, 0, 322, 0, 19, 344, 32767, + 156, 118, 0, 32767, 372, 32767, 32767, 0, + 32767, -452, 366, 1133, -126, 834, 32767, 32767, + 32767, 1193, 162, 32767, 0, 0, -328, 360, + 353, -489, 0, 32767, 32767, 32767, 32767, 32767, + -237, 290, 32767, -780, 32767, -78, 32767, 0, + 137, 0, 94, 0, 344, 32767, 671, -164, + 422, 32767, 405, 32767, 57, 0, 141, 32767, + 32767, -16, 32767, 32767, -55, 46, 221, 32767, + 247, 32767, 0, 10, 32767, 401, 613, 32767, + 0, -244, 250, 32767, 223, 32767, 274, 32767, + 32767, 0, 124, 32767, 291, 303, -299, 234, + 38, 32767, 0, 32767, 181, 0, 536, 32767, + 23, -195, -192, 0, 1087, 32767, 60, 32767, + 177, 32767, 0, -646, 622, -36, 752, 46, + 0, 32767, 32767, 1067, 0, 32767, -187, 192, + 0, 32767, 32767, 425, 0, 32767, 879, 32767, + 32767, -129, 0, 32767, 190, 175, 254 }; const unsigned char *k = (const unsigned char *) key; uint32 a = 0; - uint32 b = 0; + uint32 b = 1; while (keylen--) { unsigned char c = *k++ | 0x20; a = a * 257 + c; - b = b * 31 + c; + b = b * 127 + c; } - return h[a % 985] + h[b % 985]; + return h[a % 991] + h[b % 991]; } const ScanKeywordList ScanKeywords = { diff --git a/src/include/parser/makefuncs.h b/src/include/parser/makefuncs.h index 1086b1f55..0441c8e5d 100644 --- a/src/include/parser/makefuncs.h +++ b/src/include/parser/makefuncs.h @@ -4,8 +4,8 @@ * prototypes for the creator functions of various nodes * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/makefuncs.h @@ -68,6 +68,7 @@ extern RelabelType *makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat); extern RangeVar *makeRangeVar(char *schemaname, char *relname, int location); +extern Constraint *makeNotNullConstraint(String *colname); extern TypeName *makeTypeName(char *typnam); extern TypeName *makeTypeNameFromNameList(List *names); diff --git a/src/include/parser/miscnodes.h b/src/include/parser/miscnodes.h new file mode 100644 index 000000000..719cacff1 --- /dev/null +++ b/src/include/parser/miscnodes.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * miscnodes.h + * Definitions for hard-to-classify node types. + * + * Node types declared here are not part of parse trees, plan trees, + * or execution state trees. We only assign them NodeTag values because + * IsA() tests provide a convenient way to disambiguate what kind of + * structure is being passed through assorted APIs, such as function + * "context" pointers. + * + * + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/miscnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef MISCNODES_H +#define MISCNODES_H + +#include "nodes.h" + +/* + * ErrorSaveContext - + * function call context node for handling of "soft" errors + * + * A caller wishing to trap soft errors must initialize a struct like this + * with all fields zero/NULL except for the NodeTag. Optionally, set + * details_wanted = true if more than the bare knowledge that a soft error + * occurred is required. The struct is then passed to a SQL-callable function + * via the FunctionCallInfo.context field; or below the level of SQL calls, + * it could be passed to a subroutine directly. + * + * After calling code that might report an error this way, check + * error_occurred to see if an error happened. If so, and if details_wanted + * is true, error_data has been filled with error details (stored in the + * callee's memory context!). The ErrorData can be modified (e.g. downgraded + * to a WARNING) and reported with ThrowErrorData(). FreeErrorData() can be + * called to release error_data, although that step is typically not necessary + * if the called code was run in a short-lived context. + */ +typedef struct ErrorSaveContext +{ + NodeTag type; + bool error_occurred; /* set to true if we detect a soft error */ + bool details_wanted; /* does caller want more info than that? */ + ErrorData *error_data; /* details of error, if so */ +} ErrorSaveContext; + +#endif /* MISCNODES_H */ diff --git a/src/include/parser/nodes.h b/src/include/parser/nodes.h index d0d4f3cce..5412ef4c8 100644 --- a/src/include/parser/nodes.h +++ b/src/include/parser/nodes.h @@ -4,8 +4,8 @@ * Definitions for tagged nodes. * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/nodes.h @@ -30,12 +30,11 @@ typedef enum NodeTag { T_Invalid = 0, - +#include "nodetags.h" /* pgpool Extension */ T_PgpoolVariableSetStmt, T_PgpoolVariableShowStmt, T_PgpoolQueryCacheStmt, -#include "nodetags.h" } NodeTag; /* @@ -62,6 +61,7 @@ typedef enum NodeTag * readfuncs.c. * * - custom_query_jumble: Has custom implementation in queryjumblefuncs.c. + * Also available as a node field attribute. * * - no_copy: Does not support copyObject() at all. * @@ -109,10 +109,15 @@ typedef enum NodeTag * - equal_ignore_if_zero: Ignore the field for equality if it is zero. * (Otherwise, compare normally.) * + * - custom_query_jumble: Has custom implementation in queryjumblefuncs.c + * for the field of a node. Also available as a node attribute. + * * - query_jumble_ignore: Ignore the field for the query jumbling. Note * that typmod and collation information are usually irrelevant for the * query jumbling. * + * - query_jumble_squash: Squash multiple values during query jumbling. + * * - query_jumble_location: Mark the field as a location to track. This is * only allowed for integer fields that include "location" in their name. * @@ -210,7 +215,7 @@ extern char *bmsToString(const struct Bitmapset *bms); * nodes/{readfuncs.c,read.c} */ extern void *stringToNode(const char *str); -#ifdef WRITE_READ_PARSE_PLAN_TREES +#ifdef DEBUG_NODE_TESTS_ENABLED extern void *stringToNodeWithLocations(const char *str); #endif extern struct Bitmapset *readBitmapset(void); @@ -314,6 +319,7 @@ typedef enum JoinType */ JOIN_SEMI, /* 1 copy of each LHS row that has match(es) */ JOIN_ANTI, /* 1 copy of each LHS row that has no match */ + JOIN_RIGHT_SEMI, /* 1 copy of each RHS row that has match(es) */ JOIN_RIGHT_ANTI, /* 1 copy of each RHS row that has no match */ /* @@ -330,10 +336,10 @@ typedef enum JoinType /* * OUTER joins are those for which pushed-down quals must behave differently - * from the join's own quals. This is in fact everything except INNER and - * SEMI joins. However, this macro must also exclude the JOIN_UNIQUE symbols - * since those are temporary proxies for what will eventually be an INNER - * join. + * from the join's own quals. This is in fact everything except INNER, SEMI + * and RIGHT_SEMI joins. However, this macro must also exclude the + * JOIN_UNIQUE symbols since those are temporary proxies for what will + * eventually be an INNER join. * * Note: semijoins are a hybrid case, but we choose to treat them as not * being outer joins. This is okay principally because the SQL syntax makes diff --git a/src/include/parser/nodetags.h b/src/include/parser/nodetags.h index ee1fb29ce..312727639 100644 --- a/src/include/parser/nodetags.h +++ b/src/include/parser/nodetags.h @@ -3,7 +3,7 @@ * nodetags.h * Generated node infrastructure code * - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -75,45 +75,45 @@ T_CurrentOfExpr = 58, T_NextValueExpr = 59, T_InferenceElem = 60, - T_TargetEntry = 61, - T_RangeTblRef = 62, - T_JoinExpr = 63, - T_FromExpr = 64, - T_OnConflictExpr = 65, - T_Query = 66, - T_TypeName = 67, - T_ColumnRef = 68, - T_ParamRef = 69, - T_A_Expr = 70, - T_A_Const = 71, - T_TypeCast = 72, - T_CollateClause = 73, - T_RoleSpec = 74, - T_FuncCall = 75, - T_A_Star = 76, - T_A_Indices = 77, - T_A_Indirection = 78, - T_A_ArrayExpr = 79, - T_ResTarget = 80, - T_MultiAssignRef = 81, - T_SortBy = 82, - T_WindowDef = 83, - T_RangeSubselect = 84, - T_RangeFunction = 85, - T_RangeTableFunc = 86, - T_RangeTableFuncCol = 87, - T_RangeTableSample = 88, - T_ColumnDef = 89, - T_TableLikeClause = 90, - T_IndexElem = 91, - T_DefElem = 92, - T_LockingClause = 93, - T_XmlSerialize = 94, - T_PartitionElem = 95, - T_PartitionSpec = 96, - T_PartitionBoundSpec = 97, - T_PartitionRangeDatum = 98, - T_SinglePartitionSpec = 99, + T_ReturningExpr = 61, + T_TargetEntry = 62, + T_RangeTblRef = 63, + T_JoinExpr = 64, + T_FromExpr = 65, + T_OnConflictExpr = 66, + T_Query = 67, + T_TypeName = 68, + T_ColumnRef = 69, + T_ParamRef = 70, + T_A_Expr = 71, + T_A_Const = 72, + T_TypeCast = 73, + T_CollateClause = 74, + T_RoleSpec = 75, + T_FuncCall = 76, + T_A_Star = 77, + T_A_Indices = 78, + T_A_Indirection = 79, + T_A_ArrayExpr = 80, + T_ResTarget = 81, + T_MultiAssignRef = 82, + T_SortBy = 83, + T_WindowDef = 84, + T_RangeSubselect = 85, + T_RangeFunction = 86, + T_RangeTableFunc = 87, + T_RangeTableFuncCol = 88, + T_RangeTableSample = 89, + T_ColumnDef = 90, + T_TableLikeClause = 91, + T_IndexElem = 92, + T_DefElem = 93, + T_LockingClause = 94, + T_XmlSerialize = 95, + T_PartitionElem = 96, + T_PartitionSpec = 97, + T_PartitionBoundSpec = 98, + T_PartitionRangeDatum = 99, T_PartitionCmd = 100, T_RangeTblEntry = 101, T_RTEPermissionInfo = 102, @@ -131,361 +131,366 @@ T_CTECycleClause = 114, T_CommonTableExpr = 115, T_MergeWhenClause = 116, - T_TriggerTransition = 117, - T_JsonOutput = 118, - T_JsonArgument = 119, - T_JsonFuncExpr = 120, - T_JsonTablePathSpec = 121, - T_JsonTable = 122, - T_JsonTableColumn = 123, - T_JsonKeyValue = 124, - T_JsonParseExpr = 125, - T_JsonScalarExpr = 126, - T_JsonSerializeExpr = 127, - T_JsonObjectConstructor = 128, - T_JsonArrayConstructor = 129, - T_JsonArrayQueryConstructor = 130, - T_JsonAggConstructor = 131, - T_JsonObjectAgg = 132, - T_JsonArrayAgg = 133, - T_RawStmt = 134, - T_InsertStmt = 135, - T_DeleteStmt = 136, - T_UpdateStmt = 137, - T_MergeStmt = 138, - T_SelectStmt = 139, - T_SetOperationStmt = 140, - T_ReturnStmt = 141, - T_PLAssignStmt = 142, - T_CreateSchemaStmt = 143, - T_AlterTableStmt = 144, - T_ReplicaIdentityStmt = 145, - T_AlterTableCmd = 146, - T_AlterCollationStmt = 147, - T_AlterDomainStmt = 148, - T_GrantStmt = 149, - T_ObjectWithArgs = 150, - T_AccessPriv = 151, - T_GrantRoleStmt = 152, - T_AlterDefaultPrivilegesStmt = 153, - T_CopyStmt = 154, - T_VariableSetStmt = 155, - T_VariableShowStmt = 156, - T_CreateStmt = 157, - T_Constraint = 158, - T_CreateTableSpaceStmt = 159, - T_DropTableSpaceStmt = 160, - T_AlterTableSpaceOptionsStmt = 161, - T_AlterTableMoveAllStmt = 162, - T_CreateExtensionStmt = 163, - T_AlterExtensionStmt = 164, - T_AlterExtensionContentsStmt = 165, - T_CreateFdwStmt = 166, - T_AlterFdwStmt = 167, - T_CreateForeignServerStmt = 168, - T_AlterForeignServerStmt = 169, - T_CreateForeignTableStmt = 170, - T_CreateUserMappingStmt = 171, - T_AlterUserMappingStmt = 172, - T_DropUserMappingStmt = 173, - T_ImportForeignSchemaStmt = 174, - T_CreatePolicyStmt = 175, - T_AlterPolicyStmt = 176, - T_CreateAmStmt = 177, - T_CreateTrigStmt = 178, - T_CreateEventTrigStmt = 179, - T_AlterEventTrigStmt = 180, - T_CreatePLangStmt = 181, - T_CreateRoleStmt = 182, - T_AlterRoleStmt = 183, - T_AlterRoleSetStmt = 184, - T_DropRoleStmt = 185, - T_CreateSeqStmt = 186, - T_AlterSeqStmt = 187, - T_DefineStmt = 188, - T_CreateDomainStmt = 189, - T_CreateOpClassStmt = 190, - T_CreateOpClassItem = 191, - T_CreateOpFamilyStmt = 192, - T_AlterOpFamilyStmt = 193, - T_DropStmt = 194, - T_TruncateStmt = 195, - T_CommentStmt = 196, - T_SecLabelStmt = 197, - T_DeclareCursorStmt = 198, - T_ClosePortalStmt = 199, - T_FetchStmt = 200, - T_IndexStmt = 201, - T_CreateStatsStmt = 202, - T_StatsElem = 203, - T_AlterStatsStmt = 204, - T_CreateFunctionStmt = 205, - T_FunctionParameter = 206, - T_AlterFunctionStmt = 207, - T_DoStmt = 208, - T_InlineCodeBlock = 209, - T_CallStmt = 210, - T_CallContext = 211, - T_RenameStmt = 212, - T_AlterObjectDependsStmt = 213, - T_AlterObjectSchemaStmt = 214, - T_AlterOwnerStmt = 215, - T_AlterOperatorStmt = 216, - T_AlterTypeStmt = 217, - T_RuleStmt = 218, - T_NotifyStmt = 219, - T_ListenStmt = 220, - T_UnlistenStmt = 221, - T_TransactionStmt = 222, - T_CompositeTypeStmt = 223, - T_CreateEnumStmt = 224, - T_CreateRangeStmt = 225, - T_AlterEnumStmt = 226, - T_ViewStmt = 227, - T_LoadStmt = 228, - T_CreatedbStmt = 229, - T_AlterDatabaseStmt = 230, - T_AlterDatabaseRefreshCollStmt = 231, - T_AlterDatabaseSetStmt = 232, - T_DropdbStmt = 233, - T_AlterSystemStmt = 234, - T_ClusterStmt = 235, - T_VacuumStmt = 236, - T_VacuumRelation = 237, - T_ExplainStmt = 238, - T_CreateTableAsStmt = 239, - T_RefreshMatViewStmt = 240, - T_CheckPointStmt = 241, - T_DiscardStmt = 242, - T_LockStmt = 243, - T_ConstraintsSetStmt = 244, - T_ReindexStmt = 245, - T_CreateConversionStmt = 246, - T_CreateCastStmt = 247, - T_CreateTransformStmt = 248, - T_PrepareStmt = 249, - T_ExecuteStmt = 250, - T_DeallocateStmt = 251, - T_DropOwnedStmt = 252, - T_ReassignOwnedStmt = 253, - T_AlterTSDictionaryStmt = 254, - T_AlterTSConfigurationStmt = 255, - T_PublicationTable = 256, - T_PublicationObjSpec = 257, - T_CreatePublicationStmt = 258, - T_AlterPublicationStmt = 259, - T_CreateSubscriptionStmt = 260, - T_AlterSubscriptionStmt = 261, - T_DropSubscriptionStmt = 262, - T_PlannerGlobal = 263, - T_PlannerInfo = 264, - T_RelOptInfo = 265, - T_IndexOptInfo = 266, - T_ForeignKeyOptInfo = 267, - T_StatisticExtInfo = 268, - T_JoinDomain = 269, - T_EquivalenceClass = 270, - T_EquivalenceMember = 271, - T_PathKey = 272, - T_GroupByOrdering = 273, - T_PathTarget = 274, - T_ParamPathInfo = 275, - T_Path = 276, - T_IndexPath = 277, - T_IndexClause = 278, - T_BitmapHeapPath = 279, - T_BitmapAndPath = 280, - T_BitmapOrPath = 281, - T_TidPath = 282, - T_TidRangePath = 283, - T_SubqueryScanPath = 284, - T_ForeignPath = 285, - T_CustomPath = 286, - T_AppendPath = 287, - T_MergeAppendPath = 288, - T_GroupResultPath = 289, - T_MaterialPath = 290, - T_MemoizePath = 291, - T_UniquePath = 292, - T_GatherPath = 293, - T_GatherMergePath = 294, - T_NestPath = 295, - T_MergePath = 296, - T_HashPath = 297, - T_ProjectionPath = 298, - T_ProjectSetPath = 299, - T_SortPath = 300, - T_IncrementalSortPath = 301, - T_GroupPath = 302, - T_UpperUniquePath = 303, - T_AggPath = 304, - T_GroupingSetData = 305, - T_RollupData = 306, - T_GroupingSetsPath = 307, - T_MinMaxAggPath = 308, - T_WindowAggPath = 309, - T_SetOpPath = 310, - T_RecursiveUnionPath = 311, - T_LockRowsPath = 312, - T_ModifyTablePath = 313, - T_LimitPath = 314, - T_RestrictInfo = 315, - T_PlaceHolderVar = 316, - T_SpecialJoinInfo = 317, - T_OuterJoinClauseInfo = 318, - T_AppendRelInfo = 319, - T_RowIdentityVarInfo = 320, - T_PlaceHolderInfo = 321, - T_MinMaxAggInfo = 322, - T_PlannerParamItem = 323, - T_AggInfo = 324, - T_AggTransInfo = 325, - T_PlannedStmt = 326, - T_Result = 327, - T_ProjectSet = 328, - T_ModifyTable = 329, - T_Append = 330, - T_MergeAppend = 331, - T_RecursiveUnion = 332, - T_BitmapAnd = 333, - T_BitmapOr = 334, - T_SeqScan = 335, - T_SampleScan = 336, - T_IndexScan = 337, - T_IndexOnlyScan = 338, - T_BitmapIndexScan = 339, - T_BitmapHeapScan = 340, - T_TidScan = 341, - T_TidRangeScan = 342, - T_SubqueryScan = 343, - T_FunctionScan = 344, - T_ValuesScan = 345, - T_TableFuncScan = 346, - T_CteScan = 347, - T_NamedTuplestoreScan = 348, - T_WorkTableScan = 349, - T_ForeignScan = 350, - T_CustomScan = 351, - T_NestLoop = 352, - T_NestLoopParam = 353, - T_MergeJoin = 354, - T_HashJoin = 355, - T_Material = 356, - T_Memoize = 357, - T_Sort = 358, - T_IncrementalSort = 359, - T_Group = 360, - T_Agg = 361, - T_WindowAgg = 362, - T_Unique = 363, - T_Gather = 364, - T_GatherMerge = 365, - T_Hash = 366, - T_SetOp = 367, - T_LockRows = 368, - T_Limit = 369, - T_PlanRowMark = 370, - T_PartitionPruneInfo = 371, - T_PartitionedRelPruneInfo = 372, - T_PartitionPruneStepOp = 373, - T_PartitionPruneStepCombine = 374, - T_PlanInvalItem = 375, - T_ExprState = 376, - T_IndexInfo = 377, - T_ExprContext = 378, - T_ReturnSetInfo = 379, - T_ProjectionInfo = 380, - T_JunkFilter = 381, - T_OnConflictSetState = 382, - T_MergeActionState = 383, - T_ResultRelInfo = 384, - T_EState = 385, - T_WindowFuncExprState = 386, - T_SetExprState = 387, - T_SubPlanState = 388, - T_DomainConstraintState = 389, - T_ResultState = 390, - T_ProjectSetState = 391, - T_ModifyTableState = 392, - T_AppendState = 393, - T_MergeAppendState = 394, - T_RecursiveUnionState = 395, - T_BitmapAndState = 396, - T_BitmapOrState = 397, - T_ScanState = 398, - T_SeqScanState = 399, - T_SampleScanState = 400, - T_IndexScanState = 401, - T_IndexOnlyScanState = 402, - T_BitmapIndexScanState = 403, - T_BitmapHeapScanState = 404, - T_TidScanState = 405, - T_TidRangeScanState = 406, - T_SubqueryScanState = 407, - T_FunctionScanState = 408, - T_ValuesScanState = 409, - T_TableFuncScanState = 410, - T_CteScanState = 411, - T_NamedTuplestoreScanState = 412, - T_WorkTableScanState = 413, - T_ForeignScanState = 414, - T_CustomScanState = 415, - T_JoinState = 416, - T_NestLoopState = 417, - T_MergeJoinState = 418, - T_HashJoinState = 419, - T_MaterialState = 420, - T_MemoizeState = 421, - T_SortState = 422, - T_IncrementalSortState = 423, - T_GroupState = 424, - T_AggState = 425, - T_WindowAggState = 426, - T_UniqueState = 427, - T_GatherState = 428, - T_GatherMergeState = 429, - T_HashState = 430, - T_SetOpState = 431, - T_LockRowsState = 432, - T_LimitState = 433, - T_IndexAmRoutine = 434, - T_TableAmRoutine = 435, - T_TsmRoutine = 436, - T_EventTriggerData = 437, - T_TriggerData = 438, - T_TupleTableSlot = 439, - T_FdwRoutine = 440, - T_Bitmapset = 441, - T_ExtensibleNode = 442, - T_ErrorSaveContext = 443, - T_IdentifySystemCmd = 444, - T_BaseBackupCmd = 445, - T_CreateReplicationSlotCmd = 446, - T_DropReplicationSlotCmd = 447, - T_AlterReplicationSlotCmd = 448, - T_StartReplicationCmd = 449, - T_ReadReplicationSlotCmd = 450, - T_TimeLineHistoryCmd = 451, - T_UploadManifestCmd = 452, - T_SupportRequestSimplify = 453, - T_SupportRequestSelectivity = 454, - T_SupportRequestCost = 455, - T_SupportRequestRows = 456, - T_SupportRequestIndexCondition = 457, - T_SupportRequestWFuncMonotonic = 458, - T_SupportRequestOptimizeWindowClause = 459, - T_Integer = 460, - T_Float = 461, - T_Boolean = 462, - T_String = 463, - T_BitString = 464, - T_ForeignKeyCacheInfo = 465, - T_IntList = 466, - T_OidList = 467, - T_XidList = 468, - T_AllocSetContext = 469, - T_GenerationContext = 470, - T_SlabContext = 471, - T_BumpContext = 472, - T_TIDBitmap = 473, - T_WindowObjectData = 474, + T_ReturningOption = 117, + T_ReturningClause = 118, + T_TriggerTransition = 119, + T_JsonOutput = 120, + T_JsonArgument = 121, + T_JsonFuncExpr = 122, + T_JsonTablePathSpec = 123, + T_JsonTable = 124, + T_JsonTableColumn = 125, + T_JsonKeyValue = 126, + T_JsonParseExpr = 127, + T_JsonScalarExpr = 128, + T_JsonSerializeExpr = 129, + T_JsonObjectConstructor = 130, + T_JsonArrayConstructor = 131, + T_JsonArrayQueryConstructor = 132, + T_JsonAggConstructor = 133, + T_JsonObjectAgg = 134, + T_JsonArrayAgg = 135, + T_RawStmt = 136, + T_InsertStmt = 137, + T_DeleteStmt = 138, + T_UpdateStmt = 139, + T_MergeStmt = 140, + T_SelectStmt = 141, + T_SetOperationStmt = 142, + T_ReturnStmt = 143, + T_PLAssignStmt = 144, + T_CreateSchemaStmt = 145, + T_AlterTableStmt = 146, + T_AlterTableCmd = 147, + T_ATAlterConstraint = 148, + T_ReplicaIdentityStmt = 149, + T_AlterCollationStmt = 150, + T_AlterDomainStmt = 151, + T_GrantStmt = 152, + T_ObjectWithArgs = 153, + T_AccessPriv = 154, + T_GrantRoleStmt = 155, + T_AlterDefaultPrivilegesStmt = 156, + T_CopyStmt = 157, + T_VariableSetStmt = 158, + T_VariableShowStmt = 159, + T_CreateStmt = 160, + T_Constraint = 161, + T_CreateTableSpaceStmt = 162, + T_DropTableSpaceStmt = 163, + T_AlterTableSpaceOptionsStmt = 164, + T_AlterTableMoveAllStmt = 165, + T_CreateExtensionStmt = 166, + T_AlterExtensionStmt = 167, + T_AlterExtensionContentsStmt = 168, + T_CreateFdwStmt = 169, + T_AlterFdwStmt = 170, + T_CreateForeignServerStmt = 171, + T_AlterForeignServerStmt = 172, + T_CreateForeignTableStmt = 173, + T_CreateUserMappingStmt = 174, + T_AlterUserMappingStmt = 175, + T_DropUserMappingStmt = 176, + T_ImportForeignSchemaStmt = 177, + T_CreatePolicyStmt = 178, + T_AlterPolicyStmt = 179, + T_CreateAmStmt = 180, + T_CreateTrigStmt = 181, + T_CreateEventTrigStmt = 182, + T_AlterEventTrigStmt = 183, + T_CreatePLangStmt = 184, + T_CreateRoleStmt = 185, + T_AlterRoleStmt = 186, + T_AlterRoleSetStmt = 187, + T_DropRoleStmt = 188, + T_CreateSeqStmt = 189, + T_AlterSeqStmt = 190, + T_DefineStmt = 191, + T_CreateDomainStmt = 192, + T_CreateOpClassStmt = 193, + T_CreateOpClassItem = 194, + T_CreateOpFamilyStmt = 195, + T_AlterOpFamilyStmt = 196, + T_DropStmt = 197, + T_TruncateStmt = 198, + T_CommentStmt = 199, + T_SecLabelStmt = 200, + T_DeclareCursorStmt = 201, + T_ClosePortalStmt = 202, + T_FetchStmt = 203, + T_IndexStmt = 204, + T_CreateStatsStmt = 205, + T_StatsElem = 206, + T_AlterStatsStmt = 207, + T_CreateFunctionStmt = 208, + T_FunctionParameter = 209, + T_AlterFunctionStmt = 210, + T_DoStmt = 211, + T_InlineCodeBlock = 212, + T_CallStmt = 213, + T_CallContext = 214, + T_RenameStmt = 215, + T_AlterObjectDependsStmt = 216, + T_AlterObjectSchemaStmt = 217, + T_AlterOwnerStmt = 218, + T_AlterOperatorStmt = 219, + T_AlterTypeStmt = 220, + T_RuleStmt = 221, + T_NotifyStmt = 222, + T_ListenStmt = 223, + T_UnlistenStmt = 224, + T_TransactionStmt = 225, + T_CompositeTypeStmt = 226, + T_CreateEnumStmt = 227, + T_CreateRangeStmt = 228, + T_AlterEnumStmt = 229, + T_ViewStmt = 230, + T_LoadStmt = 231, + T_CreatedbStmt = 232, + T_AlterDatabaseStmt = 233, + T_AlterDatabaseRefreshCollStmt = 234, + T_AlterDatabaseSetStmt = 235, + T_DropdbStmt = 236, + T_AlterSystemStmt = 237, + T_ClusterStmt = 238, + T_VacuumStmt = 239, + T_VacuumRelation = 240, + T_ExplainStmt = 241, + T_CreateTableAsStmt = 242, + T_RefreshMatViewStmt = 243, + T_CheckPointStmt = 244, + T_DiscardStmt = 245, + T_LockStmt = 246, + T_ConstraintsSetStmt = 247, + T_ReindexStmt = 248, + T_CreateConversionStmt = 249, + T_CreateCastStmt = 250, + T_CreateTransformStmt = 251, + T_PrepareStmt = 252, + T_ExecuteStmt = 253, + T_DeallocateStmt = 254, + T_DropOwnedStmt = 255, + T_ReassignOwnedStmt = 256, + T_AlterTSDictionaryStmt = 257, + T_AlterTSConfigurationStmt = 258, + T_PublicationTable = 259, + T_PublicationObjSpec = 260, + T_CreatePublicationStmt = 261, + T_AlterPublicationStmt = 262, + T_CreateSubscriptionStmt = 263, + T_AlterSubscriptionStmt = 264, + T_DropSubscriptionStmt = 265, + T_PlannerGlobal = 266, + T_PlannerInfo = 267, + T_RelOptInfo = 268, + T_IndexOptInfo = 269, + T_ForeignKeyOptInfo = 270, + T_StatisticExtInfo = 271, + T_JoinDomain = 272, + T_EquivalenceClass = 273, + T_EquivalenceMember = 274, + T_PathKey = 275, + T_GroupByOrdering = 276, + T_PathTarget = 277, + T_ParamPathInfo = 278, + T_Path = 279, + T_IndexPath = 280, + T_IndexClause = 281, + T_BitmapHeapPath = 282, + T_BitmapAndPath = 283, + T_BitmapOrPath = 284, + T_TidPath = 285, + T_TidRangePath = 286, + T_SubqueryScanPath = 287, + T_ForeignPath = 288, + T_CustomPath = 289, + T_AppendPath = 290, + T_MergeAppendPath = 291, + T_GroupResultPath = 292, + T_MaterialPath = 293, + T_MemoizePath = 294, + T_UniquePath = 295, + T_GatherPath = 296, + T_GatherMergePath = 297, + T_NestPath = 298, + T_MergePath = 299, + T_HashPath = 300, + T_ProjectionPath = 301, + T_ProjectSetPath = 302, + T_SortPath = 303, + T_IncrementalSortPath = 304, + T_GroupPath = 305, + T_UpperUniquePath = 306, + T_AggPath = 307, + T_GroupingSetData = 308, + T_RollupData = 309, + T_GroupingSetsPath = 310, + T_MinMaxAggPath = 311, + T_WindowAggPath = 312, + T_SetOpPath = 313, + T_RecursiveUnionPath = 314, + T_LockRowsPath = 315, + T_ModifyTablePath = 316, + T_LimitPath = 317, + T_RestrictInfo = 318, + T_PlaceHolderVar = 319, + T_SpecialJoinInfo = 320, + T_OuterJoinClauseInfo = 321, + T_AppendRelInfo = 322, + T_RowIdentityVarInfo = 323, + T_PlaceHolderInfo = 324, + T_MinMaxAggInfo = 325, + T_PlannerParamItem = 326, + T_AggInfo = 327, + T_AggTransInfo = 328, + T_UniqueRelInfo = 329, + T_PlannedStmt = 330, + T_Result = 331, + T_ProjectSet = 332, + T_ModifyTable = 333, + T_Append = 334, + T_MergeAppend = 335, + T_RecursiveUnion = 336, + T_BitmapAnd = 337, + T_BitmapOr = 338, + T_SeqScan = 339, + T_SampleScan = 340, + T_IndexScan = 341, + T_IndexOnlyScan = 342, + T_BitmapIndexScan = 343, + T_BitmapHeapScan = 344, + T_TidScan = 345, + T_TidRangeScan = 346, + T_SubqueryScan = 347, + T_FunctionScan = 348, + T_ValuesScan = 349, + T_TableFuncScan = 350, + T_CteScan = 351, + T_NamedTuplestoreScan = 352, + T_WorkTableScan = 353, + T_ForeignScan = 354, + T_CustomScan = 355, + T_NestLoop = 356, + T_NestLoopParam = 357, + T_MergeJoin = 358, + T_HashJoin = 359, + T_Material = 360, + T_Memoize = 361, + T_Sort = 362, + T_IncrementalSort = 363, + T_Group = 364, + T_Agg = 365, + T_WindowAgg = 366, + T_Unique = 367, + T_Gather = 368, + T_GatherMerge = 369, + T_Hash = 370, + T_SetOp = 371, + T_LockRows = 372, + T_Limit = 373, + T_PlanRowMark = 374, + T_PartitionPruneInfo = 375, + T_PartitionedRelPruneInfo = 376, + T_PartitionPruneStepOp = 377, + T_PartitionPruneStepCombine = 378, + T_PlanInvalItem = 379, + T_ExprState = 380, + T_IndexInfo = 381, + T_ExprContext = 382, + T_ReturnSetInfo = 383, + T_ProjectionInfo = 384, + T_JunkFilter = 385, + T_OnConflictSetState = 386, + T_MergeActionState = 387, + T_ResultRelInfo = 388, + T_EState = 389, + T_WindowFuncExprState = 390, + T_SetExprState = 391, + T_SubPlanState = 392, + T_DomainConstraintState = 393, + T_ResultState = 394, + T_ProjectSetState = 395, + T_ModifyTableState = 396, + T_AppendState = 397, + T_MergeAppendState = 398, + T_RecursiveUnionState = 399, + T_BitmapAndState = 400, + T_BitmapOrState = 401, + T_ScanState = 402, + T_SeqScanState = 403, + T_SampleScanState = 404, + T_IndexScanState = 405, + T_IndexOnlyScanState = 406, + T_BitmapIndexScanState = 407, + T_BitmapHeapScanState = 408, + T_TidScanState = 409, + T_TidRangeScanState = 410, + T_SubqueryScanState = 411, + T_FunctionScanState = 412, + T_ValuesScanState = 413, + T_TableFuncScanState = 414, + T_CteScanState = 415, + T_NamedTuplestoreScanState = 416, + T_WorkTableScanState = 417, + T_ForeignScanState = 418, + T_CustomScanState = 419, + T_JoinState = 420, + T_NestLoopState = 421, + T_MergeJoinState = 422, + T_HashJoinState = 423, + T_MaterialState = 424, + T_MemoizeState = 425, + T_SortState = 426, + T_IncrementalSortState = 427, + T_GroupState = 428, + T_AggState = 429, + T_WindowAggState = 430, + T_UniqueState = 431, + T_GatherState = 432, + T_GatherMergeState = 433, + T_HashState = 434, + T_SetOpState = 435, + T_LockRowsState = 436, + T_LimitState = 437, + T_IndexAmRoutine = 438, + T_TableAmRoutine = 439, + T_TsmRoutine = 440, + T_EventTriggerData = 441, + T_TriggerData = 442, + T_TupleTableSlot = 443, + T_FdwRoutine = 444, + T_Bitmapset = 445, + T_ExtensibleNode = 446, + T_ErrorSaveContext = 447, + T_IdentifySystemCmd = 448, + T_BaseBackupCmd = 449, + T_CreateReplicationSlotCmd = 450, + T_DropReplicationSlotCmd = 451, + T_AlterReplicationSlotCmd = 452, + T_StartReplicationCmd = 453, + T_ReadReplicationSlotCmd = 454, + T_TimeLineHistoryCmd = 455, + T_UploadManifestCmd = 456, + T_SupportRequestSimplify = 457, + T_SupportRequestSelectivity = 458, + T_SupportRequestCost = 459, + T_SupportRequestRows = 460, + T_SupportRequestIndexCondition = 461, + T_SupportRequestWFuncMonotonic = 462, + T_SupportRequestOptimizeWindowClause = 463, + T_SupportRequestModifyInPlace = 464, + T_Integer = 465, + T_Float = 466, + T_Boolean = 467, + T_String = 468, + T_BitString = 469, + T_ForeignKeyCacheInfo = 470, + T_IntList = 471, + T_OidList = 472, + T_XidList = 473, + T_AllocSetContext = 474, + T_GenerationContext = 475, + T_SlabContext = 476, + T_BumpContext = 477, + T_TIDBitmap = 478, + T_WindowObjectData = 479, diff --git a/src/include/parser/parsenodes.h b/src/include/parser/parsenodes.h index cf0ee5bcd..7608230b9 100644 --- a/src/include/parser/parsenodes.h +++ b/src/include/parser/parsenodes.h @@ -12,8 +12,8 @@ * identifying statement boundaries in multi-statement source strings. * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/parsenodes.h @@ -132,8 +132,13 @@ typedef struct Query * query identifier (can be set by plugins); ignored for equal, as it * might not be set; also not stored. This is the result of the query * jumble, hence ignored. + * + * We store this as a signed value as this is the form it's displayed to + * users in places such as EXPLAIN and pg_stat_statements. Primarily this + * is done due to lack of an SQL type to represent the full range of + * uint64. */ - uint64 queryId pg_node_attr(equal_ignore, query_jumble_ignore, read_write_ignore, read_as(0)); + int64 queryId pg_node_attr(equal_ignore, query_jumble_ignore, read_write_ignore, read_as(0)); /* do I set the command result tag? */ bool canSetTag pg_node_attr(query_jumble_ignore); @@ -165,6 +170,8 @@ typedef struct Query bool hasForUpdate pg_node_attr(query_jumble_ignore); /* rewriter has applied some RLS policy */ bool hasRowSecurity pg_node_attr(query_jumble_ignore); + /* parser has added an RTE_GROUP RTE */ + bool hasGroupRTE pg_node_attr(query_jumble_ignore); /* is a RETURN statement */ bool isReturn pg_node_attr(query_jumble_ignore); @@ -200,6 +207,15 @@ typedef struct Query OnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */ + /* + * The following three fields describe the contents of the RETURNING list + * for INSERT/UPDATE/DELETE/MERGE. returningOldAlias and returningNewAlias + * are the alias names for OLD and NEW, which may be user-supplied values, + * the defaults "old" and "new", or NULL (if the default "old"/"new" is + * already in use as the alias for some other relation). + */ + char *returningOldAlias pg_node_attr(query_jumble_ignore); + char *returningNewAlias pg_node_attr(query_jumble_ignore); List *returningList; /* return-values list (of TargetEntry) */ List *groupClause; /* a list of SortGroupClause's */ @@ -340,6 +356,14 @@ typedef struct A_Expr List *name; /* possibly-qualified name of operator */ Node *lexpr; /* left argument, or NULL if none */ Node *rexpr; /* right argument, or NULL if none */ + + /* + * If rexpr is a list of some kind, we separately track its starting and + * ending location; it's not the same as the starting and ending location + * of the token itself. + */ + ParseLoc rexpr_list_start; + ParseLoc rexpr_list_end; ParseLoc location; /* token location, or -1 if unknown */ } A_Expr; @@ -495,6 +519,8 @@ typedef struct A_ArrayExpr { NodeTag type; List *elements; /* array element expressions */ + ParseLoc list_start; /* start of the element list */ + ParseLoc list_end; /* end of the elements list */ ParseLoc location; /* token location, or -1 if unknown */ } A_ArrayExpr; @@ -731,7 +757,7 @@ typedef struct ColumnDef char *colname; /* name of column */ TypeName *typeName; /* type of column */ char *compression; /* compression method for column */ - int inhcount; /* number of times column is inherited */ + int16 inhcount; /* number of times column is inherited */ bool is_local; /* column has local (non-inherited) def'n */ bool is_not_null; /* NOT NULL constraint specified? */ bool is_from_type; /* column definition came from table type */ @@ -943,16 +969,6 @@ typedef struct PartitionRangeDatum } PartitionRangeDatum; /* - * PartitionDesc - used in reverted ALTER TABLE SPLIT PARTITION command - * - * Kept as a stub for nodetag ABI compatibility. - */ -typedef struct SinglePartitionSpec -{ - NodeTag type; -} SinglePartitionSpec; - -/* * PartitionCmd - info for ALTER TABLE/INDEX ATTACH/DETACH PARTITION commands */ typedef struct PartitionCmd @@ -1038,6 +1054,7 @@ typedef enum RTEKind RTE_RESULT, /* RTE represents an empty FROM clause; such * RTEs are added by the planner, they're not * present during parsing or rewriting */ + RTE_GROUP, /* the grouping step */ } RTEKind; typedef struct RangeTblEntry @@ -1053,8 +1070,13 @@ typedef struct RangeTblEntry */ /* user-written alias clause, if any */ Alias *alias pg_node_attr(query_jumble_ignore); - /* expanded reference names */ - Alias *eref pg_node_attr(query_jumble_ignore); + + /* + * Expanded reference names. This uses a custom query jumble function so + * that the table name is included in the computation, but not its list of + * columns. + */ + Alias *eref pg_node_attr(custom_query_jumble); RTEKind rtekind; /* see above */ @@ -1097,7 +1119,7 @@ typedef struct RangeTblEntry * tables to be invalidated if the underlying table is altered. */ /* OID of the relation */ - Oid relid; + Oid relid pg_node_attr(query_jumble_ignore); /* inheritance requested? */ bool inh; /* relation kind (see pg_class.relkind) */ @@ -1245,6 +1267,12 @@ typedef struct RangeTblEntry Cardinality enrtuples pg_node_attr(query_jumble_ignore); /* + * Fields valid for a GROUP RTE (else NIL): + */ + /* list of grouping expressions */ + List *groupexprs pg_node_attr(query_jumble_ignore); + + /* * Fields valid in all RTEs: */ /* was LATERAL specified? */ @@ -1444,6 +1472,7 @@ typedef struct SortGroupClause Index tleSortGroupRef; /* reference into targetlist */ Oid eqop; /* the equality operator ('=' op) */ Oid sortop; /* the ordering operator ('<' op), or 0 */ + bool reverse_sort; /* is sortop a "greater than" operator? */ bool nulls_first; /* do NULLs come before normal values? */ /* can eqop be implemented by hashing? */ bool hashable pg_node_attr(query_jumble_ignore); @@ -1732,6 +1761,41 @@ typedef struct MergeWhenClause } MergeWhenClause; /* + * ReturningOptionKind - + * Possible kinds of option in RETURNING WITH(...) list + * + * Currently, this is used only for specifying OLD/NEW aliases. + */ +typedef enum ReturningOptionKind +{ + RETURNING_OPTION_OLD, /* specify alias for OLD in RETURNING */ + RETURNING_OPTION_NEW, /* specify alias for NEW in RETURNING */ +} ReturningOptionKind; + +/* + * ReturningOption - + * An individual option in the RETURNING WITH(...) list + */ +typedef struct ReturningOption +{ + NodeTag type; + ReturningOptionKind option; /* specified option */ + char *value; /* option's value */ + ParseLoc location; /* token location, or -1 if unknown */ +} ReturningOption; + +/* + * ReturningClause - + * List of RETURNING expressions, together with any WITH(...) options + */ +typedef struct ReturningClause +{ + NodeTag type; + List *options; /* list of ReturningOption elements */ + List *exprs; /* list of expressions to return */ +} ReturningClause; + +/* * TriggerTransition - * representation of transition row or table naming clause * @@ -2048,7 +2112,7 @@ typedef struct InsertStmt List *cols; /* optional: names of the target columns */ Node *selectStmt; /* the source SELECT/VALUES, or NULL */ OnConflictClause *onConflictClause; /* ON CONFLICT clause */ - List *returningList; /* list of expressions to return */ + ReturningClause *returningClause; /* RETURNING clause */ WithClause *withClause; /* WITH clause */ OverridingKind override; /* OVERRIDING clause */ } InsertStmt; @@ -2063,7 +2127,7 @@ typedef struct DeleteStmt RangeVar *relation; /* relation to delete from */ List *usingClause; /* optional using clause for more tables */ Node *whereClause; /* qualifications */ - List *returningList; /* list of expressions to return */ + ReturningClause *returningClause; /* RETURNING clause */ WithClause *withClause; /* WITH clause */ } DeleteStmt; @@ -2078,7 +2142,7 @@ typedef struct UpdateStmt List *targetList; /* the target list (of ResTarget) */ Node *whereClause; /* qualifications */ List *fromClause; /* optional from clause for more tables */ - List *returningList; /* list of expressions to return */ + ReturningClause *returningClause; /* RETURNING clause */ WithClause *withClause; /* WITH clause */ } UpdateStmt; @@ -2093,7 +2157,7 @@ typedef struct MergeStmt Node *sourceRelation; /* source relation */ Node *joinCondition; /* join condition between source and target */ List *mergeWhenClauses; /* list of MergeWhenClause(es) */ - List *returningList; /* list of expressions to return */ + ReturningClause *returningClause; /* RETURNING clause */ WithClause *withClause; /* WITH clause */ } MergeStmt; @@ -2360,7 +2424,6 @@ typedef enum AlterTableType AT_SetNotNull, /* alter column set not null */ AT_SetExpression, /* alter column set expression */ AT_DropExpression, /* alter column drop expression */ - AT_CheckNotNull, /* check column is already marked not null */ AT_SetStatistics, /* alter column set statistics */ AT_SetOptions, /* alter column set ( options ) */ AT_ResetOptions, /* alter column reset ( options ) */ @@ -2421,13 +2484,6 @@ typedef enum AlterTableType AT_ReAddStatistics, /* internal to commands/tablecmds.c */ } AlterTableType; -typedef struct ReplicaIdentityStmt -{ - NodeTag type; - char identity_type; - char *name; -} ReplicaIdentityStmt; - typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ { NodeTag type; @@ -2444,6 +2500,28 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ bool recurse; /* exec-time recursion */ } AlterTableCmd; +/* Ad-hoc node for AT_AlterConstraint */ +typedef struct ATAlterConstraint +{ + NodeTag type; + char *conname; /* Constraint name */ + bool alterEnforceability; /* changing enforceability properties? */ + bool is_enforced; /* ENFORCED? */ + bool alterDeferrability; /* changing deferrability properties? */ + bool deferrable; /* DEFERRABLE? */ + bool initdeferred; /* INITIALLY DEFERRED? */ + bool alterInheritability; /* changing inheritability properties */ + bool noinherit; +} ATAlterConstraint; + +/* Ad-hoc node for AT_ReplicaIdentity */ +typedef struct ReplicaIdentityStmt +{ + NodeTag type; + char identity_type; + char *name; +} ReplicaIdentityStmt; + /* ---------------------- * Alter Collation @@ -2622,11 +2700,26 @@ typedef enum VariableSetKind typedef struct VariableSetStmt { + pg_node_attr(custom_query_jumble) + NodeTag type; VariableSetKind kind; - char *name; /* variable to be set */ - List *args; /* List of A_Const nodes */ - bool is_local; /* SET LOCAL? */ + /* variable to be set */ + char *name; + /* List of A_Const nodes */ + List *args; + + /* + * True if arguments should be accounted for in query jumbling. We use a + * separate flag rather than query_jumble_ignore on "args" as several + * grammar flavors of SET rely on a list of values that are parsed + * directly from the grammar's keywords. + */ + bool jumble_args; + /* SET LOCAL? */ + bool is_local; + /* token location, or -1 if unknown */ + ParseLoc location pg_node_attr(query_jumble_location); } VariableSetStmt; /* ---------------------- @@ -2643,10 +2736,10 @@ typedef struct VariableShowStmt * Create Table Statement * * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are - * intermixed in tableElts, and constraints is NIL. After parse analysis, - * tableElts contains just ColumnDefs, and constraints contains just - * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present - * implementation). + * intermixed in tableElts, and constraints and nnconstraints are NIL. After + * parse analysis, tableElts contains just ColumnDefs, nnconstraints contains + * Constraint nodes of CONSTR_NOTNULL type from various sources, and + * constraints contains just CONSTR_CHECK Constraint nodes. * ---------------------- */ @@ -2661,6 +2754,7 @@ typedef struct CreateStmt PartitionSpec *partspec; /* PARTITION BY clause */ TypeName *ofTypename; /* OF typename */ List *constraints; /* constraints (list of Constraint nodes) */ + List *nnconstraints; /* NOT NULL constraints (ditto) */ List *options; /* options from WITH clause */ OnCommitAction oncommit; /* what do we do at COMMIT? */ char *tablespacename; /* table space to use, or NULL */ @@ -2716,6 +2810,8 @@ typedef enum ConstrType /* types of constraints */ CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, + CONSTR_ATTR_ENFORCED, + CONSTR_ATTR_NOT_ENFORCED, } ConstrType; /* Foreign key action codes */ @@ -2737,6 +2833,7 @@ typedef struct Constraint char *conname; /* Constraint name, or NULL if unnamed */ bool deferrable; /* DEFERRABLE? */ bool initdeferred; /* INITIALLY DEFERRED? */ + bool is_enforced; /* enforced constraint? */ bool skip_validation; /* skip validation of existing rows? */ bool initially_valid; /* mark the new constraint as valid? */ bool is_no_inherit; /* is constraint non-inheritable? */ @@ -2745,11 +2842,11 @@ typedef struct Constraint char *cooked_expr; /* CHECK or DEFAULT expression, as * nodeToString representation */ char generated_when; /* ALWAYS or BY DEFAULT */ - int inhcount; /* initial inheritance count to apply, for - * "raw" NOT NULL constraints */ + char generated_kind; /* STORED or VIRTUAL */ bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ List *keys; /* String nodes naming referenced key * column(s); for UNIQUE/PK/NOT NULL */ + bool without_overlaps; /* WITHOUT OVERLAPS specified */ List *including; /* String nodes naming referenced nonkey * column(s); for UNIQUE/PK */ List *exclusions; /* list of (IndexElem, operator name) pairs; @@ -2766,6 +2863,8 @@ typedef struct Constraint RangeVar *pktable; /* Primary key table */ List *fk_attrs; /* Attributes of foreign key */ List *pk_attrs; /* Corresponding attrs in PK table */ + bool fk_with_period; /* Last attribute of FK uses PERIOD */ + bool pk_with_period; /* Last attribute of PK uses PERIOD */ char fk_matchtype; /* FULL, PARTIAL, SIMPLE */ char fk_upd_action; /* ON UPDATE action */ char fk_del_action; /* ON DELETE action */ @@ -3373,6 +3472,7 @@ typedef struct IndexStmt bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ bool primary; /* is index a primary key? */ bool isconstraint; /* is it for a pkey/unique constraint? */ + bool iswithoutoverlaps; /* is the constraint WITHOUT OVERLAPS? */ bool deferrable; /* is the constraint DEFERRABLE? */ bool initdeferred; /* is the constraint INITIALLY DEFERRED? */ bool transformed; /* true when transformIndexStmt is finished */ @@ -3460,6 +3560,7 @@ typedef struct FunctionParameter TypeName *argType; /* TypeName for parameter type */ FunctionParameterMode mode; /* IN/OUT/etc */ Node *defexpr; /* raw default expr, or NULL if not given */ + ParseLoc location; /* token location, or -1 if unknown */ } FunctionParameter; typedef struct AlterFunctionStmt diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index e412c438e..70a08f145 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -5,8 +5,8 @@ * * This is the external API for the raw lexing/parsing functions. * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parser.h diff --git a/src/include/parser/pg_class.h b/src/include/parser/pg_class.h index 7ebf4c439..82438dede 100644 --- a/src/include/parser/pg_class.h +++ b/src/include/parser/pg_class.h @@ -4,8 +4,8 @@ * definition of the "relation" system catalog (pg_class) * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_class.h @@ -22,7 +22,7 @@ #if 0 /* NOT_USED_IN_PGPOOL */ #include "catalog/genbki.h" -#include "catalog/pg_class_d.h" +#include "catalog/pg_class_d.h" /* IWYU pragma: export */ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO { @@ -63,6 +63,9 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat /* # of all-visible blocks (not always up-to-date) */ int32 relallvisible BKI_DEFAULT(0); + /* # of all-frozen blocks (not always up-to-date) */ + int32 relallfrozen BKI_DEFAULT(0); + /* OID of toast table; 0 if none */ Oid reltoastrelid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); diff --git a/src/include/parser/pg_config_manual.h b/src/include/parser/pg_config_manual.h index f522dc2a0..cbea7dc1d 100644 --- a/src/include/parser/pg_config_manual.h +++ b/src/include/parser/pg_config_manual.h @@ -6,8 +6,8 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pg_config_manual.h @@ -104,21 +104,6 @@ #define USE_FLOAT8_BYVAL 1 #endif -/* - * When we don't have native spinlocks, we use semaphores to simulate them. - * Decreasing this value reduces consumption of OS resources; increasing it - * may improve performance, but supplying a real spinlock implementation is - * probably far better. - */ -#define NUM_SPINLOCK_SEMAPHORES 128 - -/* - * When we have neither spinlocks nor atomic operations support we're - * implementing atomic operations on top of spinlock on top of semaphores. To - * be safe against atomic operations while holding a spinlock separate - * semaphores have to be used. - */ -#define NUM_ATOMICS_SEMAPHORES 64 /* * MAXPGPATH: standard size of a pathname buffer in PostgreSQL (hence, @@ -172,9 +157,8 @@ /* * USE_PREFETCH code should be compiled only if we have a way to implement * prefetching. (This is decoupled from USE_POSIX_FADVISE because there - * might in future be support for alternative low-level prefetch APIs. - * If you change this, you probably need to adjust the error message in - * check_effective_io_concurrency.) + * might in future be support for alternative low-level prefetch APIs, + * as well as platform-specific APIs defined elsewhere.) */ #ifdef USE_POSIX_FADVISE #define USE_PREFETCH @@ -316,10 +300,10 @@ /* * For cache-invalidation debugging, define DISCARD_CACHES_ENABLED to enable - * use of the debug_discard_caches GUC to aggressively flush syscache/relcache - * entries whenever it's possible to deliver invalidations. See - * AcceptInvalidationMessages() in src/backend/utils/cache/inval.c for - * details. + * use of the debug_discard_caches GUC to aggressively flush + * syscache/relcache/relsynccache entries whenever it's possible to deliver + * invalidations. See AcceptInvalidationMessages() in + * src/backend/utils/cache/inval.c for details. * * USE_ASSERT_CHECKING builds default to enabling this. It's possible to use * DISCARD_CACHES_ENABLED without a cassert build and the implied @@ -354,31 +338,31 @@ /* #define RECOVER_RELATION_BUILD_MEMORY 1 */ /* Force enable */ /* - * Define this to force all parse and plan trees to be passed through - * copyObject(), to facilitate catching errors and omissions in - * copyObject(). + * Define DEBUG_NODE_TESTS_ENABLED to enable use of the GUCs + * debug_copy_parse_plan_trees, debug_write_read_parse_plan_trees, and + * debug_raw_expression_coverage_test, to test coverage of node support + * functions in src/backend/nodes/. + * + * USE_ASSERT_CHECKING builds default to enabling this. */ -/* #define COPY_PARSE_PLAN_TREES */ +/* #define DEBUG_NODE_TESTS_ENABLED */ -/* - * Define this to force Bitmapset reallocation on each modification. Helps - * to find dangling pointers to Bitmapset's. - */ -/* #define REALLOCATE_BITMAPSETS */ +#if defined(USE_ASSERT_CHECKING) && !defined(DEBUG_NODE_TESTS_ENABLED) +#define DEBUG_NODE_TESTS_ENABLED +#endif /* - * Define this to force all parse and plan trees to be passed through - * outfuncs.c/readfuncs.c, to facilitate catching errors and omissions in - * those modules. + * Backwards compatibility for the older compile-time-only node-tests macros. */ -/* #define WRITE_READ_PARSE_PLAN_TREES */ +#if !defined(DEBUG_NODE_TESTS_ENABLED) && (defined(COPY_PARSE_PLAN_TREES) || defined(WRITE_READ_PARSE_PLAN_TREES) || defined(RAW_EXPRESSION_COVERAGE_TEST)) +#define DEBUG_NODE_TESTS_ENABLED +#endif /* - * Define this to force all raw parse trees for DML statements to be scanned - * by raw_expression_tree_walker(), to facilitate catching errors and - * omissions in that function. + * Define this to force Bitmapset reallocation on each modification. Helps + * to find dangling pointers to Bitmapset's. */ -/* #define RAW_EXPRESSION_COVERAGE_TEST */ +/* #define REALLOCATE_BITMAPSETS */ /* * Define this to force all raw parse trees for DML statements to be scanned @@ -399,12 +383,6 @@ /* #define WAL_DEBUG */ /* - * Enable tracing of resource consumption during sort operations; - * see also the trace_sort GUC var. For 8.1 this is enabled by default. - */ -#define TRACE_SORT 1 - -/* * Enable tracing of syncscan operations (see also the trace_syncscan GUC var). */ /* #define TRACE_SYNCSCAN */ diff --git a/src/include/parser/pg_list.h b/src/include/parser/pg_list.h index 4a63a466d..99f334b84 100644 --- a/src/include/parser/pg_list.h +++ b/src/include/parser/pg_list.h @@ -29,8 +29,8 @@ * always be so; be careful to use the appropriate list type for your data.) * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/pg_list.h @@ -493,7 +493,7 @@ for_each_cell_setup(const List *lst, const ListCell *initcell) for (ForEachState var##__state = {(lst), 0}; \ (var##__state.l != NIL && \ var##__state.i < var##__state.l->length && \ - (var = func(&var##__state.l->elements[var##__state.i]), true)); \ + (var = (type pointer) func(&var##__state.l->elements[var##__state.i]), true)); \ var##__state.i++) /* @@ -630,23 +630,23 @@ extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2, #define pg_nodiscard #endif -extern pg_nodiscard List *lappend(List *list, void *datum); -extern pg_nodiscard List *lappend_int(List *list, int datum); -extern pg_nodiscard List *lappend_oid(List *list, Oid datum); -extern pg_nodiscard List *lappend_xid(List *list, TransactionId datum); +pg_nodiscard extern List *lappend(List *list, void *datum); +pg_nodiscard extern List *lappend_int(List *list, int datum); +pg_nodiscard extern List *lappend_oid(List *list, Oid datum); +pg_nodiscard extern List *lappend_xid(List *list, TransactionId datum); -extern pg_nodiscard List *list_insert_nth(List *list, int pos, void *datum); -extern pg_nodiscard List *list_insert_nth_int(List *list, int pos, int datum); -extern pg_nodiscard List *list_insert_nth_oid(List *list, int pos, Oid datum); +pg_nodiscard extern List *list_insert_nth(List *list, int pos, void *datum); +pg_nodiscard extern List *list_insert_nth_int(List *list, int pos, int datum); +pg_nodiscard extern List *list_insert_nth_oid(List *list, int pos, Oid datum); -extern pg_nodiscard List *lcons(void *datum, List *list); -extern pg_nodiscard List *lcons_int(int datum, List *list); -extern pg_nodiscard List *lcons_oid(Oid datum, List *list); +pg_nodiscard extern List *lcons(void *datum, List *list); +pg_nodiscard extern List *lcons_int(int datum, List *list); +pg_nodiscard extern List *lcons_oid(Oid datum, List *list); -extern pg_nodiscard List *list_concat(List *list1, const List *list2); -extern pg_nodiscard List *list_concat_copy(const List *list1, const List *list2); +pg_nodiscard extern List *list_concat(List *list1, const List *list2); +pg_nodiscard extern List *list_concat_copy(const List *list1, const List *list2); -extern pg_nodiscard List *list_truncate(List *list, int new_size); +pg_nodiscard extern List *list_truncate(List *list, int new_size); extern bool list_member(const List *list, const void *datum); extern bool list_member_ptr(const List *list, const void *datum); @@ -654,15 +654,15 @@ extern bool list_member_int(const List *list, int datum); extern bool list_member_oid(const List *list, Oid datum); extern bool list_member_xid(const List *list, TransactionId datum); -extern pg_nodiscard List *list_delete(List *list, void *datum); -extern pg_nodiscard List *list_delete_ptr(List *list, void *datum); -extern pg_nodiscard List *list_delete_int(List *list, int datum); -extern pg_nodiscard List *list_delete_oid(List *list, Oid datum); -extern pg_nodiscard List *list_delete_first(List *list); -extern pg_nodiscard List *list_delete_last(List *list); -extern pg_nodiscard List *list_delete_first_n(List *list, int n); -extern pg_nodiscard List *list_delete_nth_cell(List *list, int n); -extern pg_nodiscard List *list_delete_cell(List *list, ListCell *cell); +pg_nodiscard extern List *list_delete(List *list, void *datum); +pg_nodiscard extern List *list_delete_ptr(List *list, void *datum); +pg_nodiscard extern List *list_delete_int(List *list, int datum); +pg_nodiscard extern List *list_delete_oid(List *list, Oid datum); +pg_nodiscard extern List *list_delete_first(List *list); +pg_nodiscard extern List *list_delete_last(List *list); +pg_nodiscard extern List *list_delete_first_n(List *list, int n); +pg_nodiscard extern List *list_delete_nth_cell(List *list, int n); +pg_nodiscard extern List *list_delete_cell(List *list, ListCell *cell); extern List *list_union(const List *list1, const List *list2); extern List *list_union_ptr(const List *list1, const List *list2); @@ -679,25 +679,25 @@ extern List *list_difference_ptr(const List *list1, const List *list2); extern List *list_difference_int(const List *list1, const List *list2); extern List *list_difference_oid(const List *list1, const List *list2); -extern pg_nodiscard List *list_append_unique(List *list, void *datum); -extern pg_nodiscard List *list_append_unique_ptr(List *list, void *datum); -extern pg_nodiscard List *list_append_unique_int(List *list, int datum); -extern pg_nodiscard List *list_append_unique_oid(List *list, Oid datum); +pg_nodiscard extern List *list_append_unique(List *list, void *datum); +pg_nodiscard extern List *list_append_unique_ptr(List *list, void *datum); +pg_nodiscard extern List *list_append_unique_int(List *list, int datum); +pg_nodiscard extern List *list_append_unique_oid(List *list, Oid datum); -extern pg_nodiscard List *list_concat_unique(List *list1, const List *list2); -extern pg_nodiscard List *list_concat_unique_ptr(List *list1, const List *list2); -extern pg_nodiscard List *list_concat_unique_int(List *list1, const List *list2); -extern pg_nodiscard List *list_concat_unique_oid(List *list1, const List *list2); +pg_nodiscard extern List *list_concat_unique(List *list1, const List *list2); +pg_nodiscard extern List *list_concat_unique_ptr(List *list1, const List *list2); +pg_nodiscard extern List *list_concat_unique_int(List *list1, const List *list2); +pg_nodiscard extern List *list_concat_unique_oid(List *list1, const List *list2); extern void list_deduplicate_oid(List *list); extern void list_free(List *list); extern void list_free_deep(List *list); -extern pg_nodiscard List *list_copy(const List *oldlist); -extern pg_nodiscard List *list_copy_head(const List *oldlist, int len); -extern pg_nodiscard List *list_copy_tail(const List *oldlist, int nskip); -extern pg_nodiscard List *list_copy_deep(const List *oldlist); +pg_nodiscard extern List *list_copy(const List *oldlist); +pg_nodiscard extern List *list_copy_head(const List *oldlist, int len); +pg_nodiscard extern List *list_copy_tail(const List *oldlist, int nskip); +pg_nodiscard extern List *list_copy_deep(const List *oldlist); typedef int (*list_sort_comparator) (const ListCell *a, const ListCell *b); extern void list_sort(List *list, list_sort_comparator cmp); diff --git a/src/include/parser/pg_trigger.h b/src/include/parser/pg_trigger.h index 745fe049a..daec329dd 100644 --- a/src/include/parser/pg_trigger.h +++ b/src/include/parser/pg_trigger.h @@ -4,8 +4,8 @@ * definition of the "trigger" system catalog (pg_trigger) * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_trigger.h @@ -21,7 +21,7 @@ #if 0 #include "catalog/genbki.h" -#include "catalog/pg_trigger_d.h" +#include "catalog/pg_trigger_d.h" /* IWYU pragma: export */ /* ---------------- * pg_trigger definition. cpp turns this into diff --git a/src/include/parser/pg_wchar.h b/src/include/parser/pg_wchar.h index 59582d1ff..8612afd07 100644 --- a/src/include/parser/pg_wchar.h +++ b/src/include/parser/pg_wchar.h @@ -3,8 +3,8 @@ * pg_wchar.h * multibyte-character support * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/mb/pg_wchar.h @@ -663,7 +663,10 @@ extern int pg_valid_server_encoding_id(int encoding); * (in addition to the ones just above). The constant tables declared * earlier in this file are also available from libpgcommon. */ +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); @@ -768,9 +771,9 @@ extern void check_encoding_conversion_args(int src_encoding, int expected_src_encoding, int expected_dest_encoding); -extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn(); -extern void report_untranslatable_char(int src_encoding, int dest_encoding, - const char *mbstr, int len) pg_attribute_noreturn(); +pg_noreturn extern void report_invalid_encoding(int encoding, const char *mbstr, int len); +pg_noreturn extern void report_untranslatable_char(int src_encoding, int dest_encoding, + const char *mbstr, int len); extern int local2local(const unsigned char *l, unsigned char *p, int len, int src_encoding, int dest_encoding, diff --git a/src/include/parser/pool_parser.h b/src/include/parser/pool_parser.h index f10a9f8da..6ea19070f 100644 --- a/src/include/parser/pool_parser.h +++ b/src/include/parser/pool_parser.h @@ -66,6 +66,26 @@ typedef unsigned int Index; */ #define endof(array) (&(array)[lengthof(array)]) +/* + * pg_noreturn corresponds to the C11 noreturn/_Noreturn function specifier. + * We can't use the standard name "noreturn" because some third-party code + * uses __attribute__((noreturn)) in headers, which would get confused if + * "noreturn" is defined to "_Noreturn", as is done by <stdnoreturn.h>. + * + * In a declaration, function specifiers go before the function name. The + * common style is to put them before the return type. (The MSVC fallback has + * the same requirement. The GCC fallback is more flexible.) + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define pg_noreturn _Noreturn +#elif defined(__GNUC__) || defined(__SUNPRO_C) +#define pg_noreturn __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define pg_noreturn __declspec(noreturn) +#else +#define pg_noreturn +#endif + /* GCC and XLC support format attributes */ #if defined(__GNUC__) || defined(__IBMC__) #define pg_attribute_format_arg(a) __attribute__((format_arg(a))) @@ -78,16 +98,13 @@ typedef unsigned int Index; /* GCC, Sunpro and XLC support aligned, packed and noreturn */ #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__) #define pg_attribute_aligned(a) __attribute__((aligned(a))) -#define pg_attribute_noreturn() __attribute__((noreturn)) #define pg_attribute_packed() __attribute__((packed)) -#define HAVE_PG_ATTRIBUTE_NORETURN 1 #else /* * NB: aligned and packed are not given default definitions because they * affect code functionality; they *must* be implemented by the compiler * if they are to be used. */ -#define pg_attribute_noreturn() #endif /* diff --git a/src/include/parser/primnodes.h b/src/include/parser/primnodes.h index 09be5529b..6fce8be0c 100644 --- a/src/include/parser/primnodes.h +++ b/src/include/parser/primnodes.h @@ -6,8 +6,8 @@ * Currently, these are mostly nodes for executable expressions * and join trees. * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/primnodes.h @@ -171,8 +171,8 @@ typedef struct TableFunc * For CREATE MATERIALIZED VIEW, viewQuery is the parsed-but-not-rewritten * SELECT Query for the view; otherwise it's NULL. This is irrelevant in * the query jumbling as CreateTableAsStmt already includes a reference to - * its own Query, so ignore it. (Although it's actually Query*, we declare - * it as Node* to avoid a forward reference.) + * its own Query, so ignore it. (We declare it as struct Query* to avoid a + * forward reference.) */ typedef struct IntoClause { @@ -185,7 +185,7 @@ typedef struct IntoClause OnCommitAction onCommit; /* what do we do at COMMIT? */ char *tableSpaceName; /* table space to use, or NULL */ /* materialized view's SELECT query */ - Node *viewQuery pg_node_attr(query_jumble_ignore); + struct Query *viewQuery pg_node_attr(query_jumble_ignore); bool skipData; /* true for WITH NO DATA */ } IntoClause; @@ -242,6 +242,11 @@ typedef struct Expr * Note that it affects the meaning of all of varno, varnullingrels, and * varnosyn, all of which refer to the range table of that query level. * + * varreturningtype is used for Vars that refer to the target relation in the + * RETURNING list of data-modifying queries. The default behavior is to + * return old values for DELETE and new values for INSERT and UPDATE, but it + * is also possible to explicitly request old or new values. + * * In the parser, varnosyn and varattnosyn are either identical to * varno/varattno, or they specify the column's position in an aliased JOIN * RTE that hides the semantic referent RTE's refname. This is a syntactic @@ -263,6 +268,14 @@ typedef struct Expr #define PRS2_OLD_VARNO 1 #define PRS2_NEW_VARNO 2 +/* Returning behavior for Vars in RETURNING list */ +typedef enum VarReturningType +{ + VAR_RETURNING_DEFAULT, /* return OLD for DELETE, else return NEW */ + VAR_RETURNING_OLD, /* return OLD for DELETE/UPDATE, else NULL */ + VAR_RETURNING_NEW, /* return NEW for INSERT/UPDATE, else NULL */ +} VarReturningType; + typedef struct Var { Expr xpr; @@ -298,6 +311,9 @@ typedef struct Var */ Index varlevelsup; + /* returning type of this var (see above) */ + VarReturningType varreturningtype; + /* * varnosyn/varattnosyn are ignored for equality, because Vars with * different syntactic identifiers are semantically the same as long as @@ -391,14 +407,16 @@ typedef enum ParamKind typedef struct Param { + pg_node_attr(custom_query_jumble) + Expr xpr; ParamKind paramkind; /* kind of parameter. See above */ int paramid; /* numeric ID for parameter */ Oid paramtype; /* pg_type OID of parameter's datatype */ /* typmod value, if known */ - int32 paramtypmod pg_node_attr(query_jumble_ignore); + int32 paramtypmod; /* OID of collation, or InvalidOid if none */ - Oid paramcollid pg_node_attr(query_jumble_ignore); + Oid paramcollid; /* token location, or -1 if unknown */ ParseLoc location; } Param; @@ -1396,9 +1414,13 @@ typedef struct ArrayExpr /* common type of array elements */ Oid element_typeid pg_node_attr(query_jumble_ignore); /* the array elements or sub-arrays */ - List *elements; + List *elements pg_node_attr(query_jumble_squash); /* true if elements are sub-arrays */ bool multidims pg_node_attr(query_jumble_ignore); + /* location of the start of the elements list */ + ParseLoc list_start; + /* location of the end of the elements list */ + ParseLoc list_end; /* token location, or -1 if unknown */ ParseLoc location; } ArrayExpr; @@ -1455,6 +1477,34 @@ typedef struct RowExpr } RowExpr; /* + * CompareType - fundamental semantics of certain operators + * + * These enum symbols represent the fundamental semantics of certain operators + * that the system needs to have some hardcoded knowledge about. (For + * example, RowCompareExpr needs to know which operators can be determined to + * act like =, <>, <, etc.) Index access methods map (some of) strategy + * numbers to these values so that the system can know about the meaning of + * (some of) the operators without needing hardcoded knowledge of index AM's + * strategy numbering. + * + * XXX Currently, this mapping is not fully developed and most values are + * chosen to match btree strategy numbers, which is not going to work very + * well for other access methods. + */ +typedef enum CompareType +{ + COMPARE_INVALID = 0, + COMPARE_LT = 1, /* BTLessStrategyNumber */ + COMPARE_LE = 2, /* BTLessEqualStrategyNumber */ + COMPARE_EQ = 3, /* BTEqualStrategyNumber */ + COMPARE_GE = 4, /* BTGreaterEqualStrategyNumber */ + COMPARE_GT = 5, /* BTGreaterStrategyNumber */ + COMPARE_NE = 6, /* no such btree strategy */ + COMPARE_OVERLAP, + COMPARE_CONTAINED_BY, +} CompareType; + +/* * RowCompareExpr - row-wise comparison, such as (a, b) <= (1, 2) * * We support row comparison for any operator that can be determined to @@ -1465,26 +1515,14 @@ typedef struct RowExpr * * A RowCompareExpr node is only generated for the < <= > >= cases; * the = and <> cases are translated to simple AND or OR combinations - * of the pairwise comparisons. However, we include = and <> in the - * RowCompareType enum for the convenience of parser logic. + * of the pairwise comparisons. */ -typedef enum RowCompareType -{ - /* Values of this enum are chosen to match btree strategy numbers */ - ROWCOMPARE_LT = 1, /* BTLessStrategyNumber */ - ROWCOMPARE_LE = 2, /* BTLessEqualStrategyNumber */ - ROWCOMPARE_EQ = 3, /* BTEqualStrategyNumber */ - ROWCOMPARE_GE = 4, /* BTGreaterEqualStrategyNumber */ - ROWCOMPARE_GT = 5, /* BTGreaterStrategyNumber */ - ROWCOMPARE_NE = 6, /* no such btree strategy */ -} RowCompareType; - typedef struct RowCompareExpr { Expr xpr; /* LT LE GE or GT, never EQ or NE */ - RowCompareType rctype; + CompareType cmptype; /* OID list of pairwise comparison ops */ List *opnos pg_node_attr(query_jumble_ignore); /* OID list of containing operator families */ @@ -1688,15 +1726,19 @@ typedef struct JsonReturning * JsonValueExpr - * representation of JSON value expression (expr [FORMAT JsonFormat]) * - * The actual value is obtained by evaluating formatted_expr. raw_expr is - * only there for displaying the original user-written expression and is not - * evaluated by ExecInterpExpr() and eval_const_expressions_mutator(). + * raw_expr is the user-specified value, while formatted_expr is the value + * obtained by coercing raw_expr to the type required by either the FORMAT + * clause or an enclosing node's RETURNING clause. + * + * When deparsing a JsonValueExpr, get_rule_expr() prints raw_expr. However, + * during the evaluation of a JsonValueExpr, the value of formatted_expr + * takes precedence over that of raw_expr. */ typedef struct JsonValueExpr { NodeTag type; - Expr *raw_expr; /* raw expression */ - Expr *formatted_expr; /* formatted expression */ + Expr *raw_expr; /* user-specified expression */ + Expr *formatted_expr; /* coerced formatted expression */ JsonFormat *format; /* FORMAT clause, if specified */ } JsonValueExpr; @@ -2143,6 +2185,30 @@ typedef struct InferenceElem Oid inferopclass; /* OID of att opclass, or InvalidOid */ } InferenceElem; +/* + * ReturningExpr - return OLD/NEW.(expression) in RETURNING list + * + * This is used when updating an auto-updatable view and returning a view + * column that is not simply a Var referring to the base relation. In such + * cases, OLD/NEW.viewcol can expand to an arbitrary expression, but the + * result is required to be NULL if the OLD/NEW row doesn't exist. To handle + * this, the rewriter wraps the expanded expression in a ReturningExpr, which + * is equivalent to "CASE WHEN (OLD/NEW row exists) THEN (expr) ELSE NULL". + * + * A similar situation can arise when rewriting the RETURNING clause of a + * rule, which may also contain arbitrary expressions. + * + * ReturningExpr nodes never appear in a parsed Query --- they are only ever + * inserted by the rewriter and the planner. + */ +typedef struct ReturningExpr +{ + Expr xpr; + int retlevelsup; /* > 0 if it belongs to outer query */ + bool retold; /* true for OLD, false for NEW */ + Expr *retexpr; /* expression to be returned */ +} ReturningExpr; + /*-------------------- * TargetEntry - * a target entry (used in query target lists) diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h index 8c78b0a57..69deaeb48 100644 --- a/src/include/parser/scanner.h +++ b/src/include/parser/scanner.h @@ -8,8 +8,8 @@ * higher-level API provided by parser.h. * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scanner.h @@ -148,6 +148,6 @@ extern void setup_scanner_errposition_callback(ScannerCallbackState *scbstate, core_yyscan_t yyscanner, int location); extern void cancel_scanner_errposition_callback(ScannerCallbackState *scbstate); -extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn(); +pg_noreturn extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner); #endif /* SCANNER_H */ diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h index 319b12800..ef5e618be 100644 --- a/src/include/parser/scansup.h +++ b/src/include/parser/scansup.h @@ -3,8 +3,8 @@ * scansup.h * scanner support routines used by the core lexer * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scansup.h diff --git a/src/include/parser/stringinfo.h b/src/include/parser/stringinfo.h index 16515b0b1..1897c96bb 100644 --- a/src/include/parser/stringinfo.h +++ b/src/include/parser/stringinfo.h @@ -8,8 +8,8 @@ * (null-terminated text) or arbitrary binary data. All storage is allocated * with palloc() (falling back to malloc in frontend code). * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/lib/stringinfo.h @@ -104,11 +104,15 @@ typedef StringInfoData *StringInfo; /*------------------------ - * There are four ways to create a StringInfo object initially: + * There are six ways to create a StringInfo object initially: * * StringInfo stringptr = makeStringInfo(); * Both the StringInfoData and the data buffer are palloc'd. * + * StringInfo stringptr = makeStringInfoExt(initsize); + * Same as makeStringInfo except the data buffer is allocated + * with size 'initsize'. + * * StringInfoData string; * initStringInfo(&string); * The data buffer is palloc'd but the StringInfoData is just local. @@ -116,6 +120,11 @@ typedef StringInfoData *StringInfo; * only live as long as the current routine. * * StringInfoData string; + * initStringInfoExt(&string, initsize); + * Same as initStringInfo except the data buffer is allocated + * with size 'initsize'. + * + * StringInfoData string; * initReadOnlyStringInfo(&string, existingbuf, len); * The StringInfoData's data field is set to point directly to the * existing buffer and the StringInfoData's len is set to the given len. @@ -149,6 +158,8 @@ typedef StringInfoData *StringInfo; *------------------------- */ +#define STRINGINFO_DEFAULT_SIZE 1024 /* default initial allocation size */ + /*------------------------ * makeStringInfo * Create an empty 'StringInfoData' & return a pointer to it. @@ -156,6 +167,14 @@ typedef StringInfoData *StringInfo; extern StringInfo makeStringInfo(void); /*------------------------ + * makeStringInfoExt + * Create an empty 'StringInfoData' & return a pointer to it. + * The data buffer is allocated with size 'initsize'. + * The valid range for 'initsize' is 1 to MaxAllocSize. + */ +extern StringInfo makeStringInfoExt(int initsize); + +/*------------------------ * initStringInfo * Initialize a StringInfoData struct (with previously undefined contents) * to describe an empty string. @@ -163,6 +182,14 @@ extern StringInfo makeStringInfo(void); extern void initStringInfo(StringInfo str); /*------------------------ + * initStringInfoExt + * Initialize a StringInfoData struct (with previously undefined contents) to + * describe an empty string. The data buffer is allocated with size + * 'initsize'. The valid range for 'initsize' is 1 to MaxAllocSize. + */ +extern void initStringInfoExt(StringInfo str, int initsize); + +/*------------------------ * initReadOnlyStringInfo * Initialize a StringInfoData struct from an existing string without copying * the string. The caller is responsible for ensuring the given string diff --git a/src/include/parser/unicode_east_asian_fw_table.h b/src/include/parser/unicode_east_asian_fw_table.h new file mode 100644 index 000000000..db8bd0ad8 --- /dev/null +++ b/src/include/parser/unicode_east_asian_fw_table.h @@ -0,0 +1,126 @@ +/* generated by src/common/unicode/generate-unicode_east_asian_fw_table.pl, do not edit */ + +static const struct mbinterval east_asian_fw[] = { + {0x1100, 0x115F}, + {0x231A, 0x231B}, + {0x2329, 0x232A}, + {0x23E9, 0x23EC}, + {0x23F0, 0x23F0}, + {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, + {0x2614, 0x2615}, + {0x2630, 0x2637}, + {0x2648, 0x2653}, + {0x267F, 0x267F}, + {0x268A, 0x268F}, + {0x2693, 0x2693}, + {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, + {0x26BD, 0x26BE}, + {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, + {0x26D4, 0x26D4}, + {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, + {0x26F5, 0x26F5}, + {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, + {0x2705, 0x2705}, + {0x270A, 0x270B}, + {0x2728, 0x2728}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2795, 0x2797}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x2E80, 0x2E99}, + {0x2E9B, 0x2EF3}, + {0x2F00, 0x2FD5}, + {0x2FF0, 0x303E}, + {0x3041, 0x3096}, + {0x3099, 0x30FF}, + {0x3105, 0x312F}, + {0x3131, 0x318E}, + {0x3190, 0x31E5}, + {0x31EF, 0x321E}, + {0x3220, 0x3247}, + {0x3250, 0xA48C}, + {0xA490, 0xA4C6}, + {0xA960, 0xA97C}, + {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, + {0xFE10, 0xFE19}, + {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, + {0xFE68, 0xFE6B}, + {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, + {0x16FE0, 0x16FE4}, + {0x16FF0, 0x16FF1}, + {0x17000, 0x187F7}, + {0x18800, 0x18CD5}, + {0x18CFF, 0x18D08}, + {0x1AFF0, 0x1AFF3}, + {0x1AFF5, 0x1AFFB}, + {0x1AFFD, 0x1AFFE}, + {0x1B000, 0x1B122}, + {0x1B132, 0x1B132}, + {0x1B150, 0x1B152}, + {0x1B155, 0x1B155}, + {0x1B164, 0x1B167}, + {0x1B170, 0x1B2FB}, + {0x1D300, 0x1D356}, + {0x1D360, 0x1D376}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F200, 0x1F202}, + {0x1F210, 0x1F23B}, + {0x1F240, 0x1F248}, + {0x1F250, 0x1F251}, + {0x1F260, 0x1F265}, + {0x1F300, 0x1F320}, + {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F393}, + {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, + {0x1F440, 0x1F440}, + {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, + {0x1F595, 0x1F596}, + {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D2}, + {0x1F6D5, 0x1F6D7}, + {0x1F6DC, 0x1F6DF}, + {0x1F6EB, 0x1F6EC}, + {0x1F6F4, 0x1F6FC}, + {0x1F7E0, 0x1F7EB}, + {0x1F7F0, 0x1F7F0}, + {0x1F90C, 0x1F93A}, + {0x1F93C, 0x1F945}, + {0x1F947, 0x1F9FF}, + {0x1FA70, 0x1FA7C}, + {0x1FA80, 0x1FA89}, + {0x1FA8F, 0x1FAC6}, + {0x1FACE, 0x1FADC}, + {0x1FADF, 0x1FAE9}, + {0x1FAF0, 0x1FAF8}, + {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD}, +}; diff --git a/src/include/parser/unicode_nonspacing_table.h b/src/include/parser/unicode_nonspacing_table.h new file mode 100644 index 000000000..d67f5b3f2 --- /dev/null +++ b/src/include/parser/unicode_nonspacing_table.h @@ -0,0 +1,338 @@ +/* generated by src/common/unicode/generate-unicode_nonspacing_table.pl, do not edit */ + +static const struct mbinterval nonspacing[] = { + {0x00AD, 0x00AD}, + {0x0300, 0x036F}, + {0x0483, 0x0489}, + {0x0591, 0x05BD}, + {0x05BF, 0x05BF}, + {0x05C1, 0x05C2}, + {0x05C4, 0x05C5}, + {0x05C7, 0x05C7}, + {0x0600, 0x0605}, + {0x0610, 0x061A}, + {0x061C, 0x061C}, + {0x064B, 0x065F}, + {0x0670, 0x0670}, + {0x06D6, 0x06DD}, + {0x06DF, 0x06E4}, + {0x06E7, 0x06E8}, + {0x06EA, 0x06ED}, + {0x070F, 0x070F}, + {0x0711, 0x0711}, + {0x0730, 0x074A}, + {0x07A6, 0x07B0}, + {0x07EB, 0x07F3}, + {0x07FD, 0x07FD}, + {0x0816, 0x0819}, + {0x081B, 0x0823}, + {0x0825, 0x0827}, + {0x0829, 0x082D}, + {0x0859, 0x085B}, + {0x0890, 0x089F}, + {0x08CA, 0x0902}, + {0x093A, 0x093A}, + {0x093C, 0x093C}, + {0x0941, 0x0948}, + {0x094D, 0x094D}, + {0x0951, 0x0957}, + {0x0962, 0x0963}, + {0x0981, 0x0981}, + {0x09BC, 0x09BC}, + {0x09C1, 0x09C4}, + {0x09CD, 0x09CD}, + {0x09E2, 0x09E3}, + {0x09FE, 0x0A02}, + {0x0A3C, 0x0A3C}, + {0x0A41, 0x0A51}, + {0x0A70, 0x0A71}, + {0x0A75, 0x0A75}, + {0x0A81, 0x0A82}, + {0x0ABC, 0x0ABC}, + {0x0AC1, 0x0AC8}, + {0x0ACD, 0x0ACD}, + {0x0AE2, 0x0AE3}, + {0x0AFA, 0x0B01}, + {0x0B3C, 0x0B3C}, + {0x0B3F, 0x0B3F}, + {0x0B41, 0x0B44}, + {0x0B4D, 0x0B56}, + {0x0B62, 0x0B63}, + {0x0B82, 0x0B82}, + {0x0BC0, 0x0BC0}, + {0x0BCD, 0x0BCD}, + {0x0C00, 0x0C00}, + {0x0C04, 0x0C04}, + {0x0C3C, 0x0C3C}, + {0x0C3E, 0x0C40}, + {0x0C46, 0x0C56}, + {0x0C62, 0x0C63}, + {0x0C81, 0x0C81}, + {0x0CBC, 0x0CBC}, + {0x0CBF, 0x0CBF}, + {0x0CC6, 0x0CC6}, + {0x0CCC, 0x0CCD}, + {0x0CE2, 0x0CE3}, + {0x0D00, 0x0D01}, + {0x0D3B, 0x0D3C}, + {0x0D41, 0x0D44}, + {0x0D4D, 0x0D4D}, + {0x0D62, 0x0D63}, + {0x0D81, 0x0D81}, + {0x0DCA, 0x0DCA}, + {0x0DD2, 0x0DD6}, + {0x0E31, 0x0E31}, + {0x0E34, 0x0E3A}, + {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, + {0x0EB4, 0x0EBC}, + {0x0EC8, 0x0ECE}, + {0x0F18, 0x0F19}, + {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, + {0x0F71, 0x0F7E}, + {0x0F80, 0x0F84}, + {0x0F86, 0x0F87}, + {0x0F8D, 0x0FBC}, + {0x0FC6, 0x0FC6}, + {0x102D, 0x1030}, + {0x1032, 0x1037}, + {0x1039, 0x103A}, + {0x103D, 0x103E}, + {0x1058, 0x1059}, + {0x105E, 0x1060}, + {0x1071, 0x1074}, + {0x1082, 0x1082}, + {0x1085, 0x1086}, + {0x108D, 0x108D}, + {0x109D, 0x109D}, + {0x135D, 0x135F}, + {0x1712, 0x1714}, + {0x1732, 0x1733}, + {0x1752, 0x1753}, + {0x1772, 0x1773}, + {0x17B4, 0x17B5}, + {0x17B7, 0x17BD}, + {0x17C6, 0x17C6}, + {0x17C9, 0x17D3}, + {0x17DD, 0x17DD}, + {0x180B, 0x180F}, + {0x1885, 0x1886}, + {0x18A9, 0x18A9}, + {0x1920, 0x1922}, + {0x1927, 0x1928}, + {0x1932, 0x1932}, + {0x1939, 0x193B}, + {0x1A17, 0x1A18}, + {0x1A1B, 0x1A1B}, + {0x1A56, 0x1A56}, + {0x1A58, 0x1A60}, + {0x1A62, 0x1A62}, + {0x1A65, 0x1A6C}, + {0x1A73, 0x1A7F}, + {0x1AB0, 0x1B03}, + {0x1B34, 0x1B34}, + {0x1B36, 0x1B3A}, + {0x1B3C, 0x1B3C}, + {0x1B42, 0x1B42}, + {0x1B6B, 0x1B73}, + {0x1B80, 0x1B81}, + {0x1BA2, 0x1BA5}, + {0x1BA8, 0x1BA9}, + {0x1BAB, 0x1BAD}, + {0x1BE6, 0x1BE6}, + {0x1BE8, 0x1BE9}, + {0x1BED, 0x1BED}, + {0x1BEF, 0x1BF1}, + {0x1C2C, 0x1C33}, + {0x1C36, 0x1C37}, + {0x1CD0, 0x1CD2}, + {0x1CD4, 0x1CE0}, + {0x1CE2, 0x1CE8}, + {0x1CED, 0x1CED}, + {0x1CF4, 0x1CF4}, + {0x1CF8, 0x1CF9}, + {0x1DC0, 0x1DFF}, + {0x200B, 0x200F}, + {0x202A, 0x202E}, + {0x2060, 0x206F}, + {0x20D0, 0x20F0}, + {0x2CEF, 0x2CF1}, + {0x2D7F, 0x2D7F}, + {0x2DE0, 0x2DFF}, + {0x302A, 0x302D}, + {0x3099, 0x309A}, + {0xA66F, 0xA672}, + {0xA674, 0xA67D}, + {0xA69E, 0xA69F}, + {0xA6F0, 0xA6F1}, + {0xA802, 0xA802}, + {0xA806, 0xA806}, + {0xA80B, 0xA80B}, + {0xA825, 0xA826}, + {0xA82C, 0xA82C}, + {0xA8C4, 0xA8C5}, + {0xA8E0, 0xA8F1}, + {0xA8FF, 0xA8FF}, + {0xA926, 0xA92D}, + {0xA947, 0xA951}, + {0xA980, 0xA982}, + {0xA9B3, 0xA9B3}, + {0xA9B6, 0xA9B9}, + {0xA9BC, 0xA9BD}, + {0xA9E5, 0xA9E5}, + {0xAA29, 0xAA2E}, + {0xAA31, 0xAA32}, + {0xAA35, 0xAA36}, + {0xAA43, 0xAA43}, + {0xAA4C, 0xAA4C}, + {0xAA7C, 0xAA7C}, + {0xAAB0, 0xAAB0}, + {0xAAB2, 0xAAB4}, + {0xAAB7, 0xAAB8}, + {0xAABE, 0xAABF}, + {0xAAC1, 0xAAC1}, + {0xAAEC, 0xAAED}, + {0xAAF6, 0xAAF6}, + {0xABE5, 0xABE5}, + {0xABE8, 0xABE8}, + {0xABED, 0xABED}, + {0xFB1E, 0xFB1E}, + {0xFE00, 0xFE0F}, + {0xFE20, 0xFE2F}, + {0xFEFF, 0xFEFF}, + {0xFFF9, 0xFFFB}, + {0x101FD, 0x101FD}, + {0x102E0, 0x102E0}, + {0x10376, 0x1037A}, + {0x10A01, 0x10A0F}, + {0x10A38, 0x10A3F}, + {0x10AE5, 0x10AE6}, + {0x10D24, 0x10D27}, + {0x10D69, 0x10D6D}, + {0x10EAB, 0x10EAC}, + {0x10EFC, 0x10EFF}, + {0x10F46, 0x10F50}, + {0x10F82, 0x10F85}, + {0x11001, 0x11001}, + {0x11038, 0x11046}, + {0x11070, 0x11070}, + {0x11073, 0x11074}, + {0x1107F, 0x11081}, + {0x110B3, 0x110B6}, + {0x110B9, 0x110BA}, + {0x110BD, 0x110BD}, + {0x110C2, 0x110CD}, + {0x11100, 0x11102}, + {0x11127, 0x1112B}, + {0x1112D, 0x11134}, + {0x11173, 0x11173}, + {0x11180, 0x11181}, + {0x111B6, 0x111BE}, + {0x111C9, 0x111CC}, + {0x111CF, 0x111CF}, + {0x1122F, 0x11231}, + {0x11234, 0x11234}, + {0x11236, 0x11237}, + {0x1123E, 0x1123E}, + {0x11241, 0x11241}, + {0x112DF, 0x112DF}, + {0x112E3, 0x112EA}, + {0x11300, 0x11301}, + {0x1133B, 0x1133C}, + {0x11340, 0x11340}, + {0x11366, 0x11374}, + {0x113BB, 0x113C0}, + {0x113CE, 0x113CE}, + {0x113D0, 0x113D0}, + {0x113D2, 0x113D2}, + {0x113E1, 0x113E2}, + {0x11438, 0x1143F}, + {0x11442, 0x11444}, + {0x11446, 0x11446}, + {0x1145E, 0x1145E}, + {0x114B3, 0x114B8}, + {0x114BA, 0x114BA}, + {0x114BF, 0x114C0}, + {0x114C2, 0x114C3}, + {0x115B2, 0x115B5}, + {0x115BC, 0x115BD}, + {0x115BF, 0x115C0}, + {0x115DC, 0x115DD}, + {0x11633, 0x1163A}, + {0x1163D, 0x1163D}, + {0x1163F, 0x11640}, + {0x116AB, 0x116AB}, + {0x116AD, 0x116AD}, + {0x116B0, 0x116B5}, + {0x116B7, 0x116B7}, + {0x1171D, 0x1171D}, + {0x1171F, 0x1171F}, + {0x11722, 0x11725}, + {0x11727, 0x1172B}, + {0x1182F, 0x11837}, + {0x11839, 0x1183A}, + {0x1193B, 0x1193C}, + {0x1193E, 0x1193E}, + {0x11943, 0x11943}, + {0x119D4, 0x119DB}, + {0x119E0, 0x119E0}, + {0x11A01, 0x11A0A}, + {0x11A33, 0x11A38}, + {0x11A3B, 0x11A3E}, + {0x11A47, 0x11A47}, + {0x11A51, 0x11A56}, + {0x11A59, 0x11A5B}, + {0x11A8A, 0x11A96}, + {0x11A98, 0x11A99}, + {0x11C30, 0x11C3D}, + {0x11C3F, 0x11C3F}, + {0x11C92, 0x11CA7}, + {0x11CAA, 0x11CB0}, + {0x11CB2, 0x11CB3}, + {0x11CB5, 0x11CB6}, + {0x11D31, 0x11D45}, + {0x11D47, 0x11D47}, + {0x11D90, 0x11D91}, + {0x11D95, 0x11D95}, + {0x11D97, 0x11D97}, + {0x11EF3, 0x11EF4}, + {0x11F00, 0x11F01}, + {0x11F36, 0x11F3A}, + {0x11F40, 0x11F40}, + {0x11F42, 0x11F42}, + {0x11F5A, 0x11F5A}, + {0x13430, 0x13440}, + {0x13447, 0x13455}, + {0x1611E, 0x16129}, + {0x1612D, 0x1612F}, + {0x16AF0, 0x16AF4}, + {0x16B30, 0x16B36}, + {0x16F4F, 0x16F4F}, + {0x16F8F, 0x16F92}, + {0x16FE4, 0x16FE4}, + {0x1BC9D, 0x1BC9E}, + {0x1BCA0, 0x1BCA3}, + {0x1CF00, 0x1CF46}, + {0x1D167, 0x1D169}, + {0x1D173, 0x1D182}, + {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, + {0x1D242, 0x1D244}, + {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, + {0x1DA75, 0x1DA75}, + {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DAAF}, + {0x1E000, 0x1E02A}, + {0x1E08F, 0x1E08F}, + {0x1E130, 0x1E136}, + {0x1E2AE, 0x1E2AE}, + {0x1E2EC, 0x1E2EF}, + {0x1E4EC, 0x1E4EF}, + {0x1E5EE, 0x1E5EF}, + {0x1E8D0, 0x1E8D6}, + {0x1E944, 0x1E94A}, + {0xE0001, 0xE01EF}, +}; diff --git a/src/include/parser/value.h b/src/include/parser/value.h index f6fafb5c3..0734c4ea2 100644 --- a/src/include/parser/value.h +++ b/src/include/parser/value.h @@ -4,8 +4,8 @@ * interface for value nodes * * - * Copyright (c) 2003-2024, PgPool Global Development Group - * Copyright (c) 2003-2024, PostgreSQL Global Development Group + * Copyright (c) 2003-2025, PgPool Global Development Group + * Copyright (c) 2003-2025, PostgreSQL Global Development Group * * src/include/nodes/value.h * diff --git a/src/include/pool.h b/src/include/pool.h index 233d36608..ea6f87e12 100644 --- a/src/include/pool.h +++ b/src/include/pool.h @@ -410,11 +410,9 @@ typedef enum #define REPLICATION (pool_config->backend_clustering_mode == CM_NATIVE_REPLICATION || \ pool_config->backend_clustering_mode == CM_SNAPSHOT_ISOLATION) #define MAIN_REPLICA (pool_config->backend_clustering_mode == CM_STREAMING_REPLICATION || \ - pool_config->backend_clustering_mode == CM_LOGICAL_REPLICATION || \ - pool_config->backend_clustering_mode == CM_SLONY) + pool_config->backend_clustering_mode == CM_LOGICAL_REPLICATION) #define STREAM (pool_config->backend_clustering_mode == CM_STREAMING_REPLICATION) #define LOGICAL (pool_config->backend_clustering_mode == CM_LOGICAL_REPLICATION) -#define SLONY (pool_config->backend_clustering_mode == CM_SLONY) #define RAW_MODE (pool_config->backend_clustering_mode == CM_RAW) #define SL_MODE (STREAM || LOGICAL) /* streaming or logical replication mode */ @@ -717,7 +715,7 @@ extern size_t strlcpy(char *dst, const char *src, size_t siz); #endif /* pool_worker_child.c */ -extern void do_worker_child(void); +extern void do_worker_child(void *params); extern int get_query_result(POOL_CONNECTION_POOL_SLOT **slots, int backend_id, char *query, POOL_SELECT_RESULT **res); /* utils/pg_strong_random.c */ diff --git a/src/include/pool_config.h b/src/include/pool_config.h index 3d12c0a9f..758d51552 100644 --- a/src/include/pool_config.h +++ b/src/include/pool_config.h @@ -70,19 +70,11 @@ typedef enum ProcessManagementSstrategies PM_STRATEGY_LAZY } ProcessManagementSstrategies; -typedef enum NativeReplicationSubModes -{ - SLONY_MODE = 1, - STREAM_MODE, - LOGICAL_MODE -} NativeReplicationSubModes; - typedef enum ClusteringModes { CM_STREAMING_REPLICATION = 1, CM_NATIVE_REPLICATION, CM_LOGICAL_REPLICATION, - CM_SLONY, CM_RAW, CM_SNAPSHOT_ISOLATION } ClusteringModes; @@ -261,7 +253,8 @@ typedef struct int authentication_timeout; /* maximum time in seconds to complete * client authentication */ int max_pool; /* max # of connection pool per child */ - char *logdir; /* logging directory */ + char *work_dir; /* directory to create pgpool_status and lock + * files */ char *log_destination_str; /* log destination: stderr and/or * syslog */ int log_destination; /* log destination */ @@ -665,16 +658,17 @@ typedef struct * lifecheck */ char *wd_lifecheck_user; /* PostgreSQL user name for watchdog */ char *wd_lifecheck_password; /* password for watchdog user */ - int wd_heartbeat_port; /* Port number for heartbeat lifecheck */ int wd_heartbeat_keepalive; /* Interval time of sending heartbeat * signal (sec) */ int wd_heartbeat_deadtime; /* Deadtime interval for heartbeat * signal (sec) */ WdHbIf hb_ifs[WD_MAX_IF_NUM]; /* heartbeat interfaces of all * watchdog nodes */ + WdHbIf hb_local_if[WD_MAX_IF_NUM]; /* local heartbeat interfaces */ + int num_hb_local_if; /* number of local interface */ WdHbIf hb_dest_if[WD_MAX_IF_NUM]; /* heartbeat destination * interfaces */ - int num_hb_dest_if; /* number of interface devices */ + int num_hb_dest_if; /* number of destination interface */ char **wd_monitoring_interfaces_list; /* network interface name list * to be monitored by watchdog */ bool health_check_test; /* if on, enable health check testing */ diff --git a/src/include/pool_type.h b/src/include/pool_type.h index 6e8fe85dc..078376b50 100644 --- a/src/include/pool_type.h +++ b/src/include/pool_type.h @@ -31,32 +31,34 @@ #include <sys/socket.h> #include <stddef.h> #include "libpq-fe.h" -/* Define common boolean type. C++ and BEOS already has it so exclude them. */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif /* __cplusplus */ -#endif /* c_plusplus */ - -#ifndef __BEOS__ -#ifndef __cplusplus -#ifndef bool -typedef char bool; -#endif -#ifndef true -#define true ((bool) 1) -#endif + +/* ---------------------------------------------------------------- + * Section 2: bool, true, false + * ---------------------------------------------------------------- + */ + +/* + * bool + * Boolean value, either true or false. + * + * PostgreSQL currently cannot deal with bool of size other than 1; there are + * static assertions around the code to prevent that. + */ + +#include <stdbool.h> + +/* + * Pgpool-II still uses TRUE/FALSE, that are only used Windows build in + * PostgreSQL. In the feature, we should replace TRUE/FALSE with true/false, + * but until that day... + */ + #ifndef TRUE #define TRUE ((bool) 1) #endif -#ifndef false -#define false ((bool) 0) -#endif #ifndef FALSE #define FALSE ((bool) 0) #endif -#endif /* not C++ */ -#endif /* __BEOS__ */ /* ---------------------------------------------------------------- * Section 5: offsetof, lengthof, endof, alignment diff --git a/src/include/utils/json.h b/src/include/utils/json.h index cb4378a9c..8bf5b8f52 100644 --- a/src/include/utils/json.h +++ b/src/include/utils/json.h @@ -313,7 +313,7 @@ extern "C" /* pgpool-II extensions */ json_value *json_get_value_for_key(json_value *source, const char *key); int json_get_int_value_for_key(json_value *source, const char *key, int *value); -int json_get_long_value_for_key(json_value *source, const char *key, long *value); +int json_get_llong_value_for_key(json_value *source, const char *key, long long *value); char *json_get_string_value_for_key(json_value *source, const char *key); int json_get_bool_value_for_key(json_value *source, const char *key, bool *value); diff --git a/src/include/utils/pool_relcache.h b/src/include/utils/pool_relcache.h index 16f2fcd61..b19d71ebc 100644 --- a/src/include/utils/pool_relcache.h +++ b/src/include/utils/pool_relcache.h @@ -6,7 +6,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2010 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -34,8 +34,6 @@ /* Relation lookup cache structure */ -typedef void *(*func_ptr) (); - typedef struct { char dbname[MAX_ITEM_LENGTH]; /* database name */ @@ -57,13 +55,13 @@ typedef struct * POOL_SELECT_RESULT *. This function must return a pointer to be saved * in cache->data. */ - func_ptr register_func; + void *(*register_func) (POOL_SELECT_RESULT *data); /* * User defined function to be called at data unregister. Argument * cache->data. */ - func_ptr unregister_func; + void *(*unregister_func) (void *data); bool cache_is_session_local; /* True if cache life time is session * local */ bool no_cache_if_zero; /* if register func returns 0, do not @@ -72,7 +70,7 @@ typedef struct } POOL_RELCACHE; extern POOL_RELCACHE *pool_create_relcache(int cachesize, char *sql, - func_ptr register_func, func_ptr unregister_func, + void *(*register_func) (POOL_SELECT_RESULT *), void *(*unregister_func) (void *), bool issessionlocal); extern void pool_discard_relcache(POOL_RELCACHE *relcache); extern void *pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, char *table); diff --git a/src/include/utils/pool_select_walker.h b/src/include/utils/pool_select_walker.h index 9eb9760c8..3c067c61a 100644 --- a/src/include/utils/pool_select_walker.h +++ b/src/include/utils/pool_select_walker.h @@ -6,7 +6,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2024 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -54,6 +54,9 @@ typedef struct char table_names[POOL_MAX_SELECT_OIDS][NAMEDATALEN]; /* table names */ } SelectContext; + +typedef bool (*tree_walker_callback) (Node *node, void *context); + extern int pool_get_terminate_backend_pid(Node *node); extern bool pool_has_function_call(Node *node); extern bool pool_has_non_immutable_function_call(Node *node); @@ -66,7 +69,7 @@ extern bool pool_has_row_security(Node *node); extern bool pool_has_insertinto_or_locking_clause(Node *node); extern bool pool_has_pgpool_regclass(void); extern bool pool_has_to_regclass(void); -extern bool raw_expression_tree_walker(Node *node, bool (*walker) (), void *context); +extern bool raw_expression_tree_walker(Node *node, tree_walker_callback walker, void *context); extern int pool_table_name_to_oid(char *table_name); extern int pool_extract_table_oids_from_select_stmt(Node *node, SelectContext *ctx); extern RangeVar *makeRangeVarFromNameList(List *names); diff --git a/src/include/version.h b/src/include/version.h index 0af58a638..861500331 100644 --- a/src/include/version.h +++ b/src/include/version.h @@ -1 +1 @@ -#define PGPOOLVERSION "tasukiboshi" +#define PGPOOLVERSION "mitsukakeboshi" diff --git a/src/include/watchdog/wd_commands.h b/src/include/watchdog/wd_commands.h index 61326137d..a016772f6 100644 --- a/src/include/watchdog/wd_commands.h +++ b/src/include/watchdog/wd_commands.h @@ -52,7 +52,7 @@ typedef struct WDGenericData char *stringVal; int intVal; bool boolVal; - long longVal; + long long longVal; } data; } WDGenericData; diff --git a/src/include/watchdog/wd_json_data.h b/src/include/watchdog/wd_json_data.h index 1016dcae8..01e40e784 100644 --- a/src/include/watchdog/wd_json_data.h +++ b/src/include/watchdog/wd_json_data.h @@ -51,8 +51,8 @@ extern bool parse_node_status_json(char *json_data, int data_len, int *nodeID, i extern bool parse_beacon_message_json(char *json_data, int data_len, int *state, - long *seconds_since_node_startup, - long *seconds_since_current_state, + long long *seconds_since_node_startup, + long long *seconds_since_current_state, int *quorumStatus, int *standbyNodesCount, bool *escalated); diff --git a/src/include/watchdog/wd_utils.h b/src/include/watchdog/wd_utils.h index 0c8ad17ca..5df1fa1e9 100644 --- a/src/include/watchdog/wd_utils.h +++ b/src/include/watchdog/wd_utils.h @@ -49,10 +49,7 @@ extern pid_t fork_escalation_process(void); extern pid_t fork_plunging_process(void); /* wd_ping.c */ -extern int wd_is_upper_ok(char *server_list); extern bool wd_is_ip_exists(char *ip); -extern bool wd_get_ping_result(char *hostname, int exit_status, int outfd); -extern pid_t wd_issue_ping_command(char *hostname, int *outfd); extern pid_t wd_trusted_server_command(char *hostname); /* wd_if.c */ diff --git a/src/libs/pcp/Makefile.am b/src/libs/pcp/Makefile.am index c3172c203..31f51233a 100644 --- a/src/libs/pcp/Makefile.am +++ b/src/libs/pcp/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = -D_GNU_SOURCE -DPOOL_PRIVATE -I @PGSQL_INCLUDE_DIR@ lib_LTLIBRARIES = libpcp.la -libpcp_la_LDFLAGS = -version-info 2:1:0 +libpcp_la_LDFLAGS = -version-info 3:0:0 dist_libpcp_la_SOURCES = pcp.c \ ../../utils/pool_path.c \ ../../tools/fe_port.c \ diff --git a/src/libs/pcp/pcp.c b/src/libs/pcp/pcp.c index 3992eeeb7..f8a635065 100644 --- a/src/libs/pcp/pcp.c +++ b/src/libs/pcp/pcp.c @@ -196,6 +196,7 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde pcp_internal_error(pcpConn, "ERROR: failed to create INET domain socket with error \"%s\"", strerror(errno)); + freeaddrinfo(res); return pcpConn; } @@ -203,6 +204,7 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde (char *) &on, sizeof(on)) < 0) { close(fd); + freeaddrinfo(res); pcp_internal_error(pcpConn, "ERROR: set socket option failed with error \"%s\"", strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; @@ -212,6 +214,7 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde if (connect(fd, walk->ai_addr, walk->ai_addrlen) < 0) { close(fd); + freeaddrinfo(res); pcp_internal_error(pcpConn, "ERROR: connection to host \"%s\" failed with error \"%s\"", hostname, strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; @@ -220,6 +223,7 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde break; /* successfully connected */ } + freeaddrinfo(res); /* no address available */ if (fd == -1) { diff --git a/src/main/health_check.c b/src/main/health_check.c index f32d54ce0..0c72c0a72 100644 --- a/src/main/health_check.c +++ b/src/main/health_check.c @@ -109,7 +109,7 @@ static bool check_backend_down_request(int node, bool done_requests); * health check child main loop */ void -do_health_check_child(int *node_id) +do_health_check_child(void *params) { sigjmp_buf local_sigjmp_buf; MemoryContext HealthCheckMemoryContext; @@ -117,20 +117,22 @@ do_health_check_child(int *node_id) static struct timeval start_time; static struct timeval end_time; long diff_t; + int node_id; POOL_HEALTH_CHECK_STATISTICS mystat; - stats = &health_check_stats[*node_id]; + node_id = *((int *) params); + stats = &health_check_stats[node_id]; /* Set application name */ - set_application_name_with_suffix(PT_HEALTH_CHECK, *node_id); + set_application_name_with_suffix(PT_HEALTH_CHECK, node_id); ereport(DEBUG1, - (errmsg("I am health check process pid:%d DB node id:%d", getpid(), *node_id))); + (errmsg("I am health check process pid:%d DB node id:%d", getpid(), node_id))); /* Identify myself via ps */ init_ps_display("", "", "", ""); - snprintf(psbuffer, sizeof(psbuffer), "health check process(%d)", *node_id); + snprintf(psbuffer, sizeof(psbuffer), "health check process(%d)", node_id); set_ps_display(psbuffer, false); /* set up signal handlers */ @@ -193,7 +195,7 @@ do_health_check_child(int *node_id) CHECK_REQUEST; - if (pool_config->health_check_params[*node_id].health_check_period <= 0) + if (pool_config->health_check_params[node_id].health_check_period <= 0) { stats->min_health_check_duration = 0; sleep(30); @@ -203,27 +205,27 @@ do_health_check_child(int *node_id) * If health checking is enabled and the node is not in down status, * do health check. */ - else if (pool_config->health_check_params[*node_id].health_check_period > 0) + else if (pool_config->health_check_params[node_id].health_check_period > 0) { bool result; - BackendInfo *bkinfo = pool_get_node_info(*node_id); + BackendInfo *bkinfo = pool_get_node_info(node_id); stats->total_count++; gettimeofday(&start_time, NULL); stats->last_health_check = time(NULL); - result = establish_persistent_connection(*node_id); + result = establish_persistent_connection(node_id); if (result && slot == NULL) { stats->last_failed_health_check = time(NULL); - if (POOL_DISALLOW_TO_FAILOVER(BACKEND_INFO(*node_id).flag)) + if (POOL_DISALLOW_TO_FAILOVER(BACKEND_INFO(node_id).flag)) { ereport(LOG, (errmsg("health check failed on node %d but failover is disallowed for the node", - *node_id))); + node_id))); } else { @@ -232,19 +234,19 @@ do_health_check_child(int *node_id) stats->fail_count++; ereport(LOG, (errmsg("health check failed on node %d (timeout:%d)", - *node_id, health_check_timer_expired))); + node_id, health_check_timer_expired))); if (bkinfo->backend_status == CON_DOWN && bkinfo->quarantine == true) { ereport(LOG, (errmsg("health check failed on quarantine node %d (timeout:%d)", - *node_id, health_check_timer_expired), + node_id, health_check_timer_expired), errdetail("ignoring.."))); } else { /* trigger failover */ partial = health_check_timer_expired ? false : true; - degenerate_backend_set(node_id, 1, partial ? REQ_DETAIL_SWITCHOVER : 0); + degenerate_backend_set(&node_id, 1, partial ? REQ_DETAIL_SWITCHOVER : 0); } } } @@ -257,7 +259,7 @@ do_health_check_child(int *node_id) * The node has become reachable again. Reset the quarantine * state */ - send_failback_request(*node_id, false, REQ_DETAIL_UPDATE | REQ_DETAIL_WATCHDOG); + send_failback_request(node_id, false, REQ_DETAIL_UPDATE | REQ_DETAIL_WATCHDOG); } else if (result && slot) { @@ -274,7 +276,7 @@ do_health_check_child(int *node_id) } /* Discard persistent connections */ - discard_persistent_connection(*node_id); + discard_persistent_connection(node_id); /* * Update health check duration only if health check was not @@ -302,7 +304,7 @@ do_health_check_child(int *node_id) memcpy(&mystat, (void *) stats, sizeof(mystat)); - sleep(pool_config->health_check_params[*node_id].health_check_period); + sleep(pool_config->health_check_params[node_id].health_check_period); } } exit(0); @@ -618,7 +620,7 @@ check_backend_down_request(int node, bool done_requests) if (backend_down_request_file[0] == '\0') { snprintf(backend_down_request_file, sizeof(backend_down_request_file), - "%s/%s", pool_config->logdir, BACKEND_DOWN_REQUEST_FILE); + "%s/%s", pool_config->work_dir, BACKEND_DOWN_REQUEST_FILE); } fd = fopen(backend_down_request_file, "r"); diff --git a/src/main/pgpool_logger.c b/src/main/pgpool_logger.c index 9d127183a..d57a0d000 100644 --- a/src/main/pgpool_logger.c +++ b/src/main/pgpool_logger.c @@ -50,7 +50,7 @@ #include "main/pgpool_logger.h" #define DEVNULL "/dev/null" -typedef int64 pg_time_t; +typedef time_t pg_time_t; /* * We read() into a temp buffer twice as big as a chunk, so that any fragment @@ -113,7 +113,7 @@ static volatile sig_atomic_t got_SIGHUP = false; static volatile sig_atomic_t rotation_requested = false; -static void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn(); +pg_noreturn static void SysLoggerMain(int argc, char *argv[]); static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer); static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer); static FILE *logfile_open(const char *filename, const char *mode, diff --git a/src/main/pgpool_main.c b/src/main/pgpool_main.c index ef2e5dfc1..4d88c5815 100644 --- a/src/main/pgpool_main.c +++ b/src/main/pgpool_main.c @@ -5,7 +5,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2024 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -137,6 +137,7 @@ typedef struct bool sync_required; /* true if watchdog synchronization is * necessary */ + /* followings are copy of Req_info */ POOL_REQUEST_KIND reqkind; int node_id_set[MAX_NUM_BACKENDS]; int node_count; @@ -154,7 +155,7 @@ static void signal_user1_to_parent_with_reason(User1SignalReason reason); static void FileUnlink(int code, Datum path); static pid_t pcp_fork_a_child(int *fds, char *pcp_conf_file); static pid_t fork_a_child(int *fds, int id); -static pid_t worker_fork_a_child(ProcessType type, void (*func) (), void *params); +static pid_t worker_fork_a_child(ProcessType type, void (*func) (void *), void *params); static int create_unix_domain_socket(struct sockaddr_un un_addr_tmp, const char *group, const int permissions); static int *create_unix_domain_sockets_by_list(struct sockaddr_un *un_addrs, char *group, int permissions, int n_sockets); static int *create_inet_domain_sockets(const char *hostname, const int port); @@ -305,6 +306,12 @@ PgpoolMain(bool discard_status, bool clear_memcache_oidmaps) */ volatile bool first = true; + /* + * Query cache lock file path. This should be declared as "static" because + * the path is passed to be registered using on_proc_exit(). + */ + static char query_cache_lock_path[MAXPGPATH]; + processState = INITIALIZING; /* @@ -511,23 +518,23 @@ PgpoolMain(bool discard_status, bool clear_memcache_oidmaps) } /* For query cache concurrency control */ - if (pool_config->memory_cache_enabled) + if (pool_config->memory_cache_enabled || pool_config->enable_shared_relcache) { - char path[1024]; int lfd; - snprintf(path, sizeof(path), "%s/QUERY_CACHE_LOCK_FILE", pool_config->logdir); - lfd = open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); + snprintf(query_cache_lock_path, sizeof(query_cache_lock_path), + "%s/%s", pool_config->work_dir, QUERY_CACHE_LOCK_FILE); + lfd = open(query_cache_lock_path, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); if (lfd == -1) { ereport(FATAL, - (errmsg("Failed to open lock file for query cache \"%s\"", path), + (errmsg("Failed to open lock file for query cache \"%s\"", query_cache_lock_path), errdetail("%m"))); } close(lfd); /* Register file unlink at exit */ - on_proc_exit(FileUnlink, (Datum) path); + on_proc_exit(FileUnlink, (Datum) query_cache_lock_path); } /* @@ -878,7 +885,7 @@ fork_a_child(int *fds, int id) * fork worker child process */ static pid_t -worker_fork_a_child(ProcessType type, void (*func) (), void *params) +worker_fork_a_child(ProcessType type, void (*func) (void *), void *params) { pid_t pid; @@ -1636,9 +1643,9 @@ failover(void) wd_failover_start(); /* - * if not in replication mode/native replication mode, we treat this a - * restart request. otherwise we need to check if we have already - * failovered. + * If not in streaming replication mode/native replication mode, we + * treat this as a restart request. Otherwise we need to check if we + * have already performed the failover. */ ereport(DEBUG1, (errmsg("failover handler"), @@ -1651,14 +1658,14 @@ failover(void) */ if (failover_context.request_details & REQ_DETAIL_PROMOTE) { - promote_node = failover_context.node_id_set[0]; + promote_node = failover_context.node_id_set[0]; /* requested node */ for (i = 0; i < failover_context.node_count; i++) { failover_context.node_id_set[i] = REAL_PRIMARY_NODE_ID; } } - node_id = failover_context.node_id_set[0]; + node_id = failover_context.node_id_set[0]; /* set target node id */ /* failback request? */ if (failover_context.reqkind == NODE_UP_REQUEST) @@ -1686,6 +1693,7 @@ failover(void) * NODE_QUARANTINE_REQUEST */ { + /* process single failover request */ if (handle_failover_request(&failover_context, node_id) < 0) continue; } @@ -3196,7 +3204,7 @@ read_status_file(bool discard_status) pool_set_backend_status_changed_time(i); } - snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME); + snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->work_dir, STATUS_FILE_NAME); fd = fopen(fnamebuf, "r"); if (!fd) { @@ -3383,7 +3391,7 @@ write_status_file(void) return 0; } - snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME); + snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->work_dir, STATUS_FILE_NAME); fd = fopen(fnamebuf, "w"); if (!fd) { diff --git a/src/parser/copyfuncs.c b/src/parser/copyfuncs.c index 4571d4b17..9cbbbe4f0 100644 --- a/src/parser/copyfuncs.c +++ b/src/parser/copyfuncs.c @@ -11,8 +11,8 @@ * be handled easily in a simple depth-first traversal. * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -52,7 +52,7 @@ /* Copy a field that is a pointer to a C string, or perhaps NULL */ #define COPY_STRING_FIELD(fldname) \ - (newnode->fldname = from->fldname ? pstrdup(from->fldname) : (char *) NULL) + (newnode->fldname = from->fldname ? pstrdup(from->fldname) : NULL) /* Copy a field that is an inline array */ #define COPY_ARRAY_FIELD(fldname) \ @@ -90,6 +90,7 @@ _copyPlannedStmt(const PlannedStmt * from) COPY_SCALAR_FIELD(commandType); COPY_SCALAR_FIELD(queryId); + COPY_SCALAR_FIELD(planId); COPY_SCALAR_FIELD(hasReturning); COPY_SCALAR_FIELD(hasModifyingCTE); COPY_SCALAR_FIELD(canSetTag); @@ -98,7 +99,10 @@ _copyPlannedStmt(const PlannedStmt * from) COPY_SCALAR_FIELD(parallelModeNeeded); COPY_SCALAR_FIELD(jitFlags); COPY_NODE_FIELD(planTree); + COPY_NODE_FIELD(partPruneInfos); COPY_NODE_FIELD(rtable); + COPY_BITMAPSET_FIELD(unprunableRelids); + COPY_NODE_FIELD(permInfos); COPY_NODE_FIELD(resultRelations); COPY_NODE_FIELD(appendRelations); COPY_NODE_FIELD(subplans); @@ -123,6 +127,7 @@ _copyPlannedStmt(const PlannedStmt * from) static void CopyPlanFields(const Plan * from, Plan * newnode) { + COPY_SCALAR_FIELD(plan.disabled_nodes); COPY_SCALAR_FIELD(startup_cost); COPY_SCALAR_FIELD(total_cost); COPY_SCALAR_FIELD(plan_rows); @@ -218,6 +223,8 @@ _copyModifyTable(const ModifyTable * from) COPY_NODE_FIELD(resultRelations); COPY_NODE_FIELD(updateColnosLists); COPY_NODE_FIELD(withCheckOptionLists); + COPY_STRING_FIELD(returningOldAlias); + COPY_STRING_FIELD(returningNewAlias); COPY_NODE_FIELD(returningLists); COPY_NODE_FIELD(fdwPrivLists); COPY_BITMAPSET_FIELD(fdwDirectModifyPlans); @@ -256,7 +263,7 @@ _copyAppend(const Append * from) COPY_NODE_FIELD(appendplans); COPY_SCALAR_FIELD(nasyncplans); COPY_SCALAR_FIELD(first_partial_plan); - COPY_NODE_FIELD(part_prune_info); + COPY_SCALAR_FIELD(part_prune_index); return newnode; } @@ -284,7 +291,7 @@ _copyMergeAppend(const MergeAppend * from) COPY_POINTER_FIELD(sortOperators, from->numCols * sizeof(Oid)); COPY_POINTER_FIELD(collations, from->numCols * sizeof(Oid)); COPY_POINTER_FIELD(nullsFirst, from->numCols * sizeof(bool)); - COPY_NODE_FIELD(part_prune_info); + COPY_SCALAR_FIELD(part_prune_index); return newnode; } @@ -903,11 +910,11 @@ _copyMergeJoin(const MergeJoin * from) */ COPY_SCALAR_FIELD(skip_mark_restore); COPY_NODE_FIELD(mergeclauses); - numCols = list_length(from->mergeclauses); - COPY_POINTER_FIELD(mergeFamilies, numCols * sizeof(Oid)); - COPY_POINTER_FIELD(mergeCollations, numCols * sizeof(Oid)); - COPY_POINTER_FIELD(mergeStrategies, numCols * sizeof(int)); - COPY_POINTER_FIELD(mergeNullsFirst, numCols * sizeof(bool)); + COPY_POINTER_FIELD(mergeFamilies, list_length(from->mergeclauses) * sizeof(Oid)); + COPY_POINTER_FIELD(mergeCollations, list_length(from->mergeclauses) * sizeof(Oid)); + COPY_POINTER_FIELD(mergeStrategies, list_length(from->mergeclauses) * sizeof(int)); + COPY_POINTER_FIELD(mergeReversals, list_length(from->mergeclauses) * sizeof(bool)); + COPY_POINTER_FIELD(mergeNullsFirst, list_length(from->mergeclauses) * sizeof(bool)); return newnode; } @@ -1093,6 +1100,7 @@ _copyWindowAgg(const WindowAgg * from) CopyPlanFields((const Plan *) from, (Plan *) newnode); + COPY_STRING_FIELD(winname); COPY_SCALAR_FIELD(winref); COPY_SCALAR_FIELD(partNumCols); COPY_POINTER_FIELD(partColIdx, from->partNumCols * sizeof(AttrNumber)); @@ -1185,11 +1193,10 @@ _copySetOp(const SetOp * from) COPY_SCALAR_FIELD(cmd); COPY_SCALAR_FIELD(strategy); COPY_SCALAR_FIELD(numCols); - COPY_POINTER_FIELD(dupColIdx, from->numCols * sizeof(AttrNumber)); - COPY_POINTER_FIELD(dupOperators, from->numCols * sizeof(Oid)); - COPY_POINTER_FIELD(dupCollations, from->numCols * sizeof(Oid)); - COPY_SCALAR_FIELD(flagColIdx); - COPY_SCALAR_FIELD(firstFlag); + COPY_POINTER_FIELD(cmpColIdx, from->numCols * sizeof(AttrNumber)); + COPY_POINTER_FIELD(cmpOperators, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(cmpCollations, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(cmpNullsFirst, from->numCols * sizeof(bool)); COPY_SCALAR_FIELD(numGroups); return newnode; @@ -1283,6 +1290,7 @@ _copyPartitionPruneInfo(const PartitionPruneInfo * from) { PartitionPruneInfo *newnode = makeNode(PartitionPruneInfo); + COPY_BITMAPSET_FIELD(relids); COPY_NODE_FIELD(prune_infos); COPY_BITMAPSET_FIELD(other_subplans); @@ -1299,6 +1307,7 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo * from) COPY_SCALAR_FIELD(nparts); COPY_POINTER_FIELD(subplan_map, from->nparts * sizeof(int)); COPY_POINTER_FIELD(subpart_map, from->nparts * sizeof(int)); + COPY_POINTER_FIELD(leafpart_rti_map, from->nparts * sizeof(int)); COPY_POINTER_FIELD(relid_map, from->nparts * sizeof(Oid)); COPY_NODE_FIELD(initial_prunning_steps); COPY_NODE_FIELD(exec_prunning_steps); @@ -1461,7 +1470,9 @@ _copyVar(const Var *from) COPY_SCALAR_FIELD(vartype); COPY_SCALAR_FIELD(vartypmod); COPY_SCALAR_FIELD(varcollid); + COPY_BITMAPSET_FIELD(varnullingrels); COPY_SCALAR_FIELD(varlevelsup); + COPY_SCALAR_FIELD(varreturningtype); COPY_SCALAR_FIELD(varnosyn); COPY_SCALAR_FIELD(varattnosyn); COPY_LOCATION_FIELD(location); @@ -2014,6 +2025,8 @@ _copyArrayExpr(const ArrayExpr *from) COPY_SCALAR_FIELD(element_typeid); COPY_NODE_FIELD(elements); COPY_SCALAR_FIELD(multidims); + COPY_LOCATION_FIELD(list_start); + COPY_LOCATION_FIELD(list_end); COPY_LOCATION_FIELD(location); return newnode; @@ -2044,7 +2057,7 @@ _copyRowCompareExpr(const RowCompareExpr *from) { RowCompareExpr *newnode = makeNode(RowCompareExpr); - COPY_SCALAR_FIELD(rctype); + COPY_SCALAR_FIELD(cmptype); COPY_NODE_FIELD(opnos); COPY_NODE_FIELD(opfamilies); COPY_NODE_FIELD(inputcollids); @@ -2406,6 +2419,18 @@ _copyInferenceElem(const InferenceElem *from) return newnode; } +static ReturningExpr * +_copyReturningExpr(const ReturningExpr *from) +{ + ReturningExpr *newnode = makeNode(ReturningExpr); + + COPY_SCALAR_FIELD(retlevelsup); + COPY_SCALAR_FIELD(retold); + COPY_NODE_FIELD(retexpr); + + return newnode; +} + /* * _copyTargetEntry */ @@ -2513,7 +2538,7 @@ _copyPathKey(const PathKey * from) /* EquivalenceClasses are never moved, so just shallow-copy the pointer */ COPY_SCALAR_FIELD(pk_eclass); COPY_SCALAR_FIELD(pk_opfamily); - COPY_SCALAR_FIELD(pk_strategy); + COPY_SCALAR_FIELD(pk_cmptype); COPY_SCALAR_FIELD(pk_nulls_first); return newnode; @@ -2695,6 +2720,7 @@ _copyRangeTblEntry(const RangeTblEntry *from) COPY_NODE_FIELD(colcollations); COPY_STRING_FIELD(enrname); COPY_SCALAR_FIELD(enrtuples); + COPY_NODE_FIELD(groupexprs); COPY_SCALAR_FIELD(lateral); COPY_SCALAR_FIELD(inFromCl); COPY_NODE_FIELD(securityQuals); @@ -2752,6 +2778,7 @@ _copySortGroupClause(const SortGroupClause *from) COPY_SCALAR_FIELD(tleSortGroupRef); COPY_SCALAR_FIELD(eqop); COPY_SCALAR_FIELD(sortop); + COPY_SCALAR_FIELD(reverse_sort); COPY_SCALAR_FIELD(nulls_first); COPY_SCALAR_FIELD(hashable); @@ -2922,6 +2949,8 @@ _copyA_Expr(const A_Expr *from) COPY_NODE_FIELD(name); COPY_NODE_FIELD(lexpr); COPY_NODE_FIELD(rexpr); + COPY_LOCATION_FIELD(rexpr_list_start); + COPY_LOCATION_FIELD(rexpr_list_end); COPY_LOCATION_FIELD(location); return newnode; @@ -3045,6 +3074,8 @@ _copyA_ArrayExpr(const A_ArrayExpr *from) A_ArrayExpr *newnode = makeNode(A_ArrayExpr); COPY_NODE_FIELD(elements); + COPY_LOCATION_FIELD(list_start); + COPY_LOCATION_FIELD(list_end); COPY_LOCATION_FIELD(location); return newnode; @@ -3284,15 +3315,17 @@ _copyConstraint(const Constraint *from) COPY_STRING_FIELD(conname); COPY_SCALAR_FIELD(deferrable); COPY_SCALAR_FIELD(initdeferred); + COPY_SCALAR_FIELD(is_enforced); COPY_SCALAR_FIELD(skip_validation); COPY_SCALAR_FIELD(initially_valid); COPY_SCALAR_FIELD(is_no_inherit); COPY_NODE_FIELD(raw_expr); COPY_STRING_FIELD(cooked_expr); COPY_SCALAR_FIELD(generated_when); - COPY_SCALAR_FIELD(inhcount); + COPY_SCALAR_FIELD(generated_kind); COPY_SCALAR_FIELD(nulls_not_distinct); COPY_NODE_FIELD(keys); + COPY_SCALAR_FIELD(without_overlaps); COPY_NODE_FIELD(including); COPY_NODE_FIELD(exclusions); COPY_NODE_FIELD(options); @@ -3304,6 +3337,8 @@ _copyConstraint(const Constraint *from) COPY_NODE_FIELD(pktable); COPY_NODE_FIELD(fk_attrs); COPY_NODE_FIELD(pk_attrs); + COPY_SCALAR_FIELD(fk_with_period); + COPY_SCALAR_FIELD(pk_with_period); COPY_SCALAR_FIELD(fk_matchtype); COPY_SCALAR_FIELD(fk_upd_action); COPY_SCALAR_FIELD(fk_del_action); @@ -3366,6 +3401,29 @@ _copyRoleSpec(const RoleSpec *from) return newnode; } +static ReturningOption * +_copyReturningOption(const ReturningOption *from) +{ + ReturningOption *newnode = makeNode(ReturningOption); + + COPY_SCALAR_FIELD(option); + COPY_STRING_FIELD(value); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +static ReturningClause * +_copyReturningClause(const ReturningClause *from) +{ + ReturningClause *newnode = makeNode(ReturningClause); + + COPY_NODE_FIELD(options); + COPY_NODE_FIELD(exprs); + + return newnode; +} + static TriggerTransition * _copyTriggerTransition(const TriggerTransition *from) { @@ -3618,6 +3676,7 @@ _copyQuery(const Query *from) COPY_SCALAR_FIELD(hasModifyingCTE); COPY_SCALAR_FIELD(hasForUpdate); COPY_SCALAR_FIELD(hasRowSecurity); + COPY_SCALAR_FIELD(hasGroupRTE); COPY_SCALAR_FIELD(isReturn); COPY_NODE_FIELD(cteList); COPY_NODE_FIELD(rtable); @@ -3629,6 +3688,8 @@ _copyQuery(const Query *from) COPY_NODE_FIELD(targetList); COPY_SCALAR_FIELD(override); COPY_NODE_FIELD(onConflict); + COPY_STRING_FIELD(returningOldAlias); + COPY_STRING_FIELD(returningNewAlias); COPY_NODE_FIELD(returningList); COPY_NODE_FIELD(groupClause); COPY_SCALAR_FIELD(groupDistinct); @@ -3671,7 +3732,7 @@ _copyInsertStmt(const InsertStmt *from) COPY_NODE_FIELD(cols); COPY_NODE_FIELD(selectStmt); COPY_NODE_FIELD(onConflictClause); - COPY_NODE_FIELD(returningList); + COPY_NODE_FIELD(returningClause); COPY_NODE_FIELD(withClause); COPY_SCALAR_FIELD(override); @@ -3686,7 +3747,7 @@ _copyDeleteStmt(const DeleteStmt *from) COPY_NODE_FIELD(relation); COPY_NODE_FIELD(usingClause); COPY_NODE_FIELD(whereClause); - COPY_NODE_FIELD(returningList); + COPY_NODE_FIELD(returningClause); COPY_NODE_FIELD(withClause); return newnode; @@ -3701,7 +3762,7 @@ _copyUpdateStmt(const UpdateStmt *from) COPY_NODE_FIELD(targetList); COPY_NODE_FIELD(whereClause); COPY_NODE_FIELD(fromClause); - COPY_NODE_FIELD(returningList); + COPY_NODE_FIELD(returningClause); COPY_NODE_FIELD(withClause); return newnode; @@ -3716,7 +3777,7 @@ _copyMergeStmt(const MergeStmt *from) COPY_NODE_FIELD(sourceRelation); COPY_NODE_FIELD(joinCondition); COPY_NODE_FIELD(mergeWhenClauses); - COPY_NODE_FIELD(returningList); + COPY_NODE_FIELD(returningClause); COPY_NODE_FIELD(withClause); return newnode; @@ -3822,6 +3883,34 @@ _copyAlterTableCmd(const AlterTableCmd *from) return newnode; } +static ATAlterConstraint * +_copyATAlterConstraint(const ATAlterConstraint *from) +{ + ATAlterConstraint *newnode = makeNode(ATAlterConstraint); + + COPY_STRING_FIELD(conname); + COPY_SCALAR_FIELD(alterEnforceability); + COPY_SCALAR_FIELD(is_enforced); + COPY_SCALAR_FIELD(alterDeferrability); + COPY_SCALAR_FIELD(deferrable); + COPY_SCALAR_FIELD(initdeferred); + COPY_SCALAR_FIELD(alterInheritability); + COPY_SCALAR_FIELD(noinherit); + + return newnode; +} + +static ReplicaIdentityStmt * +_copyReplicaIdentityStmt(const ReplicaIdentityStmt *from) +{ + ReplicaIdentityStmt *newnode = makeNode(ReplicaIdentityStmt); + + COPY_SCALAR_FIELD(identity_type); + COPY_STRING_FIELD(name); + + return newnode; +} + static AlterCollationStmt * _copyAlterCollationStmt(const AlterCollationStmt *from) { @@ -3994,6 +4083,7 @@ CopyCreateStmtFields(const CreateStmt *from, CreateStmt *newnode) COPY_NODE_FIELD(partbound); COPY_NODE_FIELD(ofTypename); COPY_NODE_FIELD(constraints); + COPY_NODE_FIELD(nnconstraints); COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(oncommit); COPY_STRING_FIELD(tablespacename); @@ -4126,6 +4216,7 @@ _copyIndexStmt(const IndexStmt *from) COPY_SCALAR_FIELD(nulls_not_distinct); COPY_SCALAR_FIELD(primary); COPY_SCALAR_FIELD(isconstraint); + COPY_SCALAR_FIELD(iswithoutoverlaps); COPY_SCALAR_FIELD(deferrable); COPY_SCALAR_FIELD(initdeferred); COPY_SCALAR_FIELD(transformed); @@ -4189,6 +4280,7 @@ _copyFunctionParameter(const FunctionParameter *from) COPY_NODE_FIELD(argType); COPY_SCALAR_FIELD(mode); COPY_NODE_FIELD(defexpr); + COPY_LOCATION_FIELD(location); return newnode; } @@ -4613,17 +4705,6 @@ _copyRefreshMatViewStmt(const RefreshMatViewStmt *from) return newnode; } -static ReplicaIdentityStmt * -_copyReplicaIdentityStmt(const ReplicaIdentityStmt *from) -{ - ReplicaIdentityStmt *newnode = makeNode(ReplicaIdentityStmt); - - COPY_SCALAR_FIELD(identity_type); - COPY_STRING_FIELD(name); - - return newnode; -} - static AlterSystemStmt * _copyAlterSystemStmt(const AlterSystemStmt *from) { @@ -4669,7 +4750,9 @@ _copyVariableSetStmt(const VariableSetStmt *from) COPY_SCALAR_FIELD(kind); COPY_STRING_FIELD(name); COPY_NODE_FIELD(args); + COPY_SCALAR_FIELD(jumble_args); COPY_SCALAR_FIELD(is_local); + COPY_LOCATION_FIELD(location); return newnode; } @@ -5279,15 +5362,6 @@ _copyPartitionRangeDatum(const PartitionRangeDatum *from) return newnode; } -static SinglePartitionSpec * -_copySinglePartitionSpec(const SinglePartitionSpec *from) -{ - SinglePartitionSpec *newnode = makeNode(SinglePartitionSpec); - - - return newnode; -} - static PartitionCmd * _copyPartitionCmd(const PartitionCmd *from) { @@ -5479,6 +5553,7 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo * from) COPY_SCALAR_FIELD(conrelid); COPY_SCALAR_FIELD(confrelid); COPY_SCALAR_FIELD(nkeys); + COPY_SCALAR_FIELD(conenforced); COPY_ARRAY_FIELD(conkey); COPY_ARRAY_FIELD(confkey); COPY_ARRAY_FIELD(conpfeqop); @@ -5855,6 +5930,9 @@ copyObjectImpl(const void *from) case T_InferenceElem: retval = _copyInferenceElem(from); break; + case T_ReturningExpr: + retval = _copyReturningExpr(from); + break; case T_TargetEntry: retval = _copyTargetEntry(from); break; @@ -5985,6 +6063,12 @@ copyObjectImpl(const void *from) case T_AlterTableCmd: retval = _copyAlterTableCmd(from); break; + case T_ATAlterConstraint: + retval = _copyATAlterConstraint(from); + break; + case T_ReplicaIdentityStmt: + retval = _copyReplicaIdentityStmt(from); + break; case T_AlterCollationStmt: retval = _copyAlterCollationStmt(from); break; @@ -6156,9 +6240,6 @@ copyObjectImpl(const void *from) case T_RefreshMatViewStmt: retval = _copyRefreshMatViewStmt(from); break; - case T_ReplicaIdentityStmt: - retval = _copyReplicaIdentityStmt(from); - break; case T_AlterSystemStmt: retval = _copyAlterSystemStmt(from); break; @@ -6444,6 +6525,12 @@ copyObjectImpl(const void *from) case T_MergeWhenClause: retval = _copyMergeWhenClause(from); break; + case T_ReturningOption: + retval = _copyReturningOption(from); + break; + case T_ReturningClause: + retval = _copyReturningClause(from); + break; case T_ObjectWithArgs: retval = _copyObjectWithArgs(from); break; @@ -6519,9 +6606,6 @@ copyObjectImpl(const void *from) case T_PartitionRangeDatum: retval = _copyPartitionRangeDatum(from); break; - case T_SinglePartitionSpec: - retval = _copySinglePartitionSpec(from); - break; case T_PartitionCmd: retval = _copyPartitionCmd(from); break; diff --git a/src/parser/gram.y b/src/parser/gram.y index 61663cce2..8052ced8d 100644 --- a/src/parser/gram.y +++ b/src/parser/gram.y @@ -6,8 +6,8 @@ * gram.y * POSTGRESQL BISON rules/actions * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -89,6 +89,8 @@ #define ATTRIBUTE_IDENTITY_ALWAYS 'a' #define ATTRIBUTE_IDENTITY_BY_DEFAULT 'd' +#define ATTRIBUTE_GENERATED_STORED 's' +#define ATTRIBUTE_GENERATED_VIRTUAL 'v' /* * Definition taken from * postgreSQL source code file: src/include/utils/xml.h @@ -102,40 +104,26 @@ typedef enum } XmlStandaloneType; /* - * Location tracking support --- simpler than bison's default, since we only - * want to track the start position not the end position of each nonterminal. + * Location tracking support. Unlike bison's default, we only want + * to track the start position not the end position of each nonterminal. + * Nonterminals that reduce to empty receive position "-1". Since a + * production's leading RHS nonterminal(s) may have reduced to empty, + * we have to scan to find the first one that's not -1. */ #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ - if ((N) > 0) \ - (Current) = (Rhs)[1]; \ - else \ - (Current) = (-1); \ + (Current) = (-1); \ + for (int _i = 1; _i <= (N); _i++) \ + { \ + if ((Rhs)[_i] >= 0) \ + { \ + (Current) = (Rhs)[_i]; \ + break; \ + } \ + } \ } while (0) /* - * The above macro assigns -1 (unknown) as the parse location of any - * nonterminal that was reduced from an empty rule, or whose leftmost - * component was reduced from an empty rule. This is problematic - * for nonterminals defined like - * OptFooList: / * EMPTY * / { ... } | OptFooList Foo { ... } ; - * because we'll set -1 as the location during the first reduction and then - * copy it during each subsequent reduction, leaving us with -1 for the - * location even when the list is not empty. To fix that, do this in the - * action for the nonempty rule(s): - * if (@$ < 0) @$ = @2; - * (Although we have many nonterminals that follow this pattern, we only - * bother with fixing @$ like this when the nonterminal's parse location - * is actually referenced in some rule.) - * - * A cleaner answer would be to make YYLLOC_DEFAULT scan all the Rhs - * locations until it's found one that's not -1. Then we'd get a correct - * location for any nonterminal that isn't entirely empty. But this way - * would add overhead to every rule reduction, and so far there's not been - * a compelling reason to pay that overhead. - */ - -/* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents * memory leaks if we error out during parsing. @@ -158,12 +146,15 @@ typedef struct ImportQual List *table_names; } ImportQual; -/* Private struct for the result of opt_select_limit production */ +/* Private struct for the result of select_limit & limit_clause productions */ typedef struct SelectLimit { Node *limitOffset; Node *limitCount; - LimitOption limitOption; + LimitOption limitOption; /* indicates presence of WITH TIES */ + ParseLoc offsetLoc; /* location of OFFSET token, if present */ + ParseLoc countLoc; /* location of LIMIT/FETCH token, if present */ + ParseLoc optionLoc; /* location of WITH TIES, if present */ } SelectLimit; /* Private struct for the result of group_clause production */ @@ -193,6 +184,8 @@ typedef struct KeyActions #define CAS_INITIALLY_DEFERRED 0x08 #define CAS_NOT_VALID 0x10 #define CAS_NO_INHERIT 0x20 +#define CAS_NOT_ENFORCED 0x40 +#define CAS_ENFORCED 0x80 #define parser_yyerror(msg) scanner_yyerror(msg, yyscanner) @@ -228,12 +221,12 @@ static void doNegateFloat(Float *v); static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location); static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location); static Node *makeNotExpr(Node *expr, int location); -static Node *makeAArrayExpr(List *elements, int location); +static Node *makeAArrayExpr(List *elements, int location, int end_location); static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location); static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location); -static List *mergeTableFuncParameters(List *func_args, List *columns); +static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); static RangeVar *makeRangeVarFromQualifiedName(char *name, List *namelist, int location, @@ -242,9 +235,10 @@ static void SplitColQualList(List *qualList, List **constraintList, CollateClause **collClause, core_yyscan_t yyscanner); static void processCASbits(int cas_bits, int location, const char *constrType, - bool *deferrable, bool *initdeferred, bool *not_valid, - bool *no_inherit, core_yyscan_t yyscanner); -static PartitionStrategy parsePartitionStrategy(char *strategy); + bool *deferrable, bool *initdeferred, bool *is_enforced, + bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); +static PartitionStrategy parsePartitionStrategy(char *strategy, int location, + core_yyscan_t yyscanner); static void preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); @@ -310,6 +304,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); MergeWhenClause *mergewhen; struct KeyActions *keyactions; struct KeyAction *keyaction; + ReturningClause *retclause; + ReturningOptionKind retoptionkind; } %type <node> stmt toplevel_stmt schema_stmt routine_body_stmt @@ -480,7 +476,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); opclass_purpose opt_opfamily transaction_mode_list_or_empty OptTableFuncElementList TableFuncElementList opt_type_modifiers prep_type_clause - execute_param_clause using_clause returning_clause + execute_param_clause using_clause + returning_with_clause returning_options opt_enum_val_list enum_val_list table_func_column_list create_generic_options alter_generic_options relation_expr_list dostmt_opt_list @@ -489,6 +486,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); vacuum_relation_list opt_vacuum_relation_list drop_option_list pub_obj_list +%type <retclause> returning_clause +%type <node> returning_option +%type <retoptionkind> returning_option_kind %type <node> opt_routine_body %type <groupclause> group_clause %type <list> group_by_list @@ -527,7 +527,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <boolean> opt_instead %type <boolean> opt_unique opt_verbose opt_full -%type <boolean> opt_freeze opt_analyze opt_default opt_recheck +%type <boolean> opt_freeze opt_analyze opt_default %type <defelt> opt_binary copy_delimiter %type <boolean> copy_from opt_program @@ -557,14 +557,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); SetResetClause FunctionSetResetClause %type <node> TableElement TypedTableElement ConstraintElem DomainConstraintElem TableFuncElement -%type <node> columnDef columnOptions +%type <node> columnDef columnOptions optionalPeriodName %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem %type <node> def_arg columnElem where_clause where_or_current_clause a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound - columnref in_expr having_clause func_table xmltable array_expr + columnref having_clause func_table xmltable array_expr OptWhereClause operator_def_arg +%type <list> opt_column_and_period_list %type <list> rowsfrom_item rowsfrom_list opt_col_def_list -%type <boolean> opt_ordinality +%type <boolean> opt_ordinality opt_without_overlaps %type <list> ExclusionConstraintList ExclusionConstraintElem %type <list> func_arg_list func_arg_list_opt %type <node> func_arg_expr @@ -673,7 +674,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <str> opt_existing_window_name %type <boolean> opt_if_not_exists %type <boolean> opt_unique_null_treatment -%type <ival> generated_when override_kind +%type <ival> generated_when override_kind opt_virtual_or_stored %type <partspec> PartitionSpec OptPartitionSpec %type <partelem> part_elem %type <list> part_params @@ -756,9 +757,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP - EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERROR_P ESCAPE - EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION - EXTENSION EXTERNAL EXTRACT + EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERROR_P + ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN + EXPRESSION EXTENSION EXTERNAL EXTRACT FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS @@ -789,18 +790,18 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC - OBJECT_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR + OBJECT_P OBJECTS_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR ORDER ORDINALITY OTHERS OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH PGPOOL - PLACING PLAN PLANS POLICY + PERIOD PLACING PLAN PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION QUOTE QUOTES - RANGE READ REAL REASSIGN RECHECK RECURSIVE REF_P REFERENCES REFERENCING + RANGE READ REAL REASSIGN RECURSIVE REF_P REFERENCES REFERENCING REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROUTINE ROUTINES ROW ROWS RULE @@ -821,7 +822,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); UNLISTEN UNLOGGED UNTIL UPDATE USER USING VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING - VERBOSE VERSION_P VIEW VIEWS VOLATILE + VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE @@ -962,7 +963,7 @@ parse_toplevel: | MODE_PLPGSQL_EXPR PLpgSQL_Expr { pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt($2, 0)); + list_make1(makeRawStmt($2, @2)); } | MODE_PLPGSQL_ASSIGN1 PLAssignStmt { @@ -970,7 +971,7 @@ parse_toplevel: n->nnames = 1; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } | MODE_PLPGSQL_ASSIGN2 PLAssignStmt { @@ -978,7 +979,7 @@ parse_toplevel: n->nnames = 2; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } | MODE_PLPGSQL_ASSIGN3 PLAssignStmt { @@ -986,19 +987,15 @@ parse_toplevel: n->nnames = 3; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } ; /* * At top level, we wrap each stmt with a RawStmt node carrying start location - * and length of the stmt's text. Notice that the start loc/len are driven - * entirely from semicolon locations (@2). It would seem natural to use - * @1 or @3 to get the true start location of a stmt, but that doesn't work - * for statements that can start with empty nonterminals (opt_with_clause is - * the main offender here); as noted in the comments for YYLLOC_DEFAULT, - * we'd get -1 for the location in such cases. - * We also take care to discard empty statements entirely. + * and length of the stmt's text. + * We also take care to discard empty statements entirely (which among other + * things dodges the problem of assigning them a location). */ stmtmulti: stmtmulti ';' toplevel_stmt { @@ -1008,14 +1005,14 @@ stmtmulti: stmtmulti ';' toplevel_stmt updateRawStmtEnd(llast_node(RawStmt, $1), @2); } if ($3 != NULL) - $$ = lappend($1, makeRawStmt($3, @2 + 1)); + $$ = lappend($1, makeRawStmt($3, @3)); else $$ = $1; } | toplevel_stmt { if ($1 != NULL) - $$ = list_make1(makeRawStmt($1, 0)); + $$ = list_make1(makeRawStmt($1, @1)); else $$ = NIL; } @@ -1616,8 +1613,6 @@ CreateSchemaStmt: OptSchemaEltList: OptSchemaEltList schema_stmt { - if (@$ < 0) /* see comments for YYLLOC_DEFAULT */ - @$ = @2; $$ = lappend($1, $2); } | /* EMPTY */ @@ -1693,6 +1688,8 @@ set_rest: n->kind = VAR_SET_MULTI; n->name = "TRANSACTION"; n->args = $2; + n->jumble_args = true; + n->location = -1; $$ = n; } | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list @@ -1702,6 +1699,8 @@ set_rest: n->kind = VAR_SET_MULTI; n->name = "SESSION CHARACTERISTICS"; n->args = $5; + n->jumble_args = true; + n->location = -1; $$ = n; } | set_rest_more @@ -1715,6 +1714,7 @@ generic_set: n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; + n->location = @3; $$ = n; } | var_name '=' var_list @@ -1724,6 +1724,7 @@ generic_set: n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; + n->location = @3; $$ = n; } | var_name TO DEFAULT @@ -1732,6 +1733,7 @@ generic_set: n->kind = VAR_SET_DEFAULT; n->name = $1; + n->location = -1; $$ = n; } | var_name '=' DEFAULT @@ -1740,6 +1742,7 @@ generic_set: n->kind = VAR_SET_DEFAULT; n->name = $1; + n->location = -1; $$ = n; } ; @@ -1752,6 +1755,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_CURRENT; n->name = $1; + n->location = -1; $$ = n; } /* Special syntaxes mandated by SQL standard: */ @@ -1761,6 +1765,8 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "timezone"; + n->location = -1; + n->jumble_args = true; if ($3 != NULL) n->args = list_make1($3); else @@ -1782,6 +1788,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "search_path"; n->args = list_make1(makeStringConst($2, @2)); + n->location = @2; $$ = n; } | NAMES opt_encoding @@ -1790,6 +1797,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "client_encoding"; + n->location = @2; if ($2 != NULL) n->args = list_make1(makeStringConst($2, @2)); else @@ -1803,6 +1811,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "role"; n->args = list_make1(makeStringConst($2, @2)); + n->location = @2; $$ = n; } | SESSION AUTHORIZATION NonReservedWord_or_Sconst @@ -1812,6 +1821,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "session_authorization"; n->args = list_make1(makeStringConst($3, @3)); + n->location = @3; $$ = n; } | SESSION AUTHORIZATION DEFAULT @@ -1820,6 +1830,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_DEFAULT; n->name = "session_authorization"; + n->location = -1; $$ = n; } | XML_P OPTION document_or_content @@ -1829,6 +1840,8 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "xmloption"; n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3)); + n->jumble_args = true; + n->location = -1; $$ = n; } /* Special syntaxes invented by PostgreSQL: */ @@ -1839,13 +1852,14 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_MULTI; n->name = "TRANSACTION SNAPSHOT"; n->args = list_make1(makeStringConst($3, @3)); + n->location = @3; $$ = n; } /* PGPOOL CACHE DELETE */ | SET CACHE DELETE_P Sconst { VariableSetStmt *n = makeNode(VariableSetStmt); - n->name = $4; /* query to delete query cache */ + n->name = $4; /* query to delete query cache */ $$ = n; } ; @@ -1959,6 +1973,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "timezone"; + n->location = -1; $$ = n; } | TRANSACTION ISOLATION LEVEL @@ -1967,6 +1982,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "transaction_isolation"; + n->location = -1; $$ = n; } | SESSION AUTHORIZATION @@ -1975,6 +1991,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "session_authorization"; + n->location = -1; $$ = n; } ; @@ -1986,6 +2003,7 @@ generic_reset: n->kind = VAR_RESET; n->name = $1; + n->location = -1; $$ = n; } | ALL @@ -1993,6 +2011,7 @@ generic_reset: VariableSetStmt *n = makeNode(VariableSetStmt); n->kind = VAR_RESET_ALL; + n->location = -1; $$ = n; } ; @@ -2715,15 +2734,45 @@ alter_table_cmd: | ALTER CONSTRAINT name ConstraintAttributeSpec { AlterTableCmd *n = makeNode(AlterTableCmd); - Constraint *c = makeNode(Constraint); + ATAlterConstraint *c = makeNode(ATAlterConstraint); + n->subtype = AT_AlterConstraint; n->def = (Node *) c; - c->contype = CONSTR_FOREIGN; /* others not supported, yet */ c->conname = $3; - processCASbits($4, @4, "ALTER CONSTRAINT statement", + if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED)) + c->alterEnforceability = true; + if ($4 & (CAS_DEFERRABLE | CAS_NOT_DEFERRABLE | + CAS_INITIALLY_DEFERRED | CAS_INITIALLY_IMMEDIATE)) + c->alterDeferrability = true; + if ($4 & CAS_NO_INHERIT) + c->alterInheritability = true; + /* handle unsupported case with specific error message */ + if ($4 & CAS_NOT_VALID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("constraints cannot be altered to be NOT VALID"), + parser_errposition(@4))); + processCASbits($4, @4, "FOREIGN KEY", &c->deferrable, &c->initdeferred, - NULL, NULL, yyscanner); + &c->is_enforced, + NULL, + &c->noinherit, + yyscanner); + $$ = (Node *) n; + } + /* ALTER TABLE <name> ALTER CONSTRAINT INHERIT */ + | ALTER CONSTRAINT name INHERIT + { + AlterTableCmd *n = makeNode(AlterTableCmd); + ATAlterConstraint *c = makeNode(ATAlterConstraint); + + n->subtype = AT_AlterConstraint; + n->def = (Node *) c; + c->conname = $3; + c->alterInheritability = true; + c->noinherit = false; + $$ = (Node *) n; } /* ALTER TABLE <name> VALIDATE CONSTRAINT ... */ @@ -3214,11 +3263,13 @@ PartitionBoundSpec: if (n->modulus == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("modulus for hash partition must be specified"))); + errmsg("modulus for hash partition must be specified"), + parser_errposition(@3))); if (n->remainder == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("remainder for hash partition must be specified"))); + errmsg("remainder for hash partition must be specified"), + parser_errposition(@3))); n->location = @3; @@ -3970,12 +4021,16 @@ ColConstraint: * or be part of a_expr NOT LIKE or similar constructs). */ ColConstraintElem: - NOT NULL_P + NOT NULL_P opt_no_inherit { Constraint *n = makeNode(Constraint); n->contype = CONSTR_NOTNULL; n->location = @1; + n->is_no_inherit = $3; + n->is_enforced = true; + n->skip_validation = false; + n->initially_valid = true; $$ = (Node *) n; } | NULL_P @@ -4020,6 +4075,7 @@ ColConstraintElem: n->is_no_inherit = $5; n->raw_expr = $3; n->cooked_expr = NULL; + n->is_enforced = true; n->skip_validation = false; n->initially_valid = true; $$ = (Node *) n; @@ -4046,7 +4102,7 @@ ColConstraintElem: n->location = @1; $$ = (Node *) n; } - | GENERATED generated_when AS '(' a_expr ')' STORED + | GENERATED generated_when AS '(' a_expr ')' opt_virtual_or_stored { Constraint *n = makeNode(Constraint); @@ -4054,6 +4110,7 @@ ColConstraintElem: n->generated_when = $2; n->raw_expr = $5; n->cooked_expr = NULL; + n->generated_kind = $7; n->location = @1; /* @@ -4083,6 +4140,7 @@ ColConstraintElem: n->fk_upd_action = ($5)->updateAction->action; n->fk_del_action = ($5)->deleteAction->action; n->fk_del_set_cols = ($5)->deleteAction->cols; + n->is_enforced = true; n->skip_validation = false; n->initially_valid = true; $$ = (Node *) n; @@ -4100,6 +4158,12 @@ generated_when: | BY DEFAULT { $$ = ATTRIBUTE_IDENTITY_BY_DEFAULT; } ; +opt_virtual_or_stored: + STORED { $$ = ATTRIBUTE_GENERATED_STORED; } + | VIRTUAL { $$ = ATTRIBUTE_GENERATED_VIRTUAL; } + | /*EMPTY*/ { $$ = ATTRIBUTE_GENERATED_VIRTUAL; } + ; + /* * ConstraintAttr represents constraint attributes, which we parse as if * they were independent constraint clauses, in order to avoid shift/reduce @@ -4148,6 +4212,22 @@ ConstraintAttr: n->location = @1; $$ = (Node *) n; } + | ENFORCED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_ATTR_ENFORCED; + n->location = @1; + $$ = (Node *) n; + } + | NOT ENFORCED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_ATTR_NOT_ENFORCED; + n->location = @1; + $$ = (Node *) n; + } ; @@ -4209,12 +4289,25 @@ ConstraintElem: n->raw_expr = $3; n->cooked_expr = NULL; processCASbits($5, @5, "CHECK", - NULL, NULL, &n->skip_validation, + NULL, NULL, &n->is_enforced, &n->skip_validation, &n->is_no_inherit, yyscanner); n->initially_valid = !n->skip_validation; $$ = (Node *) n; } - | UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + | NOT NULL_P ColId ConstraintAttributeSpec + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_NOTNULL; + n->location = @1; + n->keys = list_make1(makeString($3)); + processCASbits($4, @4, "NOT NULL", + NULL, NULL, NULL, &n->skip_validation, + &n->is_no_inherit, yyscanner); + n->initially_valid = !n->skip_validation; + $$ = (Node *) n; + } + | UNIQUE opt_unique_null_treatment '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4223,13 +4316,14 @@ ConstraintElem: n->location = @1; n->nulls_not_distinct = !$2; n->keys = $4; - n->including = $6; - n->options = $7; + n->without_overlaps = $5; + n->including = $7; + n->options = $8; n->indexname = NULL; - n->indexspace = $8; - processCASbits($9, @9, "UNIQUE", + n->indexspace = $9; + processCASbits($10, @10, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | UNIQUE ExistingIndex ConstraintAttributeSpec @@ -4245,10 +4339,10 @@ ConstraintElem: n->indexspace = NULL; processCASbits($3, @3, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } - | PRIMARY KEY '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + | PRIMARY KEY '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4256,13 +4350,14 @@ ConstraintElem: n->contype = CONSTR_PRIMARY; n->location = @1; n->keys = $4; - n->including = $6; - n->options = $7; + n->without_overlaps = $5; + n->including = $7; + n->options = $8; n->indexname = NULL; - n->indexspace = $8; - processCASbits($9, @9, "PRIMARY KEY", + n->indexspace = $9; + processCASbits($10, @10, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | PRIMARY KEY ExistingIndex ConstraintAttributeSpec @@ -4278,7 +4373,7 @@ ConstraintElem: n->indexspace = NULL; processCASbits($4, @4, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | EXCLUDE access_method_clause '(' ExclusionConstraintList ')' @@ -4298,26 +4393,36 @@ ConstraintElem: n->where_clause = $9; processCASbits($10, @10, "EXCLUDE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } - | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name - opt_column_list key_match key_actions ConstraintAttributeSpec + | FOREIGN KEY '(' columnList optionalPeriodName ')' REFERENCES qualified_name + opt_column_and_period_list key_match key_actions ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); n->contype = CONSTR_FOREIGN; n->location = @1; - n->pktable = $7; + n->pktable = $8; n->fk_attrs = $4; - n->pk_attrs = $8; - n->fk_matchtype = $9; - n->fk_upd_action = ($10)->updateAction->action; - n->fk_del_action = ($10)->deleteAction->action; - n->fk_del_set_cols = ($10)->deleteAction->cols; - processCASbits($11, @11, "FOREIGN KEY", + if ($5) + { + n->fk_attrs = lappend(n->fk_attrs, $5); + n->fk_with_period = true; + } + n->pk_attrs = linitial($9); + if (lsecond($9)) + { + n->pk_attrs = lappend(n->pk_attrs, lsecond($9)); + n->pk_with_period = true; + } + n->fk_matchtype = $10; + n->fk_upd_action = ($11)->updateAction->action; + n->fk_del_action = ($11)->deleteAction->action; + n->fk_del_set_cols = ($11)->deleteAction->cols; + processCASbits($12, @12, "FOREIGN KEY", &n->deferrable, &n->initdeferred, - &n->skip_validation, NULL, + &n->is_enforced, &n->skip_validation, NULL, yyscanner); n->initially_valid = !n->skip_validation; $$ = (Node *) n; @@ -4357,8 +4462,9 @@ DomainConstraintElem: n->raw_expr = $3; n->cooked_expr = NULL; processCASbits($5, @5, "CHECK", - NULL, NULL, &n->skip_validation, + NULL, NULL, NULL, &n->skip_validation, &n->is_no_inherit, yyscanner); + n->is_enforced = true; n->initially_valid = !n->skip_validation; $$ = (Node *) n; } @@ -4369,10 +4475,10 @@ DomainConstraintElem: n->contype = CONSTR_NOTNULL; n->location = @1; n->keys = list_make1(makeString("value")); - /* no NOT VALID support yet */ + /* no NOT VALID, NO INHERIT support */ processCASbits($3, @3, "NOT NULL", NULL, NULL, NULL, - &n->is_no_inherit, yyscanner); + NULL, NULL, yyscanner); n->initially_valid = true; $$ = (Node *) n; } @@ -4382,6 +4488,11 @@ opt_no_inherit: NO INHERIT { $$ = true; } | /* EMPTY */ { $$ = false; } ; +opt_without_overlaps: + WITHOUT OVERLAPS { $$ = true; } + | /*EMPTY*/ { $$ = false; } + ; + opt_column_list: '(' columnList ')' { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } @@ -4392,6 +4503,16 @@ columnList: | columnList ',' columnElem { $$ = lappend($1, $3); } ; +optionalPeriodName: + ',' PERIOD columnElem { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + +opt_column_and_period_list: + '(' columnList optionalPeriodName ')' { $$ = list_make2($2, $3); } + | /*EMPTY*/ { $$ = list_make2(NIL, NULL); } + ; + columnElem: ColId { $$ = (Node *) makeString($1); @@ -4571,7 +4692,7 @@ PartitionSpec: PARTITION BY ColId '(' part_params ')' { PartitionSpec *n = makeNode(PartitionSpec); - n->strategy = parsePartitionStrategy($3); + n->strategy = parsePartitionStrategy($3, @3, yyscanner); n->partParams = $5; n->location = @1; @@ -4981,6 +5102,10 @@ SeqOptElem: AS SimpleTypename { $$ = makeDefElem("increment", (Node *) $3, @1); } + | LOGGED + { + $$ = makeDefElem("logged", NULL, @1); + } | MAXVALUE NumericOnly { $$ = makeDefElem("maxvalue", (Node *) $2, @1); @@ -5003,7 +5128,6 @@ SeqOptElem: AS SimpleTypename } | SEQUENCE NAME_P any_name { - /* not documented, only used by pg_dump */ $$ = makeDefElem("sequence_name", (Node *) $3, @1); } | START opt_with NumericOnly @@ -5018,6 +5142,10 @@ SeqOptElem: AS SimpleTypename { $$ = makeDefElem("restart", (Node *) $3, @1); } + | UNLOGGED + { + $$ = makeDefElem("unlogged", NULL, @1); + } ; opt_by: BY @@ -5998,7 +6126,8 @@ CreateTrigStmt: if (n->replace) /* not supported, see CreateTrigger */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"))); + errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"), + parser_errposition(@1))); n->isconstraint = true; n->trigname = $5; n->relation = $9; @@ -6012,7 +6141,7 @@ CreateTrigStmt: n->transitionRels = NIL; processCASbits($11, @11, "TRIGGER", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); n->constrrel = $10; $$ = (Node *) n; } @@ -6181,7 +6310,8 @@ ConstraintAttributeSpec: parser_errposition(@2))); /* generic message for other conflicts */ if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) || - (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) + (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED) || + (newspec & (CAS_NOT_ENFORCED | CAS_ENFORCED)) == (CAS_NOT_ENFORCED | CAS_ENFORCED)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting constraint properties"), @@ -6197,6 +6327,8 @@ ConstraintAttributeElem: | INITIALLY DEFERRED { $$ = CAS_INITIALLY_DEFERRED; } | NOT VALID { $$ = CAS_NOT_VALID; } | NO INHERIT { $$ = CAS_NO_INHERIT; } + | NOT ENFORCED { $$ = CAS_NOT_ENFORCED; } + | ENFORCED { $$ = CAS_ENFORCED; } ; @@ -6283,7 +6415,8 @@ CreateAssertionStmt: { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE ASSERTION is not yet implemented"))); + errmsg("CREATE ASSERTION is not yet implemented"), + parser_errposition(@1))); $$ = NULL; } @@ -6643,7 +6776,7 @@ opclass_item_list: ; opclass_item: - OPERATOR Iconst any_operator opclass_purpose opt_recheck + OPERATOR Iconst any_operator opclass_purpose { CreateOpClassItem *n = makeNode(CreateOpClassItem); ObjectWithArgs *owa = makeNode(ObjectWithArgs); @@ -6657,7 +6790,6 @@ opclass_item: $$ = (Node *) n; } | OPERATOR Iconst operator_with_argtypes opclass_purpose - opt_recheck { CreateOpClassItem *n = makeNode(CreateOpClassItem); @@ -6709,23 +6841,6 @@ opclass_purpose: FOR SEARCH { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; } ; -opt_recheck: RECHECK - { - /* - * RECHECK no longer does anything in opclass definitions, - * but we still accept it to ease porting of old database - * dumps. - */ - ereport(NOTICE, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("RECHECK is no longer required"), - errhint("Update your data type."), - parser_errposition(@1))); - $$ = true; - } - | /*EMPTY*/ { $$ = false; } - ; - CreateOpFamilyStmt: CREATE OPERATOR FAMILY any_name USING name @@ -8145,6 +8260,7 @@ defacl_privilege_target: | SEQUENCES { $$ = OBJECT_SEQUENCE; } | TYPES_P { $$ = OBJECT_TYPE; } | SCHEMAS { $$ = OBJECT_SCHEMA; } + | LARGE_P OBJECTS_P { $$ = OBJECT_LARGEOBJECT; } ; @@ -8344,7 +8460,7 @@ CreateFunctionStmt: n->is_procedure = false; n->replace = $2; n->funcname = $4; - n->parameters = mergeTableFuncParameters($5, $9); + n->parameters = mergeTableFuncParameters($5, $9, yyscanner); n->returnType = TableFuncTypeName($9); n->returnType->location = @7; n->options = $11; @@ -8477,6 +8593,7 @@ func_arg: n->argType = $3; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name arg_class func_type @@ -8487,6 +8604,7 @@ func_arg: n->argType = $3; n->mode = $2; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name func_type @@ -8497,6 +8615,7 @@ func_arg: n->argType = $2; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } | arg_class func_type @@ -8507,6 +8626,7 @@ func_arg: n->argType = $2; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | func_type @@ -8517,6 +8637,7 @@ func_arg: n->argType = $1; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -8853,6 +8974,7 @@ table_func_column: param_name func_type n->argType = $2; n->mode = FUNC_PARAM_TABLE; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -11977,7 +12099,7 @@ opt_name_list: ; vacuum_relation: - qualified_name opt_name_list + relation_expr opt_name_list { $$ = (Node *) makeVacuumRelation($1, InvalidOid, $2); } @@ -12200,7 +12322,7 @@ InsertStmt: { $5->relation = $4; $5->onConflictClause = $6; - $5->returningList = $7; + $5->returningClause = $7; $5->withClause = $1; $$ = (Node *) $5; } @@ -12333,8 +12455,45 @@ opt_conf_expr: ; returning_clause: - RETURNING target_list { $$ = $2; } - | /* EMPTY */ { $$ = NIL; } + RETURNING returning_with_clause target_list + { + ReturningClause *n = makeNode(ReturningClause); + + n->options = $2; + n->exprs = $3; + $$ = n; + } + | /* EMPTY */ + { + $$ = NULL; + } + ; + +returning_with_clause: + WITH '(' returning_options ')' { $$ = $3; } + | /* EMPTY */ { $$ = NIL; } + ; + +returning_options: + returning_option { $$ = list_make1($1); } + | returning_options ',' returning_option { $$ = lappend($1, $3); } + ; + +returning_option: + returning_option_kind AS ColId + { + ReturningOption *n = makeNode(ReturningOption); + + n->option = $1; + n->value = $3; + n->location = @1; + $$ = (Node *) n; + } + ; + +returning_option_kind: + OLD { $$ = RETURNING_OPTION_OLD; } + | NEW { $$ = RETURNING_OPTION_NEW; } ; @@ -12353,7 +12512,7 @@ DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias n->relation = $4; n->usingClause = $5; n->whereClause = $6; - n->returningList = $7; + n->returningClause = $7; n->withClause = $1; $$ = (Node *) n; } @@ -12427,7 +12586,7 @@ UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias n->targetList = $5; n->fromClause = $6; n->whereClause = $7; - n->returningList = $8; + n->returningClause = $8; n->withClause = $1; $$ = (Node *) n; } @@ -12504,7 +12663,7 @@ MergeStmt: m->sourceRelation = $6; m->joinCondition = $8; m->mergeWhenClauses = $9; - m->returningList = $10; + m->returningClause = $10; $$ = (Node *) m; } @@ -13183,11 +13342,13 @@ select_limit: { $$ = $1; ($$)->limitOffset = $2; + ($$)->offsetLoc = @2; } | offset_clause limit_clause { $$ = $2; ($$)->limitOffset = $1; + ($$)->offsetLoc = @1; } | limit_clause { @@ -13200,6 +13361,9 @@ select_limit: n->limitOffset = $1; n->limitCount = NULL; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = @1; + n->countLoc = -1; + n->optionLoc = -1; $$ = n; } ; @@ -13217,6 +13381,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $2; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | LIMIT select_limit_value ',' select_offset_value @@ -13242,6 +13409,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES @@ -13251,6 +13421,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_WITH_TIES; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = @5; $$ = n; } | FETCH first_or_next row_or_rows ONLY @@ -13260,6 +13433,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | FETCH first_or_next row_or_rows WITH TIES @@ -13269,6 +13445,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_WITH_TIES; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = @4; $$ = n; } ; @@ -14113,7 +14292,7 @@ xmltable_column_el: 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, @@ -14156,13 +14335,20 @@ xmltable_column_option_list: xmltable_column_option_el: IDENT b_expr - { $$ = makeDefElem($1, $2, @1); } + { + if (strcmp($1, "__pg__is_not_null") == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("option name \"%s\" cannot be used in XMLTABLE", $1), + parser_errposition(@1))); + $$ = makeDefElem($1, $2, @1); + } | DEFAULT b_expr { $$ = makeDefElem("default", $2, @1); } | NOT NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); } + { $$ = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(true), @1); } | NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); } + { $$ = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(false), @1); } | PATH b_expr { $$ = makeDefElem("path", $2, @1); } ; @@ -15163,49 +15349,50 @@ a_expr: c_expr { $$ = $1; } (Node *) list_make2($5, $7), @2); } - | a_expr IN_P in_expr + | a_expr IN_P select_with_parens { - /* in_expr returns a SubLink or a list of a_exprs */ - if (IsA($3, SubLink)) - { - /* generate foo = ANY (subquery) */ - SubLink *n = (SubLink *) $3; + /* generate foo = ANY (subquery) */ + SubLink *n = makeNode(SubLink); - n->subLinkType = ANY_SUBLINK; - n->subLinkId = 0; - n->testexpr = $1; - n->operName = NIL; /* show it's IN not = ANY */ - n->location = @2; - $$ = (Node *) n; - } - else - { - /* generate scalar IN expression */ - $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2); - } + n->subselect = $3; + n->subLinkType = ANY_SUBLINK; + n->subLinkId = 0; + n->testexpr = $1; + n->operName = NIL; /* show it's IN not = ANY */ + n->location = @2; + $$ = (Node *) n; } - | a_expr NOT_LA IN_P in_expr %prec NOT_LA + | a_expr IN_P '(' expr_list ')' { - /* in_expr returns a SubLink or a list of a_exprs */ - if (IsA($4, SubLink)) - { - /* generate NOT (foo = ANY (subquery)) */ - /* Make an = ANY node */ - SubLink *n = (SubLink *) $4; - - n->subLinkType = ANY_SUBLINK; - n->subLinkId = 0; - n->testexpr = $1; - n->operName = NIL; /* show it's IN not = ANY */ - n->location = @2; - /* Stick a NOT on top; must have same parse location */ - $$ = makeNotExpr((Node *) n, @2); - } - else - { - /* generate scalar NOT IN expression */ - $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2); - } + /* generate scalar IN expression */ + A_Expr *n = makeSimpleA_Expr(AEXPR_IN, "=", $1, (Node *) $4, @2); + + n->rexpr_list_start = @3; + n->rexpr_list_end = @5; + $$ = (Node *) n; + } + | a_expr NOT_LA IN_P select_with_parens %prec NOT_LA + { + /* generate NOT (foo = ANY (subquery)) */ + SubLink *n = makeNode(SubLink); + + n->subselect = $4; + n->subLinkType = ANY_SUBLINK; + n->subLinkId = 0; + n->testexpr = $1; + n->operName = NIL; /* show it's IN not = ANY */ + n->location = @2; + /* Stick a NOT on top; must have same parse location */ + $$ = makeNotExpr((Node *) n, @2); + } + | a_expr NOT_LA IN_P '(' expr_list ')' + { + /* generate scalar NOT IN expression */ + A_Expr *n = makeSimpleA_Expr(AEXPR_IN, "<>", $1, (Node *) $5, @2); + + n->rexpr_list_start = @4; + n->rexpr_list_end = @6; + $$ = (Node *) n; } | a_expr subquery_Op sub_type select_with_parens %prec Op { @@ -16640,15 +16827,15 @@ type_list: Typename { $$ = list_make1($1); } array_expr: '[' expr_list ']' { - $$ = makeAArrayExpr($2, @1); + $$ = makeAArrayExpr($2, @1, @3); } | '[' array_expr_list ']' { - $$ = makeAArrayExpr($2, @1); + $$ = makeAArrayExpr($2, @1, @3); } | '[' ']' { - $$ = makeAArrayExpr(NIL, @1); + $$ = makeAArrayExpr(NIL, @1, @2); } ; @@ -16770,17 +16957,6 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); } | expr_list { $$ = $1; } ; -in_expr: select_with_parens - { - SubLink *n = makeNode(SubLink); - - n->subselect = $1; - /* other fields will be filled later */ - $$ = (Node *) n; - } - | '(' expr_list ')' { $$ = (Node *) $2; } - ; - /* * Define SQL-style CASE clause. * - Full specification @@ -16981,7 +17157,8 @@ json_format_clause: else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized JSON encoding: %s", $4))); + errmsg("unrecognized JSON encoding: %s", $4), + parser_errposition(@4))); $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, encoding, @1); } @@ -17483,7 +17660,8 @@ PLpgSQL_Expr: opt_distinct_clause opt_target_list $9->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition($9->optionLoc))); n->limitOption = $9->limitOption; } n->lockingClause = $10; @@ -17667,6 +17845,7 @@ unreserved_keyword: | ENABLE_P | ENCODING | ENCRYPTED + | ENFORCED | ENUM_P | ERROR_P | ESCAPE @@ -17762,6 +17941,7 @@ unreserved_keyword: | NOWAIT | NULLS_P | OBJECT_P + | OBJECTS_P | OF | OFF | OIDS @@ -17784,6 +17964,7 @@ unreserved_keyword: | PASSING | PASSWORD | PATH + | PERIOD | PLAN | PLANS | POLICY @@ -17803,7 +17984,6 @@ unreserved_keyword: | RANGE | READ | REASSIGN - | RECHECK | RECURSIVE | REF_P | REFERENCING @@ -17900,6 +18080,7 @@ unreserved_keyword: | VERSION_P | VIEW | VIEWS + | VIRTUAL | VOLATILE | WHITESPACE_P | WITHIN @@ -18244,6 +18425,7 @@ bare_label_keyword: | ENCODING | ENCRYPTED | END_P + | ENFORCED | ENUM_P | ERROR_P | ESCAPE @@ -18382,6 +18564,7 @@ bare_label_keyword: | NULLS_P | NUMERIC | OBJECT_P + | OBJECTS_P | OF | OFF | OIDS @@ -18408,6 +18591,7 @@ bare_label_keyword: | PASSING | PASSWORD | PATH + | PERIOD | PLACING | PLAN | PLANS @@ -18431,7 +18615,6 @@ bare_label_keyword: | READ | REAL | REASSIGN - | RECHECK | RECURSIVE | REF_P | REFERENCES @@ -18554,6 +18737,7 @@ bare_label_keyword: | VERSION_P | VIEW | VIEWS + | VIRTUAL | VOLATILE | WHEN | WHITESPACE_P @@ -18621,10 +18805,10 @@ makeColumnRef(char *colname, List *indirection, int location, core_yyscan_t yyscanner) { /* - * Generate a ColumnRef node, with an A_Indirection node added if there - * is any subscripting in the specified indirection list. However, - * any field selection at the start of the indirection list must be - * transposed into the "fields" part of the ColumnRef node. + * Generate a ColumnRef node, with an A_Indirection node added if there is + * any subscripting in the specified indirection list. However, any field + * selection at the start of the indirection list must be transposed into + * the "fields" part of the ColumnRef node. */ ColumnRef *c = makeNode(ColumnRef); int nfields = 0; @@ -18696,7 +18880,7 @@ makeIntConst(int val, int location) n->val.ival.ival = val; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * @@ -18708,42 +18892,42 @@ makeFloatConst(char *str, int location) n->val.fval.fval = str; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * makeBoolAConst(bool state, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.boolval.type = T_Boolean; n->val.boolval.boolval = state; n->location = location; - return (Node *) n; + return (Node *) n; } static Node * makeBitStringConst(char *str, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.bsval.type = T_BitString; n->val.bsval.bsval = str; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * makeNullAConst(int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->isnull = true; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * @@ -18827,7 +19011,7 @@ check_func_name(List *names, core_yyscan_t yyscanner) static List * check_indirection(List *indirection, core_yyscan_t yyscanner) { - ListCell *l; + ListCell *l; foreach(l, indirection) { @@ -18882,7 +19066,7 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, core_yyscan_t yyscanner) { FunctionParameter *lastd = (FunctionParameter *) llast(directargs); - Integer *ndirectargs; + Integer *ndirectargs; /* No restriction unless last direct arg is VARIADIC */ if (lastd->mode == FUNC_PARAM_VARIADIC) @@ -18890,15 +19074,15 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, FunctionParameter *firsto = (FunctionParameter *) linitial(orderedargs); /* - * We ignore the names, though the aggr_arg production allows them; - * it doesn't allow default values, so those need not be checked. + * We ignore the names, though the aggr_arg production allows them; it + * doesn't allow default values, so those need not be checked. */ if (list_length(orderedargs) != 1 || firsto->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"), - parser_errposition(exprLocation((Node *) firsto)))); + parser_errposition(firsto->location))); /* OK, drop the duplicate VARIADIC argument from the internal form */ orderedargs = NIL; @@ -18946,7 +19130,7 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple OFFSET clauses not allowed"), - parser_errposition(exprLocation(limitClause->limitOffset)))); + parser_errposition(limitClause->offsetLoc))); stmt->limitOffset = limitClause->limitOffset; } if (limitClause && limitClause->limitCount) @@ -18955,19 +19139,18 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple LIMIT clauses not allowed"), - parser_errposition(exprLocation(limitClause->limitCount)))); + parser_errposition(limitClause->countLoc))); stmt->limitCount = limitClause->limitCount; } if (limitClause) { - if (stmt->limitOption) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple limit options not allowed"))); + /* If there was a conflict, we must have detected it above */ + Assert(!stmt->limitOption); if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition(limitClause->optionLoc))); if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause) { ListCell *lc; @@ -18980,7 +19163,8 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s and %s options cannot be used together", - "SKIP LOCKED", "WITH TIES"))); + "SKIP LOCKED", "WITH TIES"), + parser_errposition(limitClause->optionLoc))); } } stmt->limitOption = limitClause->limitOption; @@ -19047,7 +19231,7 @@ doNegate(Node *n, int location) { if (IsA(n, A_Const)) { - A_Const *con = (A_Const *) n; + A_Const *con = (A_Const *) n; /* report the constant's location as that of the '-' sign */ con->location = location; @@ -19075,7 +19259,7 @@ doNegateFloat(Float *v) if (*oldval == '+') oldval++; if (*oldval == '-') - v->fval = oldval+1; /* just strip the '-' */ + v->fval = oldval + 1; /* just strip the '-' */ else v->fval = psprintf("-%s", oldval); } @@ -19121,12 +19305,14 @@ makeNotExpr(Node *expr, int location) } static Node * -makeAArrayExpr(List *elements, int location) +makeAArrayExpr(List *elements, int location, int location_end) { A_ArrayExpr *n = makeNode(A_ArrayExpr); n->elements = elements; n->location = location; + n->list_start = location; + n->list_end = location_end; return (Node *) n; } @@ -19146,10 +19332,11 @@ static Node * makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location) { - XmlExpr *x = makeNode(XmlExpr); + XmlExpr *x = makeNode(XmlExpr); x->op = op; x->name = name; + /* * named_args is a list of ResTarget; it'll be split apart into separate * expression and name lists in transformXmlExpr(). @@ -19159,7 +19346,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, x->args = args; /* xmloption, if relevant, must be filled in by caller */ /* type and typmod will be filled in during parse analysis */ - x->type = InvalidOid; /* marks the node as not analyzed */ + x->type = InvalidOid; /* marks the node as not analyzed */ x->location = location; return (Node *) x; } @@ -19168,7 +19355,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, * Merge the input and output parameters of a table function. */ static List * -mergeTableFuncParameters(List *func_args, List *columns) +mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner) { ListCell *lc; @@ -19182,7 +19369,8 @@ mergeTableFuncParameters(List *func_args, List *columns) p->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"))); + errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"), + parser_errposition(p->location))); } return list_concat(func_args, columns); @@ -19283,7 +19471,7 @@ makeRangeVarFromQualifiedName(char *name, List *namelist, int location, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", NameListToString(lcons(makeString(name), namelist))), - parser_errposition(location))); + parser_errposition(location))); break; } @@ -19334,8 +19522,8 @@ SplitColQualList(List *qualList, */ static void processCASbits(int cas_bits, int location, const char *constrType, - bool *deferrable, bool *initdeferred, bool *not_valid, - bool *no_inherit, core_yyscan_t yyscanner) + bool *deferrable, bool *initdeferred, bool *is_enforced, + bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner) { /* defaults */ if (deferrable) @@ -19344,6 +19532,8 @@ processCASbits(int cas_bits, int location, const char *constrType, *initdeferred = false; if (not_valid) *not_valid = false; + if (is_enforced) + *is_enforced = true; if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED)) { @@ -19352,7 +19542,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); @@ -19365,7 +19555,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); @@ -19378,7 +19568,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NOT VALID", constrType), parser_errposition(location))); @@ -19391,11 +19581,46 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NO INHERIT", constrType), parser_errposition(location))); } + + if (cas_bits & CAS_NOT_ENFORCED) + { + if (is_enforced) + *is_enforced = false; + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is CHECK, UNIQUE, or similar */ + errmsg("%s constraints cannot be marked NOT ENFORCED", + constrType), + parser_errposition(location))); + + /* + * NB: The validated status is irrelevant when the constraint is set to + * NOT ENFORCED, but for consistency, it should be set accordingly. + * This ensures that if the constraint is later changed to ENFORCED, it + * will automatically be in the correct NOT VALIDATED state. + */ + if (not_valid) + *not_valid = true; + } + + if (cas_bits & CAS_ENFORCED) + { + if (is_enforced) + *is_enforced = true; + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is CHECK, UNIQUE, or similar */ + errmsg("%s constraints cannot be marked ENFORCED", + constrType), + parser_errposition(location))); + } } /* @@ -19403,7 +19628,7 @@ processCASbits(int cas_bits, int location, const char *constrType, * PartitionStrategy representation, or die trying. */ static PartitionStrategy -parsePartitionStrategy(char *strategy) +parsePartitionStrategy(char *strategy, int location, core_yyscan_t yyscanner) { if (pg_strcasecmp(strategy, "list") == 0) return PARTITION_STRATEGY_LIST; @@ -19414,9 +19639,9 @@ parsePartitionStrategy(char *strategy) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized partitioning strategy \"%s\"", - strategy))); - return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ + errmsg("unrecognized partitioning strategy \"%s\"", strategy), + parser_errposition(location))); + return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ } @@ -19487,8 +19712,8 @@ preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner) parser_errposition(pubobj->location))); /* - * We can distinguish between the different type of schema - * objects based on whether name and pubtable is set. + * We can distinguish between the different type of schema objects + * based on whether name and pubtable is set. */ if (pubobj->name) pubobj->pubobjtype = PUBLICATIONOBJ_TABLES_IN_SCHEMA; @@ -19543,11 +19768,13 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) w->ctes = list_make1(cte); w->location = -1; - /* create target list for the new SELECT from the alias list of the - * recursive view specification */ - foreach (lc, aliases) + /* + * create target list for the new SELECT from the alias list of the + * recursive view specification + */ + foreach(lc, aliases) { - ResTarget *rt = makeNode(ResTarget); + ResTarget *rt = makeNode(ResTarget); rt->name = NULL; rt->indirection = NIL; @@ -19557,8 +19784,10 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) tl = lappend(tl, rt); } - /* create new SELECT combining WITH clause, target list, and fake FROM - * clause */ + /* + * create new SELECT combining WITH clause, target list, and fake FROM + * clause + */ s->withClause = w; s->targetList = tl; s->fromClause = list_make1(makeRangeVar(NULL, relname, -1)); diff --git a/src/parser/gram_minimal.y b/src/parser/gram_minimal.y index e11074e1f..dc540e1c9 100644 --- a/src/parser/gram_minimal.y +++ b/src/parser/gram_minimal.y @@ -6,8 +6,8 @@ * gram.y * POSTGRESQL BISON rules/actions * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -89,6 +89,8 @@ #define ATTRIBUTE_IDENTITY_ALWAYS 'a' #define ATTRIBUTE_IDENTITY_BY_DEFAULT 'd' +#define ATTRIBUTE_GENERATED_STORED 's' +#define ATTRIBUTE_GENERATED_VIRTUAL 'v' /* * Definition taken from * postgreSQL source code file: src/include/utils/xml.h @@ -102,40 +104,26 @@ typedef enum } XmlStandaloneType; /* - * Location tracking support --- simpler than bison's default, since we only - * want to track the start position not the end position of each nonterminal. + * Location tracking support. Unlike bison's default, we only want + * to track the start position not the end position of each nonterminal. + * Nonterminals that reduce to empty receive position "-1". Since a + * production's leading RHS nonterminal(s) may have reduced to empty, + * we have to scan to find the first one that's not -1. */ #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ - if ((N) > 0) \ - (Current) = (Rhs)[1]; \ - else \ - (Current) = (-1); \ + (Current) = (-1); \ + for (int _i = 1; _i <= (N); _i++) \ + { \ + if ((Rhs)[_i] >= 0) \ + { \ + (Current) = (Rhs)[_i]; \ + break; \ + } \ + } \ } while (0) /* - * The above macro assigns -1 (unknown) as the parse location of any - * nonterminal that was reduced from an empty rule, or whose leftmost - * component was reduced from an empty rule. This is problematic - * for nonterminals defined like - * OptFooList: / * EMPTY * / { ... } | OptFooList Foo { ... } ; - * because we'll set -1 as the location during the first reduction and then - * copy it during each subsequent reduction, leaving us with -1 for the - * location even when the list is not empty. To fix that, do this in the - * action for the nonempty rule(s): - * if (@$ < 0) @$ = @2; - * (Although we have many nonterminals that follow this pattern, we only - * bother with fixing @$ like this when the nonterminal's parse location - * is actually referenced in some rule.) - * - * A cleaner answer would be to make YYLLOC_DEFAULT scan all the Rhs - * locations until it's found one that's not -1. Then we'd get a correct - * location for any nonterminal that isn't entirely empty. But this way - * would add overhead to every rule reduction, and so far there's not been - * a compelling reason to pay that overhead. - */ - -/* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents * memory leaks if we error out during parsing. @@ -158,12 +146,15 @@ typedef struct ImportQual List *table_names; } ImportQual; -/* Private struct for the result of opt_select_limit production */ +/* Private struct for the result of select_limit & limit_clause productions */ typedef struct SelectLimit { Node *limitOffset; Node *limitCount; - LimitOption limitOption; + LimitOption limitOption; /* indicates presence of WITH TIES */ + ParseLoc offsetLoc; /* location of OFFSET token, if present */ + ParseLoc countLoc; /* location of LIMIT/FETCH token, if present */ + ParseLoc optionLoc; /* location of WITH TIES, if present */ } SelectLimit; /* Private struct for the result of group_clause production */ @@ -193,6 +184,8 @@ typedef struct KeyActions #define CAS_INITIALLY_DEFERRED 0x08 #define CAS_NOT_VALID 0x10 #define CAS_NO_INHERIT 0x20 +#define CAS_NOT_ENFORCED 0x40 +#define CAS_ENFORCED 0x80 #define parser_yyerror(msg) scanner_yyerror(msg, yyscanner) @@ -228,12 +221,12 @@ static void doNegateFloat(Float *v); static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location); static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location); static Node *makeNotExpr(Node *expr, int location); -static Node *makeAArrayExpr(List *elements, int location); +static Node *makeAArrayExpr(List *elements, int location, int end_location); static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location); static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location); -static List *mergeTableFuncParameters(List *func_args, List *columns); +static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); static RangeVar *makeRangeVarFromQualifiedName(char *name, List *namelist, int location, @@ -242,9 +235,10 @@ static void SplitColQualList(List *qualList, List **constraintList, CollateClause **collClause, core_yyscan_t yyscanner); static void processCASbits(int cas_bits, int location, const char *constrType, - bool *deferrable, bool *initdeferred, bool *not_valid, - bool *no_inherit, core_yyscan_t yyscanner); -static PartitionStrategy parsePartitionStrategy(char *strategy); + bool *deferrable, bool *initdeferred, bool *is_enforced, + bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); +static PartitionStrategy parsePartitionStrategy(char *strategy, int location, + core_yyscan_t yyscanner); static void preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); @@ -310,6 +304,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); MergeWhenClause *mergewhen; struct KeyActions *keyactions; struct KeyAction *keyaction; + ReturningClause *retclause; + ReturningOptionKind retoptionkind; } %type <node> stmt toplevel_stmt schema_stmt routine_body_stmt @@ -482,7 +478,8 @@ UpdateStmtShort opclass_purpose opt_opfamily transaction_mode_list_or_empty OptTableFuncElementList TableFuncElementList opt_type_modifiers prep_type_clause - execute_param_clause using_clause returning_clause + execute_param_clause using_clause + returning_with_clause returning_options opt_enum_val_list enum_val_list table_func_column_list create_generic_options alter_generic_options relation_expr_list dostmt_opt_list @@ -491,6 +488,9 @@ UpdateStmtShort vacuum_relation_list opt_vacuum_relation_list drop_option_list pub_obj_list +%type <retclause> returning_clause +%type <node> returning_option +%type <retoptionkind> returning_option_kind %type <node> opt_routine_body %type <groupclause> group_clause %type <list> group_by_list @@ -529,7 +529,7 @@ UpdateStmtShort %type <boolean> opt_instead %type <boolean> opt_unique opt_verbose opt_full -%type <boolean> opt_freeze opt_analyze opt_default opt_recheck +%type <boolean> opt_freeze opt_analyze opt_default %type <defelt> opt_binary copy_delimiter %type <boolean> copy_from opt_program @@ -559,14 +559,15 @@ UpdateStmtShort SetResetClause FunctionSetResetClause %type <node> TableElement TypedTableElement ConstraintElem DomainConstraintElem TableFuncElement -%type <node> columnDef columnOptions +%type <node> columnDef columnOptions optionalPeriodName %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem %type <node> def_arg columnElem where_clause where_or_current_clause a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound - columnref in_expr having_clause func_table xmltable array_expr + columnref having_clause func_table xmltable array_expr OptWhereClause operator_def_arg +%type <list> opt_column_and_period_list %type <list> rowsfrom_item rowsfrom_list opt_col_def_list -%type <boolean> opt_ordinality +%type <boolean> opt_ordinality opt_without_overlaps %type <list> ExclusionConstraintList ExclusionConstraintElem %type <list> func_arg_list func_arg_list_opt %type <node> func_arg_expr @@ -675,7 +676,7 @@ UpdateStmtShort %type <str> opt_existing_window_name %type <boolean> opt_if_not_exists %type <boolean> opt_unique_null_treatment -%type <ival> generated_when override_kind +%type <ival> generated_when override_kind opt_virtual_or_stored %type <partspec> PartitionSpec OptPartitionSpec %type <partelem> part_elem %type <list> part_params @@ -758,9 +759,9 @@ UpdateStmtShort DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP - EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERROR_P ESCAPE - EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION - EXTENSION EXTERNAL EXTRACT + EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERROR_P + ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN + EXPRESSION EXTENSION EXTERNAL EXTRACT FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS @@ -791,18 +792,18 @@ UpdateStmtShort NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC - OBJECT_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR + OBJECT_P OBJECTS_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR ORDER ORDINALITY OTHERS OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH PGPOOL - PLACING PLAN PLANS POLICY + PERIOD PLACING PLAN PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION QUOTE QUOTES - RANGE READ REAL REASSIGN RECHECK RECURSIVE REF_P REFERENCES REFERENCING + RANGE READ REAL REASSIGN RECURSIVE REF_P REFERENCES REFERENCING REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROUTINE ROUTINES ROW ROWS RULE @@ -823,7 +824,7 @@ UpdateStmtShort UNLISTEN UNLOGGED UNTIL UPDATE USER USING VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING - VERBOSE VERSION_P VIEW VIEWS VOLATILE + VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE @@ -964,7 +965,7 @@ parse_toplevel: | MODE_PLPGSQL_EXPR PLpgSQL_Expr { pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt($2, 0)); + list_make1(makeRawStmt($2, @2)); } | MODE_PLPGSQL_ASSIGN1 PLAssignStmt { @@ -972,7 +973,7 @@ parse_toplevel: n->nnames = 1; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } | MODE_PLPGSQL_ASSIGN2 PLAssignStmt { @@ -980,7 +981,7 @@ parse_toplevel: n->nnames = 2; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } | MODE_PLPGSQL_ASSIGN3 PLAssignStmt { @@ -988,19 +989,15 @@ parse_toplevel: n->nnames = 3; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } ; /* * At top level, we wrap each stmt with a RawStmt node carrying start location - * and length of the stmt's text. Notice that the start loc/len are driven - * entirely from semicolon locations (@2). It would seem natural to use - * @1 or @3 to get the true start location of a stmt, but that doesn't work - * for statements that can start with empty nonterminals (opt_with_clause is - * the main offender here); as noted in the comments for YYLLOC_DEFAULT, - * we'd get -1 for the location in such cases. - * We also take care to discard empty statements entirely. + * and length of the stmt's text. + * We also take care to discard empty statements entirely (which among other + * things dodges the problem of assigning them a location). */ stmtmulti: stmtmulti ';' toplevel_stmt { @@ -1010,14 +1007,14 @@ stmtmulti: stmtmulti ';' toplevel_stmt updateRawStmtEnd(llast_node(RawStmt, $1), @2); } if ($3 != NULL) - $$ = lappend($1, makeRawStmt($3, @2 + 1)); + $$ = lappend($1, makeRawStmt($3, @3)); else $$ = $1; } | toplevel_stmt { if ($1 != NULL) - $$ = list_make1(makeRawStmt($1, 0)); + $$ = list_make1(makeRawStmt($1, @1)); else $$ = NIL; } @@ -1618,8 +1615,6 @@ CreateSchemaStmt: OptSchemaEltList: OptSchemaEltList schema_stmt { - if (@$ < 0) /* see comments for YYLLOC_DEFAULT */ - @$ = @2; $$ = lappend($1, $2); } | /* EMPTY */ @@ -1657,6 +1652,13 @@ VariableSetStmt: n->is_local = false; $$ = (Node *) n; } + | PGPOOL set_rest_more + { + VariableSetStmt *n = $2; + n->type = T_PgpoolQueryCacheStmt; /* Hack to keep changes minimum */ + n->is_local = false; + $$ = (Node *) n; + } | SET set_rest { VariableSetStmt *n = $2; @@ -1688,6 +1690,8 @@ set_rest: n->kind = VAR_SET_MULTI; n->name = "TRANSACTION"; n->args = $2; + n->jumble_args = true; + n->location = -1; $$ = n; } | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list @@ -1697,6 +1701,8 @@ set_rest: n->kind = VAR_SET_MULTI; n->name = "SESSION CHARACTERISTICS"; n->args = $5; + n->jumble_args = true; + n->location = -1; $$ = n; } | set_rest_more @@ -1710,6 +1716,7 @@ generic_set: n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; + n->location = @3; $$ = n; } | var_name '=' var_list @@ -1719,6 +1726,7 @@ generic_set: n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; + n->location = @3; $$ = n; } | var_name TO DEFAULT @@ -1727,6 +1735,7 @@ generic_set: n->kind = VAR_SET_DEFAULT; n->name = $1; + n->location = -1; $$ = n; } | var_name '=' DEFAULT @@ -1735,6 +1744,7 @@ generic_set: n->kind = VAR_SET_DEFAULT; n->name = $1; + n->location = -1; $$ = n; } ; @@ -1747,6 +1757,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_CURRENT; n->name = $1; + n->location = -1; $$ = n; } /* Special syntaxes mandated by SQL standard: */ @@ -1756,6 +1767,8 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "timezone"; + n->location = -1; + n->jumble_args = true; if ($3 != NULL) n->args = list_make1($3); else @@ -1777,6 +1790,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "search_path"; n->args = list_make1(makeStringConst($2, @2)); + n->location = @2; $$ = n; } | NAMES opt_encoding @@ -1785,6 +1799,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "client_encoding"; + n->location = @2; if ($2 != NULL) n->args = list_make1(makeStringConst($2, @2)); else @@ -1798,6 +1813,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "role"; n->args = list_make1(makeStringConst($2, @2)); + n->location = @2; $$ = n; } | SESSION AUTHORIZATION NonReservedWord_or_Sconst @@ -1807,6 +1823,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "session_authorization"; n->args = list_make1(makeStringConst($3, @3)); + n->location = @3; $$ = n; } | SESSION AUTHORIZATION DEFAULT @@ -1815,6 +1832,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_DEFAULT; n->name = "session_authorization"; + n->location = -1; $$ = n; } | XML_P OPTION document_or_content @@ -1824,6 +1842,8 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "xmloption"; n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3)); + n->jumble_args = true; + n->location = -1; $$ = n; } /* Special syntaxes invented by PostgreSQL: */ @@ -1834,6 +1854,14 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_MULTI; n->name = "TRANSACTION SNAPSHOT"; n->args = list_make1(makeStringConst($3, @3)); + n->location = @3; + $$ = n; + } + /* PGPOOL CACHE DELETE */ + | SET CACHE DELETE_P Sconst + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->name = $4; /* query to delete query cache */ $$ = n; } ; @@ -1947,6 +1975,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "timezone"; + n->location = -1; $$ = n; } | TRANSACTION ISOLATION LEVEL @@ -1955,6 +1984,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "transaction_isolation"; + n->location = -1; $$ = n; } | SESSION AUTHORIZATION @@ -1963,6 +1993,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "session_authorization"; + n->location = -1; $$ = n; } ; @@ -1974,6 +2005,7 @@ generic_reset: n->kind = VAR_RESET; n->name = $1; + n->location = -1; $$ = n; } | ALL @@ -1981,6 +2013,7 @@ generic_reset: VariableSetStmt *n = makeNode(VariableSetStmt); n->kind = VAR_RESET_ALL; + n->location = -1; $$ = n; } ; @@ -2703,15 +2736,45 @@ alter_table_cmd: | ALTER CONSTRAINT name ConstraintAttributeSpec { AlterTableCmd *n = makeNode(AlterTableCmd); - Constraint *c = makeNode(Constraint); + ATAlterConstraint *c = makeNode(ATAlterConstraint); + n->subtype = AT_AlterConstraint; n->def = (Node *) c; - c->contype = CONSTR_FOREIGN; /* others not supported, yet */ c->conname = $3; - processCASbits($4, @4, "ALTER CONSTRAINT statement", + if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED)) + c->alterEnforceability = true; + if ($4 & (CAS_DEFERRABLE | CAS_NOT_DEFERRABLE | + CAS_INITIALLY_DEFERRED | CAS_INITIALLY_IMMEDIATE)) + c->alterDeferrability = true; + if ($4 & CAS_NO_INHERIT) + c->alterInheritability = true; + /* handle unsupported case with specific error message */ + if ($4 & CAS_NOT_VALID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("constraints cannot be altered to be NOT VALID"), + parser_errposition(@4))); + processCASbits($4, @4, "FOREIGN KEY", &c->deferrable, &c->initdeferred, - NULL, NULL, yyscanner); + &c->is_enforced, + NULL, + &c->noinherit, + yyscanner); + $$ = (Node *) n; + } + /* ALTER TABLE <name> ALTER CONSTRAINT INHERIT */ + | ALTER CONSTRAINT name INHERIT + { + AlterTableCmd *n = makeNode(AlterTableCmd); + ATAlterConstraint *c = makeNode(ATAlterConstraint); + + n->subtype = AT_AlterConstraint; + n->def = (Node *) c; + c->conname = $3; + c->alterInheritability = true; + c->noinherit = false; + $$ = (Node *) n; } /* ALTER TABLE <name> VALIDATE CONSTRAINT ... */ @@ -3202,11 +3265,13 @@ PartitionBoundSpec: if (n->modulus == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("modulus for hash partition must be specified"))); + errmsg("modulus for hash partition must be specified"), + parser_errposition(@3))); if (n->remainder == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("remainder for hash partition must be specified"))); + errmsg("remainder for hash partition must be specified"), + parser_errposition(@3))); n->location = @3; @@ -3958,12 +4023,16 @@ ColConstraint: * or be part of a_expr NOT LIKE or similar constructs). */ ColConstraintElem: - NOT NULL_P + NOT NULL_P opt_no_inherit { Constraint *n = makeNode(Constraint); n->contype = CONSTR_NOTNULL; n->location = @1; + n->is_no_inherit = $3; + n->is_enforced = true; + n->skip_validation = false; + n->initially_valid = true; $$ = (Node *) n; } | NULL_P @@ -4008,6 +4077,7 @@ ColConstraintElem: n->is_no_inherit = $5; n->raw_expr = $3; n->cooked_expr = NULL; + n->is_enforced = true; n->skip_validation = false; n->initially_valid = true; $$ = (Node *) n; @@ -4034,7 +4104,7 @@ ColConstraintElem: n->location = @1; $$ = (Node *) n; } - | GENERATED generated_when AS '(' a_expr ')' STORED + | GENERATED generated_when AS '(' a_expr ')' opt_virtual_or_stored { Constraint *n = makeNode(Constraint); @@ -4042,6 +4112,7 @@ ColConstraintElem: n->generated_when = $2; n->raw_expr = $5; n->cooked_expr = NULL; + n->generated_kind = $7; n->location = @1; /* @@ -4071,6 +4142,7 @@ ColConstraintElem: n->fk_upd_action = ($5)->updateAction->action; n->fk_del_action = ($5)->deleteAction->action; n->fk_del_set_cols = ($5)->deleteAction->cols; + n->is_enforced = true; n->skip_validation = false; n->initially_valid = true; $$ = (Node *) n; @@ -4088,6 +4160,12 @@ generated_when: | BY DEFAULT { $$ = ATTRIBUTE_IDENTITY_BY_DEFAULT; } ; +opt_virtual_or_stored: + STORED { $$ = ATTRIBUTE_GENERATED_STORED; } + | VIRTUAL { $$ = ATTRIBUTE_GENERATED_VIRTUAL; } + | /*EMPTY*/ { $$ = ATTRIBUTE_GENERATED_VIRTUAL; } + ; + /* * ConstraintAttr represents constraint attributes, which we parse as if * they were independent constraint clauses, in order to avoid shift/reduce @@ -4136,6 +4214,22 @@ ConstraintAttr: n->location = @1; $$ = (Node *) n; } + | ENFORCED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_ATTR_ENFORCED; + n->location = @1; + $$ = (Node *) n; + } + | NOT ENFORCED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_ATTR_NOT_ENFORCED; + n->location = @1; + $$ = (Node *) n; + } ; @@ -4197,12 +4291,25 @@ ConstraintElem: n->raw_expr = $3; n->cooked_expr = NULL; processCASbits($5, @5, "CHECK", - NULL, NULL, &n->skip_validation, + NULL, NULL, &n->is_enforced, &n->skip_validation, + &n->is_no_inherit, yyscanner); + n->initially_valid = !n->skip_validation; + $$ = (Node *) n; + } + | NOT NULL_P ColId ConstraintAttributeSpec + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_NOTNULL; + n->location = @1; + n->keys = list_make1(makeString($3)); + processCASbits($4, @4, "NOT NULL", + NULL, NULL, NULL, &n->skip_validation, &n->is_no_inherit, yyscanner); n->initially_valid = !n->skip_validation; $$ = (Node *) n; } - | UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + | UNIQUE opt_unique_null_treatment '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4211,13 +4318,14 @@ ConstraintElem: n->location = @1; n->nulls_not_distinct = !$2; n->keys = $4; - n->including = $6; - n->options = $7; + n->without_overlaps = $5; + n->including = $7; + n->options = $8; n->indexname = NULL; - n->indexspace = $8; - processCASbits($9, @9, "UNIQUE", + n->indexspace = $9; + processCASbits($10, @10, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | UNIQUE ExistingIndex ConstraintAttributeSpec @@ -4233,10 +4341,10 @@ ConstraintElem: n->indexspace = NULL; processCASbits($3, @3, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } - | PRIMARY KEY '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + | PRIMARY KEY '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4244,13 +4352,14 @@ ConstraintElem: n->contype = CONSTR_PRIMARY; n->location = @1; n->keys = $4; - n->including = $6; - n->options = $7; + n->without_overlaps = $5; + n->including = $7; + n->options = $8; n->indexname = NULL; - n->indexspace = $8; - processCASbits($9, @9, "PRIMARY KEY", + n->indexspace = $9; + processCASbits($10, @10, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | PRIMARY KEY ExistingIndex ConstraintAttributeSpec @@ -4266,7 +4375,7 @@ ConstraintElem: n->indexspace = NULL; processCASbits($4, @4, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | EXCLUDE access_method_clause '(' ExclusionConstraintList ')' @@ -4286,26 +4395,36 @@ ConstraintElem: n->where_clause = $9; processCASbits($10, @10, "EXCLUDE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } - | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name - opt_column_list key_match key_actions ConstraintAttributeSpec + | FOREIGN KEY '(' columnList optionalPeriodName ')' REFERENCES qualified_name + opt_column_and_period_list key_match key_actions ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); n->contype = CONSTR_FOREIGN; n->location = @1; - n->pktable = $7; + n->pktable = $8; n->fk_attrs = $4; - n->pk_attrs = $8; - n->fk_matchtype = $9; - n->fk_upd_action = ($10)->updateAction->action; - n->fk_del_action = ($10)->deleteAction->action; - n->fk_del_set_cols = ($10)->deleteAction->cols; - processCASbits($11, @11, "FOREIGN KEY", + if ($5) + { + n->fk_attrs = lappend(n->fk_attrs, $5); + n->fk_with_period = true; + } + n->pk_attrs = linitial($9); + if (lsecond($9)) + { + n->pk_attrs = lappend(n->pk_attrs, lsecond($9)); + n->pk_with_period = true; + } + n->fk_matchtype = $10; + n->fk_upd_action = ($11)->updateAction->action; + n->fk_del_action = ($11)->deleteAction->action; + n->fk_del_set_cols = ($11)->deleteAction->cols; + processCASbits($12, @12, "FOREIGN KEY", &n->deferrable, &n->initdeferred, - &n->skip_validation, NULL, + &n->is_enforced, &n->skip_validation, NULL, yyscanner); n->initially_valid = !n->skip_validation; $$ = (Node *) n; @@ -4345,8 +4464,9 @@ DomainConstraintElem: n->raw_expr = $3; n->cooked_expr = NULL; processCASbits($5, @5, "CHECK", - NULL, NULL, &n->skip_validation, + NULL, NULL, NULL, &n->skip_validation, &n->is_no_inherit, yyscanner); + n->is_enforced = true; n->initially_valid = !n->skip_validation; $$ = (Node *) n; } @@ -4357,10 +4477,10 @@ DomainConstraintElem: n->contype = CONSTR_NOTNULL; n->location = @1; n->keys = list_make1(makeString("value")); - /* no NOT VALID support yet */ + /* no NOT VALID, NO INHERIT support */ processCASbits($3, @3, "NOT NULL", NULL, NULL, NULL, - &n->is_no_inherit, yyscanner); + NULL, NULL, yyscanner); n->initially_valid = true; $$ = (Node *) n; } @@ -4370,6 +4490,11 @@ opt_no_inherit: NO INHERIT { $$ = true; } | /* EMPTY */ { $$ = false; } ; +opt_without_overlaps: + WITHOUT OVERLAPS { $$ = true; } + | /*EMPTY*/ { $$ = false; } + ; + opt_column_list: '(' columnList ')' { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } @@ -4380,6 +4505,16 @@ columnList: | columnList ',' columnElem { $$ = lappend($1, $3); } ; +optionalPeriodName: + ',' PERIOD columnElem { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + +opt_column_and_period_list: + '(' columnList optionalPeriodName ')' { $$ = list_make2($2, $3); } + | /*EMPTY*/ { $$ = list_make2(NIL, NULL); } + ; + columnElem: ColId { $$ = (Node *) makeString($1); @@ -4559,7 +4694,7 @@ PartitionSpec: PARTITION BY ColId '(' part_params ')' { PartitionSpec *n = makeNode(PartitionSpec); - n->strategy = parsePartitionStrategy($3); + n->strategy = parsePartitionStrategy($3, @3, yyscanner); n->partParams = $5; n->location = @1; @@ -4969,6 +5104,10 @@ SeqOptElem: AS SimpleTypename { $$ = makeDefElem("increment", (Node *) $3, @1); } + | LOGGED + { + $$ = makeDefElem("logged", NULL, @1); + } | MAXVALUE NumericOnly { $$ = makeDefElem("maxvalue", (Node *) $2, @1); @@ -4991,7 +5130,6 @@ SeqOptElem: AS SimpleTypename } | SEQUENCE NAME_P any_name { - /* not documented, only used by pg_dump */ $$ = makeDefElem("sequence_name", (Node *) $3, @1); } | START opt_with NumericOnly @@ -5006,6 +5144,10 @@ SeqOptElem: AS SimpleTypename { $$ = makeDefElem("restart", (Node *) $3, @1); } + | UNLOGGED + { + $$ = makeDefElem("unlogged", NULL, @1); + } ; opt_by: BY @@ -5986,7 +6128,8 @@ CreateTrigStmt: if (n->replace) /* not supported, see CreateTrigger */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"))); + errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"), + parser_errposition(@1))); n->isconstraint = true; n->trigname = $5; n->relation = $9; @@ -6000,7 +6143,7 @@ CreateTrigStmt: n->transitionRels = NIL; processCASbits($11, @11, "TRIGGER", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); n->constrrel = $10; $$ = (Node *) n; } @@ -6169,7 +6312,8 @@ ConstraintAttributeSpec: parser_errposition(@2))); /* generic message for other conflicts */ if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) || - (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) + (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED) || + (newspec & (CAS_NOT_ENFORCED | CAS_ENFORCED)) == (CAS_NOT_ENFORCED | CAS_ENFORCED)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting constraint properties"), @@ -6185,6 +6329,8 @@ ConstraintAttributeElem: | INITIALLY DEFERRED { $$ = CAS_INITIALLY_DEFERRED; } | NOT VALID { $$ = CAS_NOT_VALID; } | NO INHERIT { $$ = CAS_NO_INHERIT; } + | NOT ENFORCED { $$ = CAS_NOT_ENFORCED; } + | ENFORCED { $$ = CAS_ENFORCED; } ; @@ -6271,7 +6417,8 @@ CreateAssertionStmt: { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE ASSERTION is not yet implemented"))); + errmsg("CREATE ASSERTION is not yet implemented"), + parser_errposition(@1))); $$ = NULL; } @@ -6631,7 +6778,7 @@ opclass_item_list: ; opclass_item: - OPERATOR Iconst any_operator opclass_purpose opt_recheck + OPERATOR Iconst any_operator opclass_purpose { CreateOpClassItem *n = makeNode(CreateOpClassItem); ObjectWithArgs *owa = makeNode(ObjectWithArgs); @@ -6645,7 +6792,6 @@ opclass_item: $$ = (Node *) n; } | OPERATOR Iconst operator_with_argtypes opclass_purpose - opt_recheck { CreateOpClassItem *n = makeNode(CreateOpClassItem); @@ -6697,23 +6843,6 @@ opclass_purpose: FOR SEARCH { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; } ; -opt_recheck: RECHECK - { - /* - * RECHECK no longer does anything in opclass definitions, - * but we still accept it to ease porting of old database - * dumps. - */ - ereport(NOTICE, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("RECHECK is no longer required"), - errhint("Update your data type."), - parser_errposition(@1))); - $$ = true; - } - | /*EMPTY*/ { $$ = false; } - ; - CreateOpFamilyStmt: CREATE OPERATOR FAMILY any_name USING name @@ -8133,6 +8262,7 @@ defacl_privilege_target: | SEQUENCES { $$ = OBJECT_SEQUENCE; } | TYPES_P { $$ = OBJECT_TYPE; } | SCHEMAS { $$ = OBJECT_SCHEMA; } + | LARGE_P OBJECTS_P { $$ = OBJECT_LARGEOBJECT; } ; @@ -8332,7 +8462,7 @@ CreateFunctionStmt: n->is_procedure = false; n->replace = $2; n->funcname = $4; - n->parameters = mergeTableFuncParameters($5, $9); + n->parameters = mergeTableFuncParameters($5, $9, yyscanner); n->returnType = TableFuncTypeName($9); n->returnType->location = @7; n->options = $11; @@ -8465,6 +8595,7 @@ func_arg: n->argType = $3; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name arg_class func_type @@ -8475,6 +8606,7 @@ func_arg: n->argType = $3; n->mode = $2; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name func_type @@ -8485,6 +8617,7 @@ func_arg: n->argType = $2; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } | arg_class func_type @@ -8495,6 +8628,7 @@ func_arg: n->argType = $2; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | func_type @@ -8505,6 +8639,7 @@ func_arg: n->argType = $1; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -8841,6 +8976,7 @@ table_func_column: param_name func_type n->argType = $2; n->mode = FUNC_PARAM_TABLE; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -11965,7 +12101,7 @@ opt_name_list: ; vacuum_relation: - qualified_name opt_name_list + relation_expr opt_name_list { $$ = (Node *) makeVacuumRelation($1, InvalidOid, $2); } @@ -12188,7 +12324,7 @@ InsertStmt: { $5->relation = $4; $5->onConflictClause = $6; - $5->returningList = $7; + $5->returningClause = $7; $5->withClause = $1; $$ = (Node *) $5; } @@ -12335,8 +12471,45 @@ opt_conf_expr: ; returning_clause: - RETURNING target_list { $$ = $2; } - | /* EMPTY */ { $$ = NIL; } + RETURNING returning_with_clause target_list + { + ReturningClause *n = makeNode(ReturningClause); + + n->options = $2; + n->exprs = $3; + $$ = n; + } + | /* EMPTY */ + { + $$ = NULL; + } + ; + +returning_with_clause: + WITH '(' returning_options ')' { $$ = $3; } + | /* EMPTY */ { $$ = NIL; } + ; + +returning_options: + returning_option { $$ = list_make1($1); } + | returning_options ',' returning_option { $$ = lappend($1, $3); } + ; + +returning_option: + returning_option_kind AS ColId + { + ReturningOption *n = makeNode(ReturningOption); + + n->option = $1; + n->value = $3; + n->location = @1; + $$ = (Node *) n; + } + ; + +returning_option_kind: + OLD { $$ = RETURNING_OPTION_OLD; } + | NEW { $$ = RETURNING_OPTION_NEW; } ; @@ -12355,7 +12528,7 @@ DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias n->relation = $4; n->usingClause = $5; n->whereClause = $6; - n->returningList = $7; + n->returningClause = $7; n->withClause = $1; $$ = (Node *) n; } @@ -12429,7 +12602,7 @@ UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias n->targetList = $5; n->fromClause = $6; n->whereClause = $7; - n->returningList = $8; + n->returningClause = $8; n->withClause = $1; $$ = (Node *) n; } @@ -12441,7 +12614,7 @@ UpdateStmtShort: opt_with_clause UPDATE relation_expr_opt_alias n->targetList = NULL; n->fromClause = NULL; n->whereClause = NULL; - n->returningList = NULL; + n->returningClause = NULL; n->withClause = $1; $$ = (Node *)n; pg_yyget_extra(yyscanner)->parsetree = list_make1(makeRawStmt($$, 0)); @@ -12520,7 +12693,7 @@ MergeStmt: m->sourceRelation = $6; m->joinCondition = $8; m->mergeWhenClauses = $9; - m->returningList = $10; + m->returningClause = $10; $$ = (Node *) m; } @@ -13199,11 +13372,13 @@ select_limit: { $$ = $1; ($$)->limitOffset = $2; + ($$)->offsetLoc = @2; } | offset_clause limit_clause { $$ = $2; ($$)->limitOffset = $1; + ($$)->offsetLoc = @1; } | limit_clause { @@ -13216,6 +13391,9 @@ select_limit: n->limitOffset = $1; n->limitCount = NULL; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = @1; + n->countLoc = -1; + n->optionLoc = -1; $$ = n; } ; @@ -13233,6 +13411,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $2; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | LIMIT select_limit_value ',' select_offset_value @@ -13258,6 +13439,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES @@ -13267,6 +13451,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_WITH_TIES; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = @5; $$ = n; } | FETCH first_or_next row_or_rows ONLY @@ -13276,6 +13463,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | FETCH first_or_next row_or_rows WITH TIES @@ -13285,6 +13475,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_WITH_TIES; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = @4; $$ = n; } ; @@ -14129,7 +14322,7 @@ xmltable_column_el: 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, @@ -14172,13 +14365,20 @@ xmltable_column_option_list: xmltable_column_option_el: IDENT b_expr - { $$ = makeDefElem($1, $2, @1); } + { + if (strcmp($1, "__pg__is_not_null") == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("option name \"%s\" cannot be used in XMLTABLE", $1), + parser_errposition(@1))); + $$ = makeDefElem($1, $2, @1); + } | DEFAULT b_expr { $$ = makeDefElem("default", $2, @1); } | NOT NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); } + { $$ = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(true), @1); } | NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); } + { $$ = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(false), @1); } | PATH b_expr { $$ = makeDefElem("path", $2, @1); } ; @@ -15179,49 +15379,50 @@ a_expr: c_expr { $$ = $1; } (Node *) list_make2($5, $7), @2); } - | a_expr IN_P in_expr + | a_expr IN_P select_with_parens { - /* in_expr returns a SubLink or a list of a_exprs */ - if (IsA($3, SubLink)) - { - /* generate foo = ANY (subquery) */ - SubLink *n = (SubLink *) $3; + /* generate foo = ANY (subquery) */ + SubLink *n = makeNode(SubLink); - n->subLinkType = ANY_SUBLINK; - n->subLinkId = 0; - n->testexpr = $1; - n->operName = NIL; /* show it's IN not = ANY */ - n->location = @2; - $$ = (Node *) n; - } - else - { - /* generate scalar IN expression */ - $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2); - } + n->subselect = $3; + n->subLinkType = ANY_SUBLINK; + n->subLinkId = 0; + n->testexpr = $1; + n->operName = NIL; /* show it's IN not = ANY */ + n->location = @2; + $$ = (Node *) n; } - | a_expr NOT_LA IN_P in_expr %prec NOT_LA + | a_expr IN_P '(' expr_list ')' { - /* in_expr returns a SubLink or a list of a_exprs */ - if (IsA($4, SubLink)) - { - /* generate NOT (foo = ANY (subquery)) */ - /* Make an = ANY node */ - SubLink *n = (SubLink *) $4; - - n->subLinkType = ANY_SUBLINK; - n->subLinkId = 0; - n->testexpr = $1; - n->operName = NIL; /* show it's IN not = ANY */ - n->location = @2; - /* Stick a NOT on top; must have same parse location */ - $$ = makeNotExpr((Node *) n, @2); - } - else - { - /* generate scalar NOT IN expression */ - $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2); - } + /* generate scalar IN expression */ + A_Expr *n = makeSimpleA_Expr(AEXPR_IN, "=", $1, (Node *) $4, @2); + + n->rexpr_list_start = @3; + n->rexpr_list_end = @5; + $$ = (Node *) n; + } + | a_expr NOT_LA IN_P select_with_parens %prec NOT_LA + { + /* generate NOT (foo = ANY (subquery)) */ + SubLink *n = makeNode(SubLink); + + n->subselect = $4; + n->subLinkType = ANY_SUBLINK; + n->subLinkId = 0; + n->testexpr = $1; + n->operName = NIL; /* show it's IN not = ANY */ + n->location = @2; + /* Stick a NOT on top; must have same parse location */ + $$ = makeNotExpr((Node *) n, @2); + } + | a_expr NOT_LA IN_P '(' expr_list ')' + { + /* generate scalar NOT IN expression */ + A_Expr *n = makeSimpleA_Expr(AEXPR_IN, "<>", $1, (Node *) $5, @2); + + n->rexpr_list_start = @4; + n->rexpr_list_end = @6; + $$ = (Node *) n; } | a_expr subquery_Op sub_type select_with_parens %prec Op { @@ -16656,15 +16857,15 @@ type_list: Typename { $$ = list_make1($1); } array_expr: '[' expr_list ']' { - $$ = makeAArrayExpr($2, @1); + $$ = makeAArrayExpr($2, @1, @3); } | '[' array_expr_list ']' { - $$ = makeAArrayExpr($2, @1); + $$ = makeAArrayExpr($2, @1, @3); } | '[' ']' { - $$ = makeAArrayExpr(NIL, @1); + $$ = makeAArrayExpr(NIL, @1, @2); } ; @@ -16786,17 +16987,6 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); } | expr_list { $$ = $1; } ; -in_expr: select_with_parens - { - SubLink *n = makeNode(SubLink); - - n->subselect = $1; - /* other fields will be filled later */ - $$ = (Node *) n; - } - | '(' expr_list ')' { $$ = (Node *) $2; } - ; - /* * Define SQL-style CASE clause. * - Full specification @@ -16997,7 +17187,8 @@ json_format_clause: else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized JSON encoding: %s", $4))); + errmsg("unrecognized JSON encoding: %s", $4), + parser_errposition(@4))); $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, encoding, @1); } @@ -17499,7 +17690,8 @@ PLpgSQL_Expr: opt_distinct_clause opt_target_list $9->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition($9->optionLoc))); n->limitOption = $9->limitOption; } n->lockingClause = $10; @@ -17683,6 +17875,7 @@ unreserved_keyword: | ENABLE_P | ENCODING | ENCRYPTED + | ENFORCED | ENUM_P | ERROR_P | ESCAPE @@ -17778,6 +17971,7 @@ unreserved_keyword: | NOWAIT | NULLS_P | OBJECT_P + | OBJECTS_P | OF | OFF | OIDS @@ -17800,6 +17994,7 @@ unreserved_keyword: | PASSING | PASSWORD | PATH + | PERIOD | PLAN | PLANS | POLICY @@ -17819,7 +18014,6 @@ unreserved_keyword: | RANGE | READ | REASSIGN - | RECHECK | RECURSIVE | REF_P | REFERENCING @@ -17916,6 +18110,7 @@ unreserved_keyword: | VERSION_P | VIEW | VIEWS + | VIRTUAL | VOLATILE | WHITESPACE_P | WITHIN @@ -18260,6 +18455,7 @@ bare_label_keyword: | ENCODING | ENCRYPTED | END_P + | ENFORCED | ENUM_P | ERROR_P | ESCAPE @@ -18398,6 +18594,7 @@ bare_label_keyword: | NULLS_P | NUMERIC | OBJECT_P + | OBJECTS_P | OF | OFF | OIDS @@ -18424,6 +18621,7 @@ bare_label_keyword: | PASSING | PASSWORD | PATH + | PERIOD | PLACING | PLAN | PLANS @@ -18447,7 +18645,6 @@ bare_label_keyword: | READ | REAL | REASSIGN - | RECHECK | RECURSIVE | REF_P | REFERENCES @@ -18570,6 +18767,7 @@ bare_label_keyword: | VERSION_P | VIEW | VIEWS + | VIRTUAL | VOLATILE | WHEN | WHITESPACE_P @@ -18637,10 +18835,10 @@ makeColumnRef(char *colname, List *indirection, int location, core_yyscan_t yyscanner) { /* - * Generate a ColumnRef node, with an A_Indirection node added if there - * is any subscripting in the specified indirection list. However, - * any field selection at the start of the indirection list must be - * transposed into the "fields" part of the ColumnRef node. + * Generate a ColumnRef node, with an A_Indirection node added if there is + * any subscripting in the specified indirection list. However, any field + * selection at the start of the indirection list must be transposed into + * the "fields" part of the ColumnRef node. */ ColumnRef *c = makeNode(ColumnRef); int nfields = 0; @@ -18695,42 +18893,42 @@ makeFloatConst(char *str, int location) n->val.fval.fval = str; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * makeBoolAConst(bool state, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.boolval.type = T_Boolean; n->val.boolval.boolval = state; n->location = location; - return (Node *) n; + return (Node *) n; } static Node * makeBitStringConst(char *str, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.bsval.type = T_BitString; n->val.bsval.bsval = str; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * makeNullAConst(int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->isnull = true; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * @@ -18814,7 +19012,7 @@ check_func_name(List *names, core_yyscan_t yyscanner) static List * check_indirection(List *indirection, core_yyscan_t yyscanner) { - ListCell *l; + ListCell *l; foreach(l, indirection) { @@ -18869,7 +19067,7 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, core_yyscan_t yyscanner) { FunctionParameter *lastd = (FunctionParameter *) llast(directargs); - Integer *ndirectargs; + Integer *ndirectargs; /* No restriction unless last direct arg is VARIADIC */ if (lastd->mode == FUNC_PARAM_VARIADIC) @@ -18877,15 +19075,15 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, FunctionParameter *firsto = (FunctionParameter *) linitial(orderedargs); /* - * We ignore the names, though the aggr_arg production allows them; - * it doesn't allow default values, so those need not be checked. + * We ignore the names, though the aggr_arg production allows them; it + * doesn't allow default values, so those need not be checked. */ if (list_length(orderedargs) != 1 || firsto->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"), - parser_errposition(exprLocation((Node *) firsto)))); + parser_errposition(firsto->location))); /* OK, drop the duplicate VARIADIC argument from the internal form */ orderedargs = NIL; @@ -18933,7 +19131,7 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple OFFSET clauses not allowed"), - parser_errposition(exprLocation(limitClause->limitOffset)))); + parser_errposition(limitClause->offsetLoc))); stmt->limitOffset = limitClause->limitOffset; } if (limitClause && limitClause->limitCount) @@ -18942,19 +19140,18 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple LIMIT clauses not allowed"), - parser_errposition(exprLocation(limitClause->limitCount)))); + parser_errposition(limitClause->countLoc))); stmt->limitCount = limitClause->limitCount; } if (limitClause) { - if (stmt->limitOption) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple limit options not allowed"))); + /* If there was a conflict, we must have detected it above */ + Assert(!stmt->limitOption); if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition(limitClause->optionLoc))); if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause) { ListCell *lc; @@ -18967,7 +19164,8 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s and %s options cannot be used together", - "SKIP LOCKED", "WITH TIES"))); + "SKIP LOCKED", "WITH TIES"), + parser_errposition(limitClause->optionLoc))); } } stmt->limitOption = limitClause->limitOption; @@ -19013,7 +19211,7 @@ doNegate(Node *n, int location) { if (IsA(n, A_Const)) { - A_Const *con = (A_Const *) n; + A_Const *con = (A_Const *) n; /* report the constant's location as that of the '-' sign */ con->location = location; @@ -19041,7 +19239,7 @@ doNegateFloat(Float *v) if (*oldval == '+') oldval++; if (*oldval == '-') - v->fval = oldval+1; /* just strip the '-' */ + v->fval = oldval + 1; /* just strip the '-' */ else v->fval = psprintf("-%s", oldval); } @@ -19087,12 +19285,14 @@ makeNotExpr(Node *expr, int location) } static Node * -makeAArrayExpr(List *elements, int location) +makeAArrayExpr(List *elements, int location, int location_end) { A_ArrayExpr *n = makeNode(A_ArrayExpr); n->elements = elements; n->location = location; + n->list_start = location; + n->list_end = location_end; return (Node *) n; } @@ -19112,10 +19312,11 @@ static Node * makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location) { - XmlExpr *x = makeNode(XmlExpr); + XmlExpr *x = makeNode(XmlExpr); x->op = op; x->name = name; + /* * named_args is a list of ResTarget; it'll be split apart into separate * expression and name lists in transformXmlExpr(). @@ -19125,7 +19326,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, x->args = args; /* xmloption, if relevant, must be filled in by caller */ /* type and typmod will be filled in during parse analysis */ - x->type = InvalidOid; /* marks the node as not analyzed */ + x->type = InvalidOid; /* marks the node as not analyzed */ x->location = location; return (Node *) x; } @@ -19134,7 +19335,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, * Merge the input and output parameters of a table function. */ static List * -mergeTableFuncParameters(List *func_args, List *columns) +mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner) { ListCell *lc; @@ -19148,7 +19349,8 @@ mergeTableFuncParameters(List *func_args, List *columns) p->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"))); + errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"), + parser_errposition(p->location))); } return list_concat(func_args, columns); @@ -19249,7 +19451,7 @@ makeRangeVarFromQualifiedName(char *name, List *namelist, int location, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", NameListToString(lcons(makeString(name), namelist))), - parser_errposition(location))); + parser_errposition(location))); break; } @@ -19300,8 +19502,8 @@ SplitColQualList(List *qualList, */ static void processCASbits(int cas_bits, int location, const char *constrType, - bool *deferrable, bool *initdeferred, bool *not_valid, - bool *no_inherit, core_yyscan_t yyscanner) + bool *deferrable, bool *initdeferred, bool *is_enforced, + bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner) { /* defaults */ if (deferrable) @@ -19310,6 +19512,8 @@ processCASbits(int cas_bits, int location, const char *constrType, *initdeferred = false; if (not_valid) *not_valid = false; + if (is_enforced) + *is_enforced = true; if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED)) { @@ -19318,7 +19522,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); @@ -19331,7 +19535,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); @@ -19344,7 +19548,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NOT VALID", constrType), parser_errposition(location))); @@ -19357,11 +19561,46 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NO INHERIT", constrType), parser_errposition(location))); } + + if (cas_bits & CAS_NOT_ENFORCED) + { + if (is_enforced) + *is_enforced = false; + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is CHECK, UNIQUE, or similar */ + errmsg("%s constraints cannot be marked NOT ENFORCED", + constrType), + parser_errposition(location))); + + /* + * NB: The validated status is irrelevant when the constraint is set to + * NOT ENFORCED, but for consistency, it should be set accordingly. + * This ensures that if the constraint is later changed to ENFORCED, it + * will automatically be in the correct NOT VALIDATED state. + */ + if (not_valid) + *not_valid = true; + } + + if (cas_bits & CAS_ENFORCED) + { + if (is_enforced) + *is_enforced = true; + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is CHECK, UNIQUE, or similar */ + errmsg("%s constraints cannot be marked ENFORCED", + constrType), + parser_errposition(location))); + } } /* @@ -19369,7 +19608,7 @@ processCASbits(int cas_bits, int location, const char *constrType, * PartitionStrategy representation, or die trying. */ static PartitionStrategy -parsePartitionStrategy(char *strategy) +parsePartitionStrategy(char *strategy, int location, core_yyscan_t yyscanner) { if (pg_strcasecmp(strategy, "list") == 0) return PARTITION_STRATEGY_LIST; @@ -19380,9 +19619,9 @@ parsePartitionStrategy(char *strategy) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized partitioning strategy \"%s\"", - strategy))); - return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ + errmsg("unrecognized partitioning strategy \"%s\"", strategy), + parser_errposition(location))); + return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ } @@ -19453,8 +19692,8 @@ preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner) parser_errposition(pubobj->location))); /* - * We can distinguish between the different type of schema - * objects based on whether name and pubtable is set. + * We can distinguish between the different type of schema objects + * based on whether name and pubtable is set. */ if (pubobj->name) pubobj->pubobjtype = PUBLICATIONOBJ_TABLES_IN_SCHEMA; @@ -19509,11 +19748,13 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) w->ctes = list_make1(cte); w->location = -1; - /* create target list for the new SELECT from the alias list of the - * recursive view specification */ - foreach (lc, aliases) + /* + * create target list for the new SELECT from the alias list of the + * recursive view specification + */ + foreach(lc, aliases) { - ResTarget *rt = makeNode(ResTarget); + ResTarget *rt = makeNode(ResTarget); rt->name = NULL; rt->indirection = NIL; @@ -19523,8 +19764,10 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) tl = lappend(tl, rt); } - /* create new SELECT combining WITH clause, target list, and fake FROM - * clause */ + /* + * create new SELECT combining WITH clause, target list, and fake FROM + * clause + */ s->withClause = w; s->targetList = tl; s->fromClause = list_make1(makeRangeVar(NULL, relname, -1)); diff --git a/src/parser/gram_template.y b/src/parser/gram_template.y index fdb4e8106..4ade68365 100644 --- a/src/parser/gram_template.y +++ b/src/parser/gram_template.y @@ -6,8 +6,8 @@ * gram.y * POSTGRESQL BISON rules/actions * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -89,6 +89,8 @@ #define ATTRIBUTE_IDENTITY_ALWAYS 'a' #define ATTRIBUTE_IDENTITY_BY_DEFAULT 'd' +#define ATTRIBUTE_GENERATED_STORED 's' +#define ATTRIBUTE_GENERATED_VIRTUAL 'v' /* * Definition taken from * postgreSQL source code file: src/include/utils/xml.h @@ -102,40 +104,26 @@ typedef enum } XmlStandaloneType; /* - * Location tracking support --- simpler than bison's default, since we only - * want to track the start position not the end position of each nonterminal. + * Location tracking support. Unlike bison's default, we only want + * to track the start position not the end position of each nonterminal. + * Nonterminals that reduce to empty receive position "-1". Since a + * production's leading RHS nonterminal(s) may have reduced to empty, + * we have to scan to find the first one that's not -1. */ #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ - if ((N) > 0) \ - (Current) = (Rhs)[1]; \ - else \ - (Current) = (-1); \ + (Current) = (-1); \ + for (int _i = 1; _i <= (N); _i++) \ + { \ + if ((Rhs)[_i] >= 0) \ + { \ + (Current) = (Rhs)[_i]; \ + break; \ + } \ + } \ } while (0) /* - * The above macro assigns -1 (unknown) as the parse location of any - * nonterminal that was reduced from an empty rule, or whose leftmost - * component was reduced from an empty rule. This is problematic - * for nonterminals defined like - * OptFooList: / * EMPTY * / { ... } | OptFooList Foo { ... } ; - * because we'll set -1 as the location during the first reduction and then - * copy it during each subsequent reduction, leaving us with -1 for the - * location even when the list is not empty. To fix that, do this in the - * action for the nonempty rule(s): - * if (@$ < 0) @$ = @2; - * (Although we have many nonterminals that follow this pattern, we only - * bother with fixing @$ like this when the nonterminal's parse location - * is actually referenced in some rule.) - * - * A cleaner answer would be to make YYLLOC_DEFAULT scan all the Rhs - * locations until it's found one that's not -1. Then we'd get a correct - * location for any nonterminal that isn't entirely empty. But this way - * would add overhead to every rule reduction, and so far there's not been - * a compelling reason to pay that overhead. - */ - -/* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents * memory leaks if we error out during parsing. @@ -158,12 +146,15 @@ typedef struct ImportQual List *table_names; } ImportQual; -/* Private struct for the result of opt_select_limit production */ +/* Private struct for the result of select_limit & limit_clause productions */ typedef struct SelectLimit { Node *limitOffset; Node *limitCount; - LimitOption limitOption; + LimitOption limitOption; /* indicates presence of WITH TIES */ + ParseLoc offsetLoc; /* location of OFFSET token, if present */ + ParseLoc countLoc; /* location of LIMIT/FETCH token, if present */ + ParseLoc optionLoc; /* location of WITH TIES, if present */ } SelectLimit; /* Private struct for the result of group_clause production */ @@ -193,6 +184,8 @@ typedef struct KeyActions #define CAS_INITIALLY_DEFERRED 0x08 #define CAS_NOT_VALID 0x10 #define CAS_NO_INHERIT 0x20 +#define CAS_NOT_ENFORCED 0x40 +#define CAS_ENFORCED 0x80 #define parser_yyerror(msg) scanner_yyerror(msg, yyscanner) @@ -233,12 +226,12 @@ static void doNegateFloat(Float *v); static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location); static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location); static Node *makeNotExpr(Node *expr, int location); -static Node *makeAArrayExpr(List *elements, int location); +static Node *makeAArrayExpr(List *elements, int location, int end_location); static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location); static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location); -static List *mergeTableFuncParameters(List *func_args, List *columns); +static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); static RangeVar *makeRangeVarFromQualifiedName(char *name, List *namelist, int location, @@ -247,9 +240,10 @@ static void SplitColQualList(List *qualList, List **constraintList, CollateClause **collClause, core_yyscan_t yyscanner); static void processCASbits(int cas_bits, int location, const char *constrType, - bool *deferrable, bool *initdeferred, bool *not_valid, - bool *no_inherit, core_yyscan_t yyscanner); -static PartitionStrategy parsePartitionStrategy(char *strategy); + bool *deferrable, bool *initdeferred, bool *is_enforced, + bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); +static PartitionStrategy parsePartitionStrategy(char *strategy, int location, + core_yyscan_t yyscanner); static void preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); @@ -319,6 +313,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); MergeWhenClause *mergewhen; struct KeyActions *keyactions; struct KeyAction *keyaction; + ReturningClause *retclause; + ReturningOptionKind retoptionkind; } %type <node> stmt toplevel_stmt schema_stmt routine_body_stmt @@ -495,7 +491,8 @@ UpdateStmtShort opclass_purpose opt_opfamily transaction_mode_list_or_empty OptTableFuncElementList TableFuncElementList opt_type_modifiers prep_type_clause - execute_param_clause using_clause returning_clause + execute_param_clause using_clause + returning_with_clause returning_options opt_enum_val_list enum_val_list table_func_column_list create_generic_options alter_generic_options relation_expr_list dostmt_opt_list @@ -504,6 +501,9 @@ UpdateStmtShort vacuum_relation_list opt_vacuum_relation_list drop_option_list pub_obj_list +%type <retclause> returning_clause +%type <node> returning_option +%type <retoptionkind> returning_option_kind %type <node> opt_routine_body %type <groupclause> group_clause %type <list> group_by_list @@ -542,7 +542,7 @@ UpdateStmtShort %type <boolean> opt_instead %type <boolean> opt_unique opt_verbose opt_full -%type <boolean> opt_freeze opt_analyze opt_default opt_recheck +%type <boolean> opt_freeze opt_analyze opt_default %type <defelt> opt_binary copy_delimiter %type <boolean> copy_from opt_program @@ -572,14 +572,15 @@ UpdateStmtShort SetResetClause FunctionSetResetClause %type <node> TableElement TypedTableElement ConstraintElem DomainConstraintElem TableFuncElement -%type <node> columnDef columnOptions +%type <node> columnDef columnOptions optionalPeriodName %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem %type <node> def_arg columnElem where_clause where_or_current_clause a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound - columnref in_expr having_clause func_table xmltable array_expr + columnref having_clause func_table xmltable array_expr OptWhereClause operator_def_arg +%type <list> opt_column_and_period_list %type <list> rowsfrom_item rowsfrom_list opt_col_def_list -%type <boolean> opt_ordinality +%type <boolean> opt_ordinality opt_without_overlaps %type <list> ExclusionConstraintList ExclusionConstraintElem %type <list> func_arg_list func_arg_list_opt %type <node> func_arg_expr @@ -688,7 +689,7 @@ UpdateStmtShort %type <str> opt_existing_window_name %type <boolean> opt_if_not_exists %type <boolean> opt_unique_null_treatment -%type <ival> generated_when override_kind +%type <ival> generated_when override_kind opt_virtual_or_stored %type <partspec> PartitionSpec OptPartitionSpec %type <partelem> part_elem %type <list> part_params @@ -771,9 +772,9 @@ UpdateStmtShort DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP - EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERROR_P ESCAPE - EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION - EXTENSION EXTERNAL EXTRACT + EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERROR_P + ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN + EXPRESSION EXTENSION EXTERNAL EXTRACT FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS @@ -804,18 +805,18 @@ UpdateStmtShort NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC - OBJECT_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR + OBJECT_P OBJECTS_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR ORDER ORDINALITY OTHERS OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH PGPOOL - PLACING PLAN PLANS POLICY + PERIOD PLACING PLAN PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION QUOTE QUOTES - RANGE READ REAL REASSIGN RECHECK RECURSIVE REF_P REFERENCES REFERENCING + RANGE READ REAL REASSIGN RECURSIVE REF_P REFERENCES REFERENCING REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROUTINE ROUTINES ROW ROWS RULE @@ -836,7 +837,7 @@ UpdateStmtShort UNLISTEN UNLOGGED UNTIL UPDATE USER USING VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING - VERBOSE VERSION_P VIEW VIEWS VOLATILE + VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE @@ -977,7 +978,7 @@ parse_toplevel: | MODE_PLPGSQL_EXPR PLpgSQL_Expr { pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt($2, 0)); + list_make1(makeRawStmt($2, @2)); } | MODE_PLPGSQL_ASSIGN1 PLAssignStmt { @@ -985,7 +986,7 @@ parse_toplevel: n->nnames = 1; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } | MODE_PLPGSQL_ASSIGN2 PLAssignStmt { @@ -993,7 +994,7 @@ parse_toplevel: n->nnames = 2; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } | MODE_PLPGSQL_ASSIGN3 PLAssignStmt { @@ -1001,19 +1002,15 @@ parse_toplevel: n->nnames = 3; pg_yyget_extra(yyscanner)->parsetree = - list_make1(makeRawStmt((Node *) n, 0)); + list_make1(makeRawStmt((Node *) n, @2)); } ; /* * At top level, we wrap each stmt with a RawStmt node carrying start location - * and length of the stmt's text. Notice that the start loc/len are driven - * entirely from semicolon locations (@2). It would seem natural to use - * @1 or @3 to get the true start location of a stmt, but that doesn't work - * for statements that can start with empty nonterminals (opt_with_clause is - * the main offender here); as noted in the comments for YYLLOC_DEFAULT, - * we'd get -1 for the location in such cases. - * We also take care to discard empty statements entirely. + * and length of the stmt's text. + * We also take care to discard empty statements entirely (which among other + * things dodges the problem of assigning them a location). */ stmtmulti: stmtmulti ';' toplevel_stmt { @@ -1023,14 +1020,14 @@ stmtmulti: stmtmulti ';' toplevel_stmt updateRawStmtEnd(llast_node(RawStmt, $1), @2); } if ($3 != NULL) - $$ = lappend($1, makeRawStmt($3, @2 + 1)); + $$ = lappend($1, makeRawStmt($3, @3)); else $$ = $1; } | toplevel_stmt { if ($1 != NULL) - $$ = list_make1(makeRawStmt($1, 0)); + $$ = list_make1(makeRawStmt($1, @1)); else $$ = NIL; } @@ -1639,8 +1636,6 @@ CreateSchemaStmt: OptSchemaEltList: OptSchemaEltList schema_stmt { - if (@$ < 0) /* see comments for YYLLOC_DEFAULT */ - @$ = @2; $$ = lappend($1, $2); } | /* EMPTY */ @@ -1678,6 +1673,13 @@ VariableSetStmt: n->is_local = false; $$ = (Node *) n; } + | PGPOOL set_rest_more + { + VariableSetStmt *n = $2; + n->type = T_PgpoolQueryCacheStmt; /* Hack to keep changes minimum */ + n->is_local = false; + $$ = (Node *) n; + } | SET set_rest { VariableSetStmt *n = $2; @@ -1709,6 +1711,8 @@ set_rest: n->kind = VAR_SET_MULTI; n->name = "TRANSACTION"; n->args = $2; + n->jumble_args = true; + n->location = -1; $$ = n; } | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list @@ -1718,6 +1722,8 @@ set_rest: n->kind = VAR_SET_MULTI; n->name = "SESSION CHARACTERISTICS"; n->args = $5; + n->jumble_args = true; + n->location = -1; $$ = n; } | set_rest_more @@ -1731,6 +1737,7 @@ generic_set: n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; + n->location = @3; $$ = n; } | var_name '=' var_list @@ -1740,6 +1747,7 @@ generic_set: n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; + n->location = @3; $$ = n; } | var_name TO DEFAULT @@ -1748,6 +1756,7 @@ generic_set: n->kind = VAR_SET_DEFAULT; n->name = $1; + n->location = -1; $$ = n; } | var_name '=' DEFAULT @@ -1756,6 +1765,7 @@ generic_set: n->kind = VAR_SET_DEFAULT; n->name = $1; + n->location = -1; $$ = n; } ; @@ -1768,6 +1778,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_CURRENT; n->name = $1; + n->location = -1; $$ = n; } /* Special syntaxes mandated by SQL standard: */ @@ -1777,6 +1788,8 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "timezone"; + n->location = -1; + n->jumble_args = true; if ($3 != NULL) n->args = list_make1($3); else @@ -1798,6 +1811,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "search_path"; n->args = list_make1(makeStringConst($2, @2)); + n->location = @2; $$ = n; } | NAMES opt_encoding @@ -1806,6 +1820,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "client_encoding"; + n->location = @2; if ($2 != NULL) n->args = list_make1(makeStringConst($2, @2)); else @@ -1819,6 +1834,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "role"; n->args = list_make1(makeStringConst($2, @2)); + n->location = @2; $$ = n; } | SESSION AUTHORIZATION NonReservedWord_or_Sconst @@ -1828,6 +1844,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "session_authorization"; n->args = list_make1(makeStringConst($3, @3)); + n->location = @3; $$ = n; } | SESSION AUTHORIZATION DEFAULT @@ -1836,6 +1853,7 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_DEFAULT; n->name = "session_authorization"; + n->location = -1; $$ = n; } | XML_P OPTION document_or_content @@ -1845,6 +1863,8 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_VALUE; n->name = "xmloption"; n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3)); + n->jumble_args = true; + n->location = -1; $$ = n; } /* Special syntaxes invented by PostgreSQL: */ @@ -1855,6 +1875,14 @@ set_rest_more: /* Generic SET syntaxes: */ n->kind = VAR_SET_MULTI; n->name = "TRANSACTION SNAPSHOT"; n->args = list_make1(makeStringConst($3, @3)); + n->location = @3; + $$ = n; + } + /* PGPOOL CACHE DELETE */ + | SET CACHE DELETE_P Sconst + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->name = $4; /* query to delete query cache */ $$ = n; } ; @@ -1968,6 +1996,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "timezone"; + n->location = -1; $$ = n; } | TRANSACTION ISOLATION LEVEL @@ -1976,6 +2005,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "transaction_isolation"; + n->location = -1; $$ = n; } | SESSION AUTHORIZATION @@ -1984,6 +2014,7 @@ reset_rest: n->kind = VAR_RESET; n->name = "session_authorization"; + n->location = -1; $$ = n; } ; @@ -1995,6 +2026,7 @@ generic_reset: n->kind = VAR_RESET; n->name = $1; + n->location = -1; $$ = n; } | ALL @@ -2002,6 +2034,7 @@ generic_reset: VariableSetStmt *n = makeNode(VariableSetStmt); n->kind = VAR_RESET_ALL; + n->location = -1; $$ = n; } ; @@ -2724,15 +2757,45 @@ alter_table_cmd: | ALTER CONSTRAINT name ConstraintAttributeSpec { AlterTableCmd *n = makeNode(AlterTableCmd); - Constraint *c = makeNode(Constraint); + ATAlterConstraint *c = makeNode(ATAlterConstraint); + n->subtype = AT_AlterConstraint; n->def = (Node *) c; - c->contype = CONSTR_FOREIGN; /* others not supported, yet */ c->conname = $3; - processCASbits($4, @4, "ALTER CONSTRAINT statement", + if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED)) + c->alterEnforceability = true; + if ($4 & (CAS_DEFERRABLE | CAS_NOT_DEFERRABLE | + CAS_INITIALLY_DEFERRED | CAS_INITIALLY_IMMEDIATE)) + c->alterDeferrability = true; + if ($4 & CAS_NO_INHERIT) + c->alterInheritability = true; + /* handle unsupported case with specific error message */ + if ($4 & CAS_NOT_VALID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("constraints cannot be altered to be NOT VALID"), + parser_errposition(@4))); + processCASbits($4, @4, "FOREIGN KEY", &c->deferrable, &c->initdeferred, - NULL, NULL, yyscanner); + &c->is_enforced, + NULL, + &c->noinherit, + yyscanner); + $$ = (Node *) n; + } + /* ALTER TABLE <name> ALTER CONSTRAINT INHERIT */ + | ALTER CONSTRAINT name INHERIT + { + AlterTableCmd *n = makeNode(AlterTableCmd); + ATAlterConstraint *c = makeNode(ATAlterConstraint); + + n->subtype = AT_AlterConstraint; + n->def = (Node *) c; + c->conname = $3; + c->alterInheritability = true; + c->noinherit = false; + $$ = (Node *) n; } /* ALTER TABLE <name> VALIDATE CONSTRAINT ... */ @@ -3223,11 +3286,13 @@ PartitionBoundSpec: if (n->modulus == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("modulus for hash partition must be specified"))); + errmsg("modulus for hash partition must be specified"), + parser_errposition(@3))); if (n->remainder == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("remainder for hash partition must be specified"))); + errmsg("remainder for hash partition must be specified"), + parser_errposition(@3))); n->location = @3; @@ -3979,12 +4044,16 @@ ColConstraint: * or be part of a_expr NOT LIKE or similar constructs). */ ColConstraintElem: - NOT NULL_P + NOT NULL_P opt_no_inherit { Constraint *n = makeNode(Constraint); n->contype = CONSTR_NOTNULL; n->location = @1; + n->is_no_inherit = $3; + n->is_enforced = true; + n->skip_validation = false; + n->initially_valid = true; $$ = (Node *) n; } | NULL_P @@ -4029,6 +4098,7 @@ ColConstraintElem: n->is_no_inherit = $5; n->raw_expr = $3; n->cooked_expr = NULL; + n->is_enforced = true; n->skip_validation = false; n->initially_valid = true; $$ = (Node *) n; @@ -4055,7 +4125,7 @@ ColConstraintElem: n->location = @1; $$ = (Node *) n; } - | GENERATED generated_when AS '(' a_expr ')' STORED + | GENERATED generated_when AS '(' a_expr ')' opt_virtual_or_stored { Constraint *n = makeNode(Constraint); @@ -4063,6 +4133,7 @@ ColConstraintElem: n->generated_when = $2; n->raw_expr = $5; n->cooked_expr = NULL; + n->generated_kind = $7; n->location = @1; /* @@ -4092,6 +4163,7 @@ ColConstraintElem: n->fk_upd_action = ($5)->updateAction->action; n->fk_del_action = ($5)->deleteAction->action; n->fk_del_set_cols = ($5)->deleteAction->cols; + n->is_enforced = true; n->skip_validation = false; n->initially_valid = true; $$ = (Node *) n; @@ -4109,6 +4181,12 @@ generated_when: | BY DEFAULT { $$ = ATTRIBUTE_IDENTITY_BY_DEFAULT; } ; +opt_virtual_or_stored: + STORED { $$ = ATTRIBUTE_GENERATED_STORED; } + | VIRTUAL { $$ = ATTRIBUTE_GENERATED_VIRTUAL; } + | /*EMPTY*/ { $$ = ATTRIBUTE_GENERATED_VIRTUAL; } + ; + /* * ConstraintAttr represents constraint attributes, which we parse as if * they were independent constraint clauses, in order to avoid shift/reduce @@ -4157,6 +4235,22 @@ ConstraintAttr: n->location = @1; $$ = (Node *) n; } + | ENFORCED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_ATTR_ENFORCED; + n->location = @1; + $$ = (Node *) n; + } + | NOT ENFORCED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_ATTR_NOT_ENFORCED; + n->location = @1; + $$ = (Node *) n; + } ; @@ -4218,12 +4312,25 @@ ConstraintElem: n->raw_expr = $3; n->cooked_expr = NULL; processCASbits($5, @5, "CHECK", - NULL, NULL, &n->skip_validation, + NULL, NULL, &n->is_enforced, &n->skip_validation, + &n->is_no_inherit, yyscanner); + n->initially_valid = !n->skip_validation; + $$ = (Node *) n; + } + | NOT NULL_P ColId ConstraintAttributeSpec + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_NOTNULL; + n->location = @1; + n->keys = list_make1(makeString($3)); + processCASbits($4, @4, "NOT NULL", + NULL, NULL, NULL, &n->skip_validation, &n->is_no_inherit, yyscanner); n->initially_valid = !n->skip_validation; $$ = (Node *) n; } - | UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + | UNIQUE opt_unique_null_treatment '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4232,13 +4339,14 @@ ConstraintElem: n->location = @1; n->nulls_not_distinct = !$2; n->keys = $4; - n->including = $6; - n->options = $7; + n->without_overlaps = $5; + n->including = $7; + n->options = $8; n->indexname = NULL; - n->indexspace = $8; - processCASbits($9, @9, "UNIQUE", + n->indexspace = $9; + processCASbits($10, @10, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | UNIQUE ExistingIndex ConstraintAttributeSpec @@ -4254,10 +4362,10 @@ ConstraintElem: n->indexspace = NULL; processCASbits($3, @3, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } - | PRIMARY KEY '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + | PRIMARY KEY '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4265,13 +4373,14 @@ ConstraintElem: n->contype = CONSTR_PRIMARY; n->location = @1; n->keys = $4; - n->including = $6; - n->options = $7; + n->without_overlaps = $5; + n->including = $7; + n->options = $8; n->indexname = NULL; - n->indexspace = $8; - processCASbits($9, @9, "PRIMARY KEY", + n->indexspace = $9; + processCASbits($10, @10, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | PRIMARY KEY ExistingIndex ConstraintAttributeSpec @@ -4287,7 +4396,7 @@ ConstraintElem: n->indexspace = NULL; processCASbits($4, @4, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } | EXCLUDE access_method_clause '(' ExclusionConstraintList ')' @@ -4307,26 +4416,36 @@ ConstraintElem: n->where_clause = $9; processCASbits($10, @10, "EXCLUDE", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); $$ = (Node *) n; } - | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name - opt_column_list key_match key_actions ConstraintAttributeSpec + | FOREIGN KEY '(' columnList optionalPeriodName ')' REFERENCES qualified_name + opt_column_and_period_list key_match key_actions ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); n->contype = CONSTR_FOREIGN; n->location = @1; - n->pktable = $7; + n->pktable = $8; n->fk_attrs = $4; - n->pk_attrs = $8; - n->fk_matchtype = $9; - n->fk_upd_action = ($10)->updateAction->action; - n->fk_del_action = ($10)->deleteAction->action; - n->fk_del_set_cols = ($10)->deleteAction->cols; - processCASbits($11, @11, "FOREIGN KEY", + if ($5) + { + n->fk_attrs = lappend(n->fk_attrs, $5); + n->fk_with_period = true; + } + n->pk_attrs = linitial($9); + if (lsecond($9)) + { + n->pk_attrs = lappend(n->pk_attrs, lsecond($9)); + n->pk_with_period = true; + } + n->fk_matchtype = $10; + n->fk_upd_action = ($11)->updateAction->action; + n->fk_del_action = ($11)->deleteAction->action; + n->fk_del_set_cols = ($11)->deleteAction->cols; + processCASbits($12, @12, "FOREIGN KEY", &n->deferrable, &n->initdeferred, - &n->skip_validation, NULL, + &n->is_enforced, &n->skip_validation, NULL, yyscanner); n->initially_valid = !n->skip_validation; $$ = (Node *) n; @@ -4366,8 +4485,9 @@ DomainConstraintElem: n->raw_expr = $3; n->cooked_expr = NULL; processCASbits($5, @5, "CHECK", - NULL, NULL, &n->skip_validation, + NULL, NULL, NULL, &n->skip_validation, &n->is_no_inherit, yyscanner); + n->is_enforced = true; n->initially_valid = !n->skip_validation; $$ = (Node *) n; } @@ -4378,10 +4498,10 @@ DomainConstraintElem: n->contype = CONSTR_NOTNULL; n->location = @1; n->keys = list_make1(makeString("value")); - /* no NOT VALID support yet */ + /* no NOT VALID, NO INHERIT support */ processCASbits($3, @3, "NOT NULL", NULL, NULL, NULL, - &n->is_no_inherit, yyscanner); + NULL, NULL, yyscanner); n->initially_valid = true; $$ = (Node *) n; } @@ -4391,6 +4511,11 @@ opt_no_inherit: NO INHERIT { $$ = true; } | /* EMPTY */ { $$ = false; } ; +opt_without_overlaps: + WITHOUT OVERLAPS { $$ = true; } + | /*EMPTY*/ { $$ = false; } + ; + opt_column_list: '(' columnList ')' { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } @@ -4401,6 +4526,16 @@ columnList: | columnList ',' columnElem { $$ = lappend($1, $3); } ; +optionalPeriodName: + ',' PERIOD columnElem { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + +opt_column_and_period_list: + '(' columnList optionalPeriodName ')' { $$ = list_make2($2, $3); } + | /*EMPTY*/ { $$ = list_make2(NIL, NULL); } + ; + columnElem: ColId { $$ = (Node *) makeString($1); @@ -4580,7 +4715,7 @@ PartitionSpec: PARTITION BY ColId '(' part_params ')' { PartitionSpec *n = makeNode(PartitionSpec); - n->strategy = parsePartitionStrategy($3); + n->strategy = parsePartitionStrategy($3, @3, yyscanner); n->partParams = $5; n->location = @1; @@ -4990,6 +5125,10 @@ SeqOptElem: AS SimpleTypename { $$ = makeDefElem("increment", (Node *) $3, @1); } + | LOGGED + { + $$ = makeDefElem("logged", NULL, @1); + } | MAXVALUE NumericOnly { $$ = makeDefElem("maxvalue", (Node *) $2, @1); @@ -5012,7 +5151,6 @@ SeqOptElem: AS SimpleTypename } | SEQUENCE NAME_P any_name { - /* not documented, only used by pg_dump */ $$ = makeDefElem("sequence_name", (Node *) $3, @1); } | START opt_with NumericOnly @@ -5027,6 +5165,10 @@ SeqOptElem: AS SimpleTypename { $$ = makeDefElem("restart", (Node *) $3, @1); } + | UNLOGGED + { + $$ = makeDefElem("unlogged", NULL, @1); + } ; opt_by: BY @@ -6007,7 +6149,8 @@ CreateTrigStmt: if (n->replace) /* not supported, see CreateTrigger */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"))); + errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"), + parser_errposition(@1))); n->isconstraint = true; n->trigname = $5; n->relation = $9; @@ -6021,7 +6164,7 @@ CreateTrigStmt: n->transitionRels = NIL; processCASbits($11, @11, "TRIGGER", &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); + NULL, NULL, yyscanner); n->constrrel = $10; $$ = (Node *) n; } @@ -6190,7 +6333,8 @@ ConstraintAttributeSpec: parser_errposition(@2))); /* generic message for other conflicts */ if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) || - (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) + (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED) || + (newspec & (CAS_NOT_ENFORCED | CAS_ENFORCED)) == (CAS_NOT_ENFORCED | CAS_ENFORCED)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting constraint properties"), @@ -6206,6 +6350,8 @@ ConstraintAttributeElem: | INITIALLY DEFERRED { $$ = CAS_INITIALLY_DEFERRED; } | NOT VALID { $$ = CAS_NOT_VALID; } | NO INHERIT { $$ = CAS_NO_INHERIT; } + | NOT ENFORCED { $$ = CAS_NOT_ENFORCED; } + | ENFORCED { $$ = CAS_ENFORCED; } ; @@ -6292,7 +6438,8 @@ CreateAssertionStmt: { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE ASSERTION is not yet implemented"))); + errmsg("CREATE ASSERTION is not yet implemented"), + parser_errposition(@1))); $$ = NULL; } @@ -6652,7 +6799,7 @@ opclass_item_list: ; opclass_item: - OPERATOR Iconst any_operator opclass_purpose opt_recheck + OPERATOR Iconst any_operator opclass_purpose { CreateOpClassItem *n = makeNode(CreateOpClassItem); ObjectWithArgs *owa = makeNode(ObjectWithArgs); @@ -6666,7 +6813,6 @@ opclass_item: $$ = (Node *) n; } | OPERATOR Iconst operator_with_argtypes opclass_purpose - opt_recheck { CreateOpClassItem *n = makeNode(CreateOpClassItem); @@ -6718,23 +6864,6 @@ opclass_purpose: FOR SEARCH { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; } ; -opt_recheck: RECHECK - { - /* - * RECHECK no longer does anything in opclass definitions, - * but we still accept it to ease porting of old database - * dumps. - */ - ereport(NOTICE, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("RECHECK is no longer required"), - errhint("Update your data type."), - parser_errposition(@1))); - $$ = true; - } - | /*EMPTY*/ { $$ = false; } - ; - CreateOpFamilyStmt: CREATE OPERATOR FAMILY any_name USING name @@ -8154,6 +8283,7 @@ defacl_privilege_target: | SEQUENCES { $$ = OBJECT_SEQUENCE; } | TYPES_P { $$ = OBJECT_TYPE; } | SCHEMAS { $$ = OBJECT_SCHEMA; } + | LARGE_P OBJECTS_P { $$ = OBJECT_LARGEOBJECT; } ; @@ -8353,7 +8483,7 @@ CreateFunctionStmt: n->is_procedure = false; n->replace = $2; n->funcname = $4; - n->parameters = mergeTableFuncParameters($5, $9); + n->parameters = mergeTableFuncParameters($5, $9, yyscanner); n->returnType = TableFuncTypeName($9); n->returnType->location = @7; n->options = $11; @@ -8486,6 +8616,7 @@ func_arg: n->argType = $3; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name arg_class func_type @@ -8496,6 +8627,7 @@ func_arg: n->argType = $3; n->mode = $2; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name func_type @@ -8506,6 +8638,7 @@ func_arg: n->argType = $2; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } | arg_class func_type @@ -8516,6 +8649,7 @@ func_arg: n->argType = $2; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | func_type @@ -8526,6 +8660,7 @@ func_arg: n->argType = $1; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -8862,6 +8997,7 @@ table_func_column: param_name func_type n->argType = $2; n->mode = FUNC_PARAM_TABLE; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -11986,7 +12122,7 @@ opt_name_list: ; vacuum_relation: - qualified_name opt_name_list + relation_expr opt_name_list { $$ = (Node *) makeVacuumRelation($1, InvalidOid, $2); } @@ -12209,7 +12345,7 @@ InsertStmt: { $5->relation = $4; $5->onConflictClause = $6; - $5->returningList = $7; + $5->returningClause = $7; $5->withClause = $1; $$ = (Node *) $5; } @@ -12358,8 +12494,45 @@ opt_conf_expr: ; returning_clause: - RETURNING target_list { $$ = $2; } - | /* EMPTY */ { $$ = NIL; } + RETURNING returning_with_clause target_list + { + ReturningClause *n = makeNode(ReturningClause); + + n->options = $2; + n->exprs = $3; + $$ = n; + } + | /* EMPTY */ + { + $$ = NULL; + } + ; + +returning_with_clause: + WITH '(' returning_options ')' { $$ = $3; } + | /* EMPTY */ { $$ = NIL; } + ; + +returning_options: + returning_option { $$ = list_make1($1); } + | returning_options ',' returning_option { $$ = lappend($1, $3); } + ; + +returning_option: + returning_option_kind AS ColId + { + ReturningOption *n = makeNode(ReturningOption); + + n->option = $1; + n->value = $3; + n->location = @1; + $$ = (Node *) n; + } + ; + +returning_option_kind: + OLD { $$ = RETURNING_OPTION_OLD; } + | NEW { $$ = RETURNING_OPTION_NEW; } ; @@ -12378,7 +12551,7 @@ DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias n->relation = $4; n->usingClause = $5; n->whereClause = $6; - n->returningList = $7; + n->returningClause = $7; n->withClause = $1; $$ = (Node *) n; } @@ -12452,7 +12625,7 @@ UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias n->targetList = $5; n->fromClause = $6; n->whereClause = $7; - n->returningList = $8; + n->returningClause = $8; n->withClause = $1; $$ = (Node *) n; } @@ -12465,7 +12638,7 @@ UpdateStmtShort: opt_with_clause UPDATE relation_expr_opt_alias n->targetList = NULL; n->fromClause = NULL; n->whereClause = NULL; - n->returningList = NULL; + n->returningClause = NULL; n->withClause = $1; $$ = (Node *)n; pg_yyget_extra(yyscanner)->parsetree = list_make1(makeRawStmt($$, 0)); @@ -12545,7 +12718,7 @@ MergeStmt: m->sourceRelation = $6; m->joinCondition = $8; m->mergeWhenClauses = $9; - m->returningList = $10; + m->returningClause = $10; $$ = (Node *) m; } @@ -13224,11 +13397,13 @@ select_limit: { $$ = $1; ($$)->limitOffset = $2; + ($$)->offsetLoc = @2; } | offset_clause limit_clause { $$ = $2; ($$)->limitOffset = $1; + ($$)->offsetLoc = @1; } | limit_clause { @@ -13241,6 +13416,9 @@ select_limit: n->limitOffset = $1; n->limitCount = NULL; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = @1; + n->countLoc = -1; + n->optionLoc = -1; $$ = n; } ; @@ -13258,6 +13436,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $2; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | LIMIT select_limit_value ',' select_offset_value @@ -13283,6 +13464,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES @@ -13292,6 +13476,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_WITH_TIES; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = @5; $$ = n; } | FETCH first_or_next row_or_rows ONLY @@ -13301,6 +13488,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_COUNT; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = -1; $$ = n; } | FETCH first_or_next row_or_rows WITH TIES @@ -13310,6 +13500,9 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_WITH_TIES; + n->offsetLoc = -1; + n->countLoc = @1; + n->optionLoc = @4; $$ = n; } ; @@ -14154,7 +14347,7 @@ xmltable_column_el: 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, @@ -14197,13 +14390,20 @@ xmltable_column_option_list: xmltable_column_option_el: IDENT b_expr - { $$ = makeDefElem($1, $2, @1); } + { + if (strcmp($1, "__pg__is_not_null") == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("option name \"%s\" cannot be used in XMLTABLE", $1), + parser_errposition(@1))); + $$ = makeDefElem($1, $2, @1); + } | DEFAULT b_expr { $$ = makeDefElem("default", $2, @1); } | NOT NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); } + { $$ = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(true), @1); } | NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); } + { $$ = makeDefElem("__pg__is_not_null", (Node *) makeBoolean(false), @1); } | PATH b_expr { $$ = makeDefElem("path", $2, @1); } ; @@ -15204,49 +15404,50 @@ a_expr: c_expr { $$ = $1; } (Node *) list_make2($5, $7), @2); } - | a_expr IN_P in_expr + | a_expr IN_P select_with_parens { - /* in_expr returns a SubLink or a list of a_exprs */ - if (IsA($3, SubLink)) - { - /* generate foo = ANY (subquery) */ - SubLink *n = (SubLink *) $3; + /* generate foo = ANY (subquery) */ + SubLink *n = makeNode(SubLink); - n->subLinkType = ANY_SUBLINK; - n->subLinkId = 0; - n->testexpr = $1; - n->operName = NIL; /* show it's IN not = ANY */ - n->location = @2; - $$ = (Node *) n; - } - else - { - /* generate scalar IN expression */ - $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2); - } + n->subselect = $3; + n->subLinkType = ANY_SUBLINK; + n->subLinkId = 0; + n->testexpr = $1; + n->operName = NIL; /* show it's IN not = ANY */ + n->location = @2; + $$ = (Node *) n; } - | a_expr NOT_LA IN_P in_expr %prec NOT_LA + | a_expr IN_P '(' expr_list ')' { - /* in_expr returns a SubLink or a list of a_exprs */ - if (IsA($4, SubLink)) - { - /* generate NOT (foo = ANY (subquery)) */ - /* Make an = ANY node */ - SubLink *n = (SubLink *) $4; - - n->subLinkType = ANY_SUBLINK; - n->subLinkId = 0; - n->testexpr = $1; - n->operName = NIL; /* show it's IN not = ANY */ - n->location = @2; - /* Stick a NOT on top; must have same parse location */ - $$ = makeNotExpr((Node *) n, @2); - } - else - { - /* generate scalar NOT IN expression */ - $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2); - } + /* generate scalar IN expression */ + A_Expr *n = makeSimpleA_Expr(AEXPR_IN, "=", $1, (Node *) $4, @2); + + n->rexpr_list_start = @3; + n->rexpr_list_end = @5; + $$ = (Node *) n; + } + | a_expr NOT_LA IN_P select_with_parens %prec NOT_LA + { + /* generate NOT (foo = ANY (subquery)) */ + SubLink *n = makeNode(SubLink); + + n->subselect = $4; + n->subLinkType = ANY_SUBLINK; + n->subLinkId = 0; + n->testexpr = $1; + n->operName = NIL; /* show it's IN not = ANY */ + n->location = @2; + /* Stick a NOT on top; must have same parse location */ + $$ = makeNotExpr((Node *) n, @2); + } + | a_expr NOT_LA IN_P '(' expr_list ')' + { + /* generate scalar NOT IN expression */ + A_Expr *n = makeSimpleA_Expr(AEXPR_IN, "<>", $1, (Node *) $5, @2); + + n->rexpr_list_start = @4; + n->rexpr_list_end = @6; + $$ = (Node *) n; } | a_expr subquery_Op sub_type select_with_parens %prec Op { @@ -16681,15 +16882,15 @@ type_list: Typename { $$ = list_make1($1); } array_expr: '[' expr_list ']' { - $$ = makeAArrayExpr($2, @1); + $$ = makeAArrayExpr($2, @1, @3); } | '[' array_expr_list ']' { - $$ = makeAArrayExpr($2, @1); + $$ = makeAArrayExpr($2, @1, @3); } | '[' ']' { - $$ = makeAArrayExpr(NIL, @1); + $$ = makeAArrayExpr(NIL, @1, @2); } ; @@ -16811,17 +17012,6 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); } | expr_list { $$ = $1; } ; -in_expr: select_with_parens - { - SubLink *n = makeNode(SubLink); - - n->subselect = $1; - /* other fields will be filled later */ - $$ = (Node *) n; - } - | '(' expr_list ')' { $$ = (Node *) $2; } - ; - /* * Define SQL-style CASE clause. * - Full specification @@ -17022,7 +17212,8 @@ json_format_clause: else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized JSON encoding: %s", $4))); + errmsg("unrecognized JSON encoding: %s", $4), + parser_errposition(@4))); $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, encoding, @1); } @@ -17524,7 +17715,8 @@ PLpgSQL_Expr: opt_distinct_clause opt_target_list $9->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition($9->optionLoc))); n->limitOption = $9->limitOption; } n->lockingClause = $10; @@ -17708,6 +17900,7 @@ unreserved_keyword: | ENABLE_P | ENCODING | ENCRYPTED + | ENFORCED | ENUM_P | ERROR_P | ESCAPE @@ -17803,6 +17996,7 @@ unreserved_keyword: | NOWAIT | NULLS_P | OBJECT_P + | OBJECTS_P | OF | OFF | OIDS @@ -17825,6 +18019,7 @@ unreserved_keyword: | PASSING | PASSWORD | PATH + | PERIOD | PLAN | PLANS | POLICY @@ -17844,7 +18039,6 @@ unreserved_keyword: | RANGE | READ | REASSIGN - | RECHECK | RECURSIVE | REF_P | REFERENCING @@ -17941,6 +18135,7 @@ unreserved_keyword: | VERSION_P | VIEW | VIEWS + | VIRTUAL | VOLATILE | WHITESPACE_P | WITHIN @@ -18285,6 +18480,7 @@ bare_label_keyword: | ENCODING | ENCRYPTED | END_P + | ENFORCED | ENUM_P | ERROR_P | ESCAPE @@ -18423,6 +18619,7 @@ bare_label_keyword: | NULLS_P | NUMERIC | OBJECT_P + | OBJECTS_P | OF | OFF | OIDS @@ -18449,6 +18646,7 @@ bare_label_keyword: | PASSING | PASSWORD | PATH + | PERIOD | PLACING | PLAN | PLANS @@ -18472,7 +18670,6 @@ bare_label_keyword: | READ | REAL | REASSIGN - | RECHECK | RECURSIVE | REF_P | REFERENCES @@ -18595,6 +18792,7 @@ bare_label_keyword: | VERSION_P | VIEW | VIEWS + | VIRTUAL | VOLATILE | WHEN | WHITESPACE_P @@ -18666,10 +18864,10 @@ makeColumnRef(char *colname, List *indirection, int location, core_yyscan_t yyscanner) { /* - * Generate a ColumnRef node, with an A_Indirection node added if there - * is any subscripting in the specified indirection list. However, - * any field selection at the start of the indirection list must be - * transposed into the "fields" part of the ColumnRef node. + * Generate a ColumnRef node, with an A_Indirection node added if there is + * any subscripting in the specified indirection list. However, any field + * selection at the start of the indirection list must be transposed into + * the "fields" part of the ColumnRef node. */ ColumnRef *c = makeNode(ColumnRef); int nfields = 0; @@ -18744,7 +18942,7 @@ makeIntConst(int val, int location) n->val.ival.ival = val; n->location = location; - return (Node *)n; + return (Node *) n; } #endif @@ -18757,42 +18955,42 @@ makeFloatConst(char *str, int location) n->val.fval.fval = str; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * makeBoolAConst(bool state, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.boolval.type = T_Boolean; n->val.boolval.boolval = state; n->location = location; - return (Node *) n; + return (Node *) n; } static Node * makeBitStringConst(char *str, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.bsval.type = T_BitString; n->val.bsval.bsval = str; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * makeNullAConst(int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->isnull = true; n->location = location; - return (Node *)n; + return (Node *) n; } static Node * @@ -18876,7 +19074,7 @@ check_func_name(List *names, core_yyscan_t yyscanner) static List * check_indirection(List *indirection, core_yyscan_t yyscanner) { - ListCell *l; + ListCell *l; foreach(l, indirection) { @@ -18931,7 +19129,7 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, core_yyscan_t yyscanner) { FunctionParameter *lastd = (FunctionParameter *) llast(directargs); - Integer *ndirectargs; + Integer *ndirectargs; /* No restriction unless last direct arg is VARIADIC */ if (lastd->mode == FUNC_PARAM_VARIADIC) @@ -18939,15 +19137,15 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, FunctionParameter *firsto = (FunctionParameter *) linitial(orderedargs); /* - * We ignore the names, though the aggr_arg production allows them; - * it doesn't allow default values, so those need not be checked. + * We ignore the names, though the aggr_arg production allows them; it + * doesn't allow default values, so those need not be checked. */ if (list_length(orderedargs) != 1 || firsto->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"), - parser_errposition(exprLocation((Node *) firsto)))); + parser_errposition(firsto->location))); /* OK, drop the duplicate VARIADIC argument from the internal form */ orderedargs = NIL; @@ -18995,7 +19193,7 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple OFFSET clauses not allowed"), - parser_errposition(exprLocation(limitClause->limitOffset)))); + parser_errposition(limitClause->offsetLoc))); stmt->limitOffset = limitClause->limitOffset; } if (limitClause && limitClause->limitCount) @@ -19004,19 +19202,18 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple LIMIT clauses not allowed"), - parser_errposition(exprLocation(limitClause->limitCount)))); + parser_errposition(limitClause->countLoc))); stmt->limitCount = limitClause->limitCount; } if (limitClause) { - if (stmt->limitOption) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple limit options not allowed"))); + /* If there was a conflict, we must have detected it above */ + Assert(!stmt->limitOption); if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition(limitClause->optionLoc))); if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause) { ListCell *lc; @@ -19029,7 +19226,8 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s and %s options cannot be used together", - "SKIP LOCKED", "WITH TIES"))); + "SKIP LOCKED", "WITH TIES"), + parser_errposition(limitClause->optionLoc))); } } stmt->limitOption = limitClause->limitOption; @@ -19098,7 +19296,7 @@ doNegate(Node *n, int location) { if (IsA(n, A_Const)) { - A_Const *con = (A_Const *) n; + A_Const *con = (A_Const *) n; /* report the constant's location as that of the '-' sign */ con->location = location; @@ -19126,7 +19324,7 @@ doNegateFloat(Float *v) if (*oldval == '+') oldval++; if (*oldval == '-') - v->fval = oldval+1; /* just strip the '-' */ + v->fval = oldval + 1; /* just strip the '-' */ else v->fval = psprintf("-%s", oldval); } @@ -19172,12 +19370,14 @@ makeNotExpr(Node *expr, int location) } static Node * -makeAArrayExpr(List *elements, int location) +makeAArrayExpr(List *elements, int location, int location_end) { A_ArrayExpr *n = makeNode(A_ArrayExpr); n->elements = elements; n->location = location; + n->list_start = location; + n->list_end = location_end; return (Node *) n; } @@ -19197,10 +19397,11 @@ static Node * makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location) { - XmlExpr *x = makeNode(XmlExpr); + XmlExpr *x = makeNode(XmlExpr); x->op = op; x->name = name; + /* * named_args is a list of ResTarget; it'll be split apart into separate * expression and name lists in transformXmlExpr(). @@ -19210,7 +19411,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, x->args = args; /* xmloption, if relevant, must be filled in by caller */ /* type and typmod will be filled in during parse analysis */ - x->type = InvalidOid; /* marks the node as not analyzed */ + x->type = InvalidOid; /* marks the node as not analyzed */ x->location = location; return (Node *) x; } @@ -19219,7 +19420,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, * Merge the input and output parameters of a table function. */ static List * -mergeTableFuncParameters(List *func_args, List *columns) +mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner) { ListCell *lc; @@ -19233,7 +19434,8 @@ mergeTableFuncParameters(List *func_args, List *columns) p->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"))); + errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"), + parser_errposition(p->location))); } return list_concat(func_args, columns); @@ -19334,7 +19536,7 @@ makeRangeVarFromQualifiedName(char *name, List *namelist, int location, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", NameListToString(lcons(makeString(name), namelist))), - parser_errposition(location))); + parser_errposition(location))); break; } @@ -19385,8 +19587,8 @@ SplitColQualList(List *qualList, */ static void processCASbits(int cas_bits, int location, const char *constrType, - bool *deferrable, bool *initdeferred, bool *not_valid, - bool *no_inherit, core_yyscan_t yyscanner) + bool *deferrable, bool *initdeferred, bool *is_enforced, + bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner) { /* defaults */ if (deferrable) @@ -19395,6 +19597,8 @@ processCASbits(int cas_bits, int location, const char *constrType, *initdeferred = false; if (not_valid) *not_valid = false; + if (is_enforced) + *is_enforced = true; if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED)) { @@ -19403,7 +19607,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); @@ -19416,7 +19620,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); @@ -19429,7 +19633,7 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NOT VALID", constrType), parser_errposition(location))); @@ -19442,11 +19646,46 @@ processCASbits(int cas_bits, int location, const char *constrType, else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is CHECK, UNIQUE, or similar */ + /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NO INHERIT", constrType), parser_errposition(location))); } + + if (cas_bits & CAS_NOT_ENFORCED) + { + if (is_enforced) + *is_enforced = false; + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is CHECK, UNIQUE, or similar */ + errmsg("%s constraints cannot be marked NOT ENFORCED", + constrType), + parser_errposition(location))); + + /* + * NB: The validated status is irrelevant when the constraint is set to + * NOT ENFORCED, but for consistency, it should be set accordingly. + * This ensures that if the constraint is later changed to ENFORCED, it + * will automatically be in the correct NOT VALIDATED state. + */ + if (not_valid) + *not_valid = true; + } + + if (cas_bits & CAS_ENFORCED) + { + if (is_enforced) + *is_enforced = true; + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is CHECK, UNIQUE, or similar */ + errmsg("%s constraints cannot be marked ENFORCED", + constrType), + parser_errposition(location))); + } } /* @@ -19454,7 +19693,7 @@ processCASbits(int cas_bits, int location, const char *constrType, * PartitionStrategy representation, or die trying. */ static PartitionStrategy -parsePartitionStrategy(char *strategy) +parsePartitionStrategy(char *strategy, int location, core_yyscan_t yyscanner) { if (pg_strcasecmp(strategy, "list") == 0) return PARTITION_STRATEGY_LIST; @@ -19465,9 +19704,9 @@ parsePartitionStrategy(char *strategy) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized partitioning strategy \"%s\"", - strategy))); - return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ + errmsg("unrecognized partitioning strategy \"%s\"", strategy), + parser_errposition(location))); + return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ } @@ -19538,8 +19777,8 @@ preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner) parser_errposition(pubobj->location))); /* - * We can distinguish between the different type of schema - * objects based on whether name and pubtable is set. + * We can distinguish between the different type of schema objects + * based on whether name and pubtable is set. */ if (pubobj->name) pubobj->pubobjtype = PUBLICATIONOBJ_TABLES_IN_SCHEMA; @@ -19594,11 +19833,13 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) w->ctes = list_make1(cte); w->location = -1; - /* create target list for the new SELECT from the alias list of the - * recursive view specification */ - foreach (lc, aliases) + /* + * create target list for the new SELECT from the alias list of the + * recursive view specification + */ + foreach(lc, aliases) { - ResTarget *rt = makeNode(ResTarget); + ResTarget *rt = makeNode(ResTarget); rt->name = NULL; rt->indirection = NIL; @@ -19608,8 +19849,10 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) tl = lappend(tl, rt); } - /* create new SELECT combining WITH clause, target list, and fake FROM - * clause */ + /* + * create new SELECT combining WITH clause, target list, and fake FROM + * clause + */ s->withClause = w; s->targetList = tl; s->fromClause = list_make1(makeRangeVar(NULL, relname, -1)); diff --git a/src/parser/keywords.c b/src/parser/keywords.c index 83feb9f47..835ddfeb5 100644 --- a/src/parser/keywords.c +++ b/src/parser/keywords.c @@ -4,8 +4,8 @@ * PostgreSQL's list of SQL keywords * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/parser/kwlookup.c b/src/parser/kwlookup.c index d4364dc27..ff2498cf8 100644 --- a/src/parser/kwlookup.c +++ b/src/parser/kwlookup.c @@ -4,8 +4,8 @@ * Key word lookup for PostgreSQL * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/parser/list.c b/src/parser/list.c index 909517632..17f394fb0 100644 --- a/src/parser/list.c +++ b/src/parser/list.c @@ -5,8 +5,8 @@ * * See comments in pg_list.h * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/parser/makefuncs.c b/src/parser/makefuncs.c index 3777c66af..be807d982 100644 --- a/src/parser/makefuncs.c +++ b/src/parser/makefuncs.c @@ -4,8 +4,8 @@ * creator functions for various nodes. The functions here are for the * most frequently created nodes. * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -54,7 +54,7 @@ makeSimpleA_Expr(A_Expr_Kind kind, char *name, A_Expr *a = makeNode(A_Expr); a->kind = kind; - a->name = list_make1(makeString((char *) name)); + a->name = list_make1(makeString(name)); a->lexpr = lexpr; a->rexpr = rexpr; a->location = location; @@ -83,12 +83,14 @@ makeVar(int varno, var->varlevelsup = varlevelsup; /* - * Only a few callers need to make Var nodes with non-null varnullingrels, - * or with varnosyn/varattnosyn different from varno/varattno. We don't - * provide separate arguments for them, but just initialize them to NULL - * and the given varno/varattno. This reduces code clutter and chance of - * error for most callers. + * Only a few callers need to make Var nodes with varreturningtype + * different from VAR_RETURNING_DEFAULT, non-null varnullingrels, or with + * varnosyn/varattnosyn different from varno/varattno. We don't provide + * separate arguments for them, but just initialize them to sensible + * default values. This reduces code clutter and chance of error for most + * callers. */ + var->varreturningtype = VAR_RETURNING_DEFAULT; var->varnullingrels = NULL; var->varnosyn = (Index) varno; var->varattnosyn = varattno; @@ -163,6 +165,53 @@ makeWholeRowVar(RangeTblEntry *rte, varlevelsup); break; + case RTE_SUBQUERY: + + /* + * For a standard subquery, the Var should be of RECORD type. + * However, if we're looking at a subquery that was expanded from + * a view or SRF (only possible during planning), we must use the + * appropriate rowtype, so that the resulting Var has the same + * type that we would have produced from the original RTE. + */ + if (OidIsValid(rte->relid)) + { + /* Subquery was expanded from a view */ + toid = get_rel_type_id(rte->relid); + if (!OidIsValid(toid)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("relation \"%s\" does not have a composite type", + get_rel_name(rte->relid)))); + } + else if (rte->functions) + { + /* + * Subquery was expanded from a set-returning function. That + * would not have happened if there's more than one function + * or ordinality was requested. We also needn't worry about + * the allowScalar case, since the planner doesn't use that. + * Otherwise this must match the RTE_FUNCTION code below. + */ + Assert(!allowScalar); + fexpr = ((RangeTblFunction *) linitial(rte->functions))->funcexpr; + toid = exprType(fexpr); + if (!type_is_rowtype(toid)) + toid = RECORDOID; + } + else + { + /* Normal subquery-in-FROM */ + toid = RECORDOID; + } + result = makeVar(varno, + InvalidAttrNumber, + toid, + -1, + InvalidOid, + varlevelsup); + break; + case RTE_FUNCTION: /* @@ -219,8 +268,8 @@ makeWholeRowVar(RangeTblEntry *rte, default: /* - * RTE is a join, subselect, tablefunc, or VALUES. We represent - * this as a whole-row Var of RECORD type. (Note that in most + * RTE is a join, tablefunc, VALUES, CTE, etc. We represent these + * cases as a whole-row Var of RECORD type. (Note that in most * cases the Var will be expanded to a RowExpr during planning, * but that is not our concern here.) */ @@ -438,6 +487,30 @@ makeRangeVar(char *schemaname, char *relname, int location) } /* + * makeNotNullConstraint - + * creates a Constraint node for NOT NULL constraints + */ +Constraint * +makeNotNullConstraint(String *colname) +{ + Constraint *notnull; + + notnull = makeNode(Constraint); + notnull->contype = CONSTR_NOTNULL; + notnull->conname = NULL; + notnull->is_no_inherit = false; + notnull->deferrable = false; + notnull->initdeferred = false; + notnull->location = -1; + notnull->keys = list_make1(colname); + notnull->is_enforced = true; + notnull->skip_validation = false; + notnull->initially_valid = true; + + return notnull; +} + +/* * makeTypeName - * build a TypeName node for an unqualified name. * diff --git a/src/parser/outfuncs.c b/src/parser/outfuncs.c index f98af2b6e..529ac347c 100644 --- a/src/parser/outfuncs.c +++ b/src/parser/outfuncs.c @@ -3,8 +3,8 @@ * outfuncs.c * Output functions for Postgres tree nodes. * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -72,6 +72,7 @@ static void _outCoerceToDomainValue(StringInfo str, CoerceToDomainValue *node); static void _outSetToDefault(StringInfo str, SetToDefault *node); static void _outCurrentOfExpr(StringInfo str, CurrentOfExpr *node); static void _outInferenceElem(StringInfo str, InferenceElem *node); +static void _outReturningExpr(StringInfo str, ReturningExpr *node); static void _outTargetEntry(StringInfo str, TargetEntry *node); static void _outRangeTblRef(StringInfo str, RangeTblRef *node); static void _outJoinExpr(StringInfo str, JoinExpr *node); @@ -100,6 +101,8 @@ static void _outCTECycleClause(StringInfo str, CTECycleClause *node); static void _outCommonTableExpr(StringInfo str, CommonTableExpr *node); static void _outMergeWhenClauses(StringInfo str, List *node); static void _outMergeAction(StringInfo str, MergeAction *node); +static void _outReturningOption(StringInfo str, List *node); +static void _outReturningClause(StringInfo str, ReturningClause *node); static void _outSetOperationStmt(StringInfo str, SetOperationStmt *node); static void _outTableSampleClause(StringInfo str, TableSampleClause *node); static void _outA_Expr(StringInfo str, A_Expr *node); @@ -185,6 +188,7 @@ static void _outFuncName(StringInfo str, List *func_name); static void _outSetRest(StringInfo str, VariableSetStmt *node); static void _outSetTransactionModeList(StringInfo str, List *list); static void _outAlterTableCmd(StringInfo str, AlterTableCmd *node); +static void _outATAlterConstraint(StringInfo str, ATAlterConstraint *node); static void _outOptSeqList(StringInfo str, List *options); static void _outObjectWithArgs(StringInfo str, ObjectWithArgs *node); static void _outFunctionParameter(StringInfo str, FunctionParameter *node); @@ -811,6 +815,12 @@ _outInferenceElem(StringInfo str, InferenceElem *node) } static void +_outReturningExpr(StringInfo str, ReturningExpr *node) +{ + +} + +static void _outTargetEntry(StringInfo str, TargetEntry *node) { @@ -924,9 +934,17 @@ static void _outCreateStmt(StringInfo str, CreateStmt *node) { appendStringInfoString(str, "CREATE "); + if (node->relation->relpersistence == RELPERSISTENCE_TEMP) appendStringInfoString(str, "TEMP "); + else if (node->relation->relpersistence == RELPERSISTENCE_UNLOGGED) + appendStringInfoString(str, "UNLOGGED "); + appendStringInfoString(str, "TABLE "); + + if (node->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + _outNode(str, node->relation); appendStringInfoString(str, " ("); _outNode(str, node->tableElts); @@ -939,6 +957,12 @@ _outCreateStmt(StringInfo str, CreateStmt *node) appendStringInfoString(str, ")"); } + if (node->accessMethod) + { + appendStringInfoString(str, " USING "); + appendStringInfoString(str, node->accessMethod); + } + if (node->options) _outWithDefinition(str, node->options); @@ -972,9 +996,17 @@ static void _outCreateTableAsStmt(StringInfo str, CreateTableAsStmt *node) { appendStringInfoString(str, "CREATE "); + if (node->into->rel->relpersistence == RELPERSISTENCE_TEMP) appendStringInfoString(str, "TEMP "); + else if (node->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED) + appendStringInfoString(str, "UNLOGGED "); + appendStringInfoString(str, "TABLE "); + + if (node->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + _outNode(str, node->into->rel); if (node->into->colNames) @@ -984,6 +1016,12 @@ _outCreateTableAsStmt(StringInfo str, CreateTableAsStmt *node) appendStringInfoString(str, ") "); } + if (node->into->accessMethod) + { + appendStringInfoString(str, " USING "); + appendStringInfoString(str, node->into->accessMethod); + } + if (node->into->options) _outWithDefinition(str, node->into->options); @@ -1017,6 +1055,14 @@ _outCreateTableAsStmt(StringInfo str, CreateTableAsStmt *node) appendStringInfoString(str, " AS"); _outSelectStmt(str, (SelectStmt *) node->query); } + + if (node->into->skipData) + { + if (node->into->skipData == TRUE) + appendStringInfoString(str, " WITH NO DATA"); + else + appendStringInfoString(str, " WITH DATA"); + } } static void @@ -1180,6 +1226,8 @@ _outSelectStmt(StringInfo str, SelectStmt *node) appendStringInfoString(str, "CREATE "); if (rel->relpersistence == RELPERSISTENCE_TEMP) appendStringInfoString(str, "TEMP "); + else if (rel->relpersistence == RELPERSISTENCE_UNLOGGED) + appendStringInfoString(str, "UNLOGGED "); appendStringInfoString(str, "TABLE "); _outNode(str, into->rel); @@ -1835,6 +1883,48 @@ _outMergeAction(StringInfo str, MergeAction *node) } static void +_outReturningOption(StringInfo str, List *node) +{ + ListCell *lc; + char comma = 0; + + appendStringInfoString(str, "WITH ("); + + foreach(lc, node) + { + ReturningOption *r = (ReturningOption *) lfirst(lc); + + if (comma == 0) + comma = 1; + else + appendStringInfoString(str, ", "); + + if (r->option == RETURNING_OPTION_OLD) + appendStringInfoString(str, "OLD "); + else if (r->option == RETURNING_OPTION_NEW) + appendStringInfoString(str, "NEW "); + + appendStringInfoString(str, "AS "); + appendStringInfoString(str, "\""); + appendStringInfoString(str, r->value); + appendStringInfoString(str, "\""); + } + + appendStringInfoString(str, ") "); +} + +static void +_outReturningClause(StringInfo str, ReturningClause *node) +{ + + if (node->options) + _outReturningOption(str, node->options); + + if (node->exprs) + _outList(str, node->exprs); +} + +static void _outSetOperationStmt(StringInfo str, SetOperationStmt *node) { @@ -2604,10 +2694,10 @@ _outInsertStmt(StringInfo str, InsertStmt *node) _outOnConflictClause(str, node->onConflictClause); } - if (node->returningList) + if (node->returningClause) { appendStringInfoString(str, " RETURNING "); - _outNode(str, node->returningList); + _outNode(str, node->returningClause); } } @@ -2719,10 +2809,10 @@ _outUpdateStmt(StringInfo str, UpdateStmt *node) _outNode(str, node->whereClause); } - if (node->returningList) + if (node->returningClause) { appendStringInfoString(str, " RETURNING "); - _outNode(str, node->returningList); + _outNode(str, node->returningClause); } } @@ -2748,10 +2838,10 @@ _outDeleteStmt(StringInfo str, DeleteStmt *node) _outNode(str, node->whereClause); } - if (node->returningList) + if (node->returningClause) { appendStringInfoString(str, " RETURNING "); - _outNode(str, node->returningList); + _outNode(str, node->returningClause); } } @@ -2778,10 +2868,10 @@ _outMergeStmt(StringInfo str, MergeStmt *node) _outMergeWhenClauses(str, node->mergeWhenClauses); } - if (node->returningList) + if (node->returningClause) { appendStringInfoString(str, " RETURNING "); - _outNode(str, node->returningList); + _outNode(str, node->returningClause); } } @@ -3843,6 +3933,11 @@ _outAlterTableCmd(StringInfo str, AlterTableCmd *node) } static void +_outATAlterConstraint(StringInfo str, ATAlterConstraint *node) +{ +} + +static void _outAlterTableStmt(StringInfo str, AlterTableStmt *node) { if (node->objtype == OBJECT_TABLE) @@ -3912,9 +4007,17 @@ static void _outCreateSeqStmt(StringInfo str, CreateSeqStmt *node) { appendStringInfoString(str, "CREATE "); + if (node->sequence->relpersistence == RELPERSISTENCE_TEMP) appendStringInfoString(str, "TEMP "); + else if (node->sequence->relpersistence == RELPERSISTENCE_UNLOGGED) + appendStringInfoString(str, "UNLOGGED "); + appendStringInfoString(str, "SEQUENCE "); + + if (node->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + _outNode(str, node->sequence); _outOptSeqList(str, node->options); @@ -6076,11 +6179,6 @@ _outPartitionRangeDatum(StringInfo str, PartitionRangeDatum *node) { } -static void -_outSinglePartitionSpec(StringInfo str, const SinglePartitionSpec *node) -{ -} - /* * _outNode - * converts a Node into ascii string and append it to 'str' @@ -6297,6 +6395,9 @@ _outNode(StringInfo str, void *obj) case T_InferenceElem: _outInferenceElem(str, obj); break; + case T_ReturningExpr: + _outReturningExpr(str, obj); + break; case T_TargetEntry: _outTargetEntry(str, obj); break; @@ -6398,6 +6499,12 @@ _outNode(StringInfo str, void *obj) case T_MergeWhenClause: _outMergeWhenClauses(str, obj); break; + case T_ReturningOption: + _outReturningOption(str, obj); + break; + case T_ReturningClause: + _outReturningClause(str, obj); + break; case T_SetOperationStmt: _outSetOperationStmt(str, obj); break; @@ -6546,9 +6653,6 @@ _outNode(StringInfo str, void *obj) case T_PartitionRangeDatum: _outPartitionRangeDatum(str, obj); break; - case T_SinglePartitionSpec: - _outSinglePartitionSpec(str, obj); - break; case T_InsertStmt: _outInsertStmt(str, obj); @@ -6662,6 +6766,10 @@ _outNode(StringInfo str, void *obj) _outAlterTableCmd(str, obj); break; + case T_ATAlterConstraint: + _outATAlterConstraint(str, obj); + break; + case T_CreateSeqStmt: _outCreateSeqStmt(str, obj); break; diff --git a/src/parser/parser.c b/src/parser/parser.c index 878220be9..997c175fb 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -10,8 +10,8 @@ * analyze.c and related files. * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/parser/scan.l b/src/parser/scan.l index 03f86b5f1..011728cc8 100644 --- a/src/parser/scan.l +++ b/src/parser/scan.l @@ -22,8 +22,8 @@ * Postgres 9.2, this check is made automatically by the Makefile.) * * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -42,10 +42,12 @@ #include "scansup.h" #include "kwlookup.h" #include "pg_wchar.h" +#include "miscnodes.h" #include "gram.h" #include "utils/palloc.h" #include "utils/elog.h" +#include "utils/elog.h" } %{ @@ -96,12 +98,6 @@ const uint16 ScanKeywordTokens[] = { #define YYSTYPE core_YYSTYPE /* - * Set the type of yyextra. All state variables used by the scanner should - * be in yyextra, *not* statically allocated. - */ -#define YY_EXTRA_TYPE core_yy_extra_type * - -/* * Each call to yylex must set yylloc to the location of the found token * (expressed as a byte offset from the start of the input text). * When we parse a token that requires multiple lexer rules to process, @@ -142,15 +138,6 @@ static void addunicode(pg_wchar c, yyscan_t yyscanner); static void check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner); static void check_escape_warning(core_yyscan_t yyscanner); -/* - * Work around a bug in flex 2.5.35: it emits a couple of functions that - * it forgets to emit declarations for. Since we use -Wmissing-prototypes, - * this would cause warnings. Providing our own declarations should be - * harmless even when the bug gets fixed. - */ -extern int core_yyget_column(yyscan_t yyscanner); -extern void core_yyset_column(int column_no, yyscan_t yyscanner); - %} %option reentrant @@ -167,6 +154,7 @@ extern void core_yyset_column(int column_no, yyscan_t yyscanner); %option noyyfree %option warn %option prefix="core_yy" +%option extra-type="core_yy_extra_type *" /* * OK, here is a short description of lex/flex rules behavior. @@ -418,16 +406,30 @@ numericfail {decinteger}\.\. real ({decinteger}|{numeric})[Ee][-+]?{decinteger} realfail ({decinteger}|{numeric})[Ee][-+] -decinteger_junk {decinteger}{ident_start} -hexinteger_junk {hexinteger}{ident_start} -octinteger_junk {octinteger}{ident_start} -bininteger_junk {bininteger}{ident_start} -numeric_junk {numeric}{ident_start} -real_junk {real}{ident_start} - /* Positional parameters don't accept underscores. */ param \${decdigit}+ -param_junk \${decdigit}+{ident_start} + +/* + * An identifier immediately following an integer literal is disallowed because + * in some cases it's ambiguous what is meant: for example, 0x1234 could be + * either a hexinteger or a decinteger "0" and an identifier "x1234". We can + * detect such problems by seeing if integer_junk matches a longer substring + * than any of the XXXinteger patterns (decinteger, hexinteger, octinteger, + * bininteger). One "junk" pattern is sufficient because + * {decinteger}{identifier} will match all the same strings we'd match with + * {hexinteger}{identifier} etc. + * + * Note that the rule for integer_junk must appear after the ones for + * XXXinteger to make this work correctly: 0x1234 will match both hexinteger + * and integer_junk, and we need hexinteger to be chosen in that case. + * + * Also disallow strings matched by numeric_junk, real_junk and param_junk + * for consistency. + */ +integer_junk {decinteger}{identifier} +numeric_junk {numeric}{identifier} +real_junk {real}{identifier} +param_junk \${decdigit}+{identifier} other . @@ -1057,19 +1059,7 @@ other . SET_YYLLOC(); yyerror("trailing junk after numeric literal"); } -{decinteger_junk} { - SET_YYLLOC(); - yyerror("trailing junk after numeric literal"); - } -{hexinteger_junk} { - SET_YYLLOC(); - yyerror("trailing junk after numeric literal"); - } -{octinteger_junk} { - SET_YYLLOC(); - yyerror("trailing junk after numeric literal"); - } -{bininteger_junk} { +{integer_junk} { SET_YYLLOC(); yyerror("trailing junk after numeric literal"); } @@ -1210,7 +1200,7 @@ setup_scanner_errposition_callback(ScannerCallbackState *scbstate, scbstate->yyscanner = yyscanner; scbstate->location = location; scbstate->errcallback.callback = scb_error_callback; - scbstate->errcallback.arg = (void *) scbstate; + scbstate->errcallback.arg = scbstate; scbstate->errcallback.previous = error_context_stack; error_context_stack = &scbstate->errcallback; } @@ -1490,10 +1480,10 @@ check_escape_warning(core_yyscan_t yyscanner) ereport(WARNING, (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER), errmsg("nonstandard use of escape in a string literal"), - errhint("Use the escape string syntax for escapes, e.g., E'\\r\\n'."), + errhint("Use the escape string syntax for escapes, e.g., E'\\r\\n'."), lexer_errposition())); #endif - yyextra->warn_on_first_escape = false; /* warn only once per string */ + yyextra->warn_on_first_escape = false; /* warn only once per string */ } /* diff --git a/src/parser/scansup.c b/src/parser/scansup.c index 27df0468a..943fb358b 100644 --- a/src/parser/scansup.c +++ b/src/parser/scansup.c @@ -3,8 +3,8 @@ * scansup.c * scanner support routines used by the core lexer * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/parser/snprintf.c b/src/parser/snprintf.c index c3564935e..e82832f24 100644 --- a/src/parser/snprintf.c +++ b/src/parser/snprintf.c @@ -1,9 +1,9 @@ /* - * Copyright (c) 2003-2024, PgPool Global Development Group + * Copyright (c) 2003-2025, PgPool Global Development Group * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,17 +32,14 @@ * src/port/snprintf.c */ -#if 0 -#include "c.h" -#endif - +#include <ctype.h> +#include <errno.h> +#include <math.h> #include <stdarg.h> -#include <stdio.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> -#include <errno.h> #include "pool_parser.h" #include "stringinfo.h" #include "utils/palloc.h" @@ -397,13 +394,22 @@ static void leading_pad(int zpad, int signvalue, int *padlen, static void trailing_pad(int padlen, PrintfTarget * target); /* - * If strchrnul exists (it's a glibc-ism), it's a good bit faster than the - * equivalent manual loop. If it doesn't exist, provide a replacement. + * If strchrnul exists (it's a glibc-ism, but since adopted by some other + * platforms), it's a good bit faster than the equivalent manual loop. + * Use it if possible, and if it doesn't exist, use this replacement. * * Note: glibc declares this as returning "char *", but that would require * casting away const internally, so we don't follow that detail. + * + * Note: macOS has this too as of Sequoia 15.4, but it's hidden behind + * a deployment-target check that causes compile errors if the deployment + * target isn't high enough. So !HAVE_DECL_STRCHRNUL may mean "yes it's + * declared, but it doesn't compile". To avoid failing in that scenario, + * use a macro to avoid matching <string.h>'s name. */ -#ifndef HAVE_STRCHRNUL +#if !HAVE_DECL_STRCHRNUL + +#define strchrnul pg_strchrnul static inline const char * strchrnul(const char *s, int c) @@ -413,19 +419,7 @@ strchrnul(const char *s, int c) return s; } -#else - -/* - * glibc's <string.h> declares strchrnul only if _GNU_SOURCE is defined. - * While we typically use that on glibc platforms, configure will set - * HAVE_STRCHRNUL whether it's used or not. Fill in the missing declaration - * so that this file will compile cleanly with or without _GNU_SOURCE. - */ -#ifndef _GNU_SOURCE -extern char *strchrnul(const char *s, int c); -#endif - -#endif /* HAVE_STRCHRNUL */ +#endif /* !HAVE_DECL_STRCHRNUL */ /* @@ -619,6 +613,28 @@ nextch2: fmtpos = accum; accum = 0; goto nextch2; +#ifdef WIN32 + case 'I': + /* Windows PRI*{32,64,PTR} size */ + if (format[0] == '3' && format[1] == '2') + format += 2; + else if (format[0] == '6' && format[1] == '4') + { + format += 2; + longlongflag = 1; + } + else + { +#if SIZEOF_VOID_P == SIZEOF_LONG + longflag = 1; +#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG + longlongflag = 1; +#else +#error "cannot find integer type of the same size as intptr_t" +#endif + } + goto nextch2; +#endif case 'l': if (longflag) longlongflag = 1; @@ -626,16 +642,12 @@ nextch2: longflag = 1; goto nextch2; case 'z': -#if SIZEOF_SIZE_T == 8 -#ifdef HAVE_LONG_INT_64 +#if SIZEOF_SIZE_T == SIZEOF_LONG longflag = 1; -#elif defined(HAVE_LONG_LONG_INT_64) +#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG longlongflag = 1; #else -#error "Don't know how to print 64bit integers" -#endif -#else - /* assume size_t is same size as int */ +#error "cannot find integer type of the same size as size_t" #endif goto nextch2; case 'h': @@ -886,6 +898,28 @@ nextch1: fmtpos = accum; accum = 0; goto nextch1; +#ifdef WIN32 + case 'I': + /* Windows PRI*{32,64,PTR} size */ + if (format[0] == '3' && format[1] == '2') + format += 2; + else if (format[0] == '6' && format[1] == '4') + { + format += 2; + longlongflag = 1; + } + else + { +#if SIZEOF_VOID_P == SIZEOF_LONG + longflag = 1; +#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG + longlongflag = 1; +#else +#error "cannot find integer type of the same size as intptr_t" +#endif + } + goto nextch1; +#endif case 'l': if (longflag) longlongflag = 1; @@ -893,16 +927,12 @@ nextch1: longflag = 1; goto nextch1; case 'z': -#if SIZEOF_SIZE_T == 8 -#ifdef HAVE_LONG_INT_64 +#if SIZEOF_SIZE_T == SIZEOF_LONG longflag = 1; -#elif defined(HAVE_LONG_LONG_INT_64) +#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG longlongflag = 1; #else -#error "Don't know how to print 64bit integers" -#endif -#else - /* assume size_t is same size as int */ +#error "cannot find integer type of the same size as size_t" #endif goto nextch1; case 'h': diff --git a/src/parser/stringinfo.c b/src/parser/stringinfo.c index c35e5bacf..9429dac46 100644 --- a/src/parser/stringinfo.c +++ b/src/parser/stringinfo.c @@ -6,11 +6,11 @@ * It can be used to buffer either ordinary C strings (null-terminated text) * or arbitrary binary data. All storage is allocated with palloc(). * - * Portions Copyright (c) 2003-2024, PgPool Global Development Group - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2025, PgPool Global Development Group + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * src/backend/lib/stringinfo.c + * src/common/stringinfo.c * *------------------------------------------------------------------------- */ @@ -22,6 +22,40 @@ #include "utils/palloc.h" /* + * initStringInfoInternal + * + * Initialize a StringInfoData struct (with previously undefined contents) + * to describe an empty string. + * The initial memory allocation size is specified by 'initsize'. + * The valid range for 'initsize' is 1 to MaxAllocSize. + */ +static inline void +initStringInfoInternal(StringInfo str, int initsize) +{ + Assert(initsize >= 1 && initsize <= MaxAllocSize); + + str->data = (char *) palloc(initsize); + str->maxlen = initsize; + resetStringInfo(str); +} + +/* + * makeStringInfoInternal(int initsize) + * + * Create an empty 'StringInfoData' & return a pointer to it. + * The initial memory allocation size is specified by 'initsize'. + * The valid range for 'initsize' is 1 to MaxAllocSize. + */ +static inline StringInfo +makeStringInfoInternal(int initsize) +{ + StringInfo res = (StringInfo) palloc(sizeof(StringInfoData)); + + initStringInfoInternal(res, initsize); + return res; +} + +/* * makeStringInfo * * Create an empty 'StringInfoData' & return a pointer to it. @@ -29,13 +63,20 @@ StringInfo makeStringInfo(void) { - StringInfo res; - - res = (StringInfo) palloc(sizeof(StringInfoData)); - - initStringInfo(res); + return makeStringInfoInternal(STRINGINFO_DEFAULT_SIZE); +} - return res; +/* + * makeStringInfoExt(int initsize) + * + * Create an empty 'StringInfoData' & return a pointer to it. + * The initial memory allocation size is specified by 'initsize'. + * The valid range for 'initsize' is 1 to MaxAllocSize. + */ +StringInfo +makeStringInfoExt(int initsize) +{ + return makeStringInfoInternal(initsize); } /* @@ -47,11 +88,21 @@ makeStringInfo(void) void initStringInfo(StringInfo str) { - int size = 1024; /* initial default buffer size */ + initStringInfoInternal(str, STRINGINFO_DEFAULT_SIZE); +} - str->data = (char *) palloc(size); - str->maxlen = size; - resetStringInfo(str); +/* + * initStringInfoExt + * + * Initialize a StringInfoData struct (with previously undefined contents) + * to describe an empty string. + * The initial memory allocation size is specified by 'initsize'. + * The valid range for 'initsize' is 1 to MaxAllocSize. + */ +void +initStringInfoExt(StringInfo str, int initsize) +{ + initStringInfoInternal(str, initsize); } /* @@ -292,7 +343,7 @@ enlargeStringInfo(StringInfo str, int needed) if (((Size) needed) >= (MaxAllocSize - (Size) str->len)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("out of memory"), + errmsg("string buffer exceeds maximum allowed length (%zu bytes)", MaxAllocSize), errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.", str->len, needed))); #endif diff --git a/src/parser/value.c b/src/parser/value.c index 3b7ab09a8..f99883c5b 100644 --- a/src/parser/value.c +++ b/src/parser/value.c @@ -4,8 +4,8 @@ * implementation of value nodes * * - * Copyright (c) 2003-2024, PgPool Global Development Group - * Copyright (c) 2003-2024, PostgreSQL Global Development Group + * Copyright (c) 2003-2025, PgPool Global Development Group + * Copyright (c) 2003-2025, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/parser/wchar.c b/src/parser/wchar.c index 1e3a1b0ae..27c972fc0 100644 --- a/src/parser/wchar.c +++ b/src/parser/wchar.c @@ -9,6 +9,7 @@ #include "utils/elog.h" #include <stdio.h> #include <string.h> +#include <limits.h> #include "pg_wchar.h" #ifndef WIN32 @@ -115,6 +116,24 @@ const char *pg_enc2gettext_tbl[] = [PG_SHIFT_JIS_2004] = "SHIFT_JISX0213", }; +/* + * In today's multibyte encodings other than UTF8, this two-byte sequence + * ensures pg_encoding_mblen() == 2 && pg_encoding_verifymbstr() == 0. + * + * For historical reasons, several verifychar implementations opt to reject + * this pair specifically. Byte pair range constraints, in encoding + * originator documentation, always excluded this pair. No core conversion + * could translate it. However, longstanding verifychar implementations + * accepted any non-NUL byte. big5_to_euc_tw and big5_to_mic even translate + * pairs not valid per encoding originator documentation. To avoid tightening + * core or non-core conversions in a security patch, we sought this one pair. + * + * PQescapeString() historically used spaces for BYTE1; many other values + * could suffice for BYTE1. + */ +#define NONUTF8_INVALID_BYTE0 (0x8d) +#define NONUTF8_INVALID_BYTE1 (' ') + /* * Operations on multi-byte encodings are driven by a table of helper @@ -706,454 +725,8 @@ mbbisearch(pg_wchar ucs, const struct mbinterval *table, int max) static int ucs_wcwidth(pg_wchar ucs) { - /* sorted list of non-overlapping intervals of non-spacing characters */ - static const struct mbinterval nonspacing[] = { - {0x00AD, 0x00AD}, - {0x0300, 0x036F}, - {0x0483, 0x0489}, - {0x0591, 0x05BD}, - {0x05BF, 0x05BF}, - {0x05C1, 0x05C2}, - {0x05C4, 0x05C5}, - {0x05C7, 0x05C7}, - {0x0600, 0x0605}, - {0x0610, 0x061A}, - {0x061C, 0x061C}, - {0x064B, 0x065F}, - {0x0670, 0x0670}, - {0x06D6, 0x06DD}, - {0x06DF, 0x06E4}, - {0x06E7, 0x06E8}, - {0x06EA, 0x06ED}, - {0x070F, 0x070F}, - {0x0711, 0x0711}, - {0x0730, 0x074A}, - {0x07A6, 0x07B0}, - {0x07EB, 0x07F3}, - {0x07FD, 0x07FD}, - {0x0816, 0x0819}, - {0x081B, 0x0823}, - {0x0825, 0x0827}, - {0x0829, 0x082D}, - {0x0859, 0x085B}, - {0x0890, 0x089F}, - {0x08CA, 0x0902}, - {0x093A, 0x093A}, - {0x093C, 0x093C}, - {0x0941, 0x0948}, - {0x094D, 0x094D}, - {0x0951, 0x0957}, - {0x0962, 0x0963}, - {0x0981, 0x0981}, - {0x09BC, 0x09BC}, - {0x09C1, 0x09C4}, - {0x09CD, 0x09CD}, - {0x09E2, 0x09E3}, - {0x09FE, 0x0A02}, - {0x0A3C, 0x0A3C}, - {0x0A41, 0x0A51}, - {0x0A70, 0x0A71}, - {0x0A75, 0x0A75}, - {0x0A81, 0x0A82}, - {0x0ABC, 0x0ABC}, - {0x0AC1, 0x0AC8}, - {0x0ACD, 0x0ACD}, - {0x0AE2, 0x0AE3}, - {0x0AFA, 0x0B01}, - {0x0B3C, 0x0B3C}, - {0x0B3F, 0x0B3F}, - {0x0B41, 0x0B44}, - {0x0B4D, 0x0B56}, - {0x0B62, 0x0B63}, - {0x0B82, 0x0B82}, - {0x0BC0, 0x0BC0}, - {0x0BCD, 0x0BCD}, - {0x0C00, 0x0C00}, - {0x0C04, 0x0C04}, - {0x0C3C, 0x0C3C}, - {0x0C3E, 0x0C40}, - {0x0C46, 0x0C56}, - {0x0C62, 0x0C63}, - {0x0C81, 0x0C81}, - {0x0CBC, 0x0CBC}, - {0x0CBF, 0x0CBF}, - {0x0CC6, 0x0CC6}, - {0x0CCC, 0x0CCD}, - {0x0CE2, 0x0CE3}, - {0x0D00, 0x0D01}, - {0x0D3B, 0x0D3C}, - {0x0D41, 0x0D44}, - {0x0D4D, 0x0D4D}, - {0x0D62, 0x0D63}, - {0x0D81, 0x0D81}, - {0x0DCA, 0x0DCA}, - {0x0DD2, 0x0DD6}, - {0x0E31, 0x0E31}, - {0x0E34, 0x0E3A}, - {0x0E47, 0x0E4E}, - {0x0EB1, 0x0EB1}, - {0x0EB4, 0x0EBC}, - {0x0EC8, 0x0ECE}, - {0x0F18, 0x0F19}, - {0x0F35, 0x0F35}, - {0x0F37, 0x0F37}, - {0x0F39, 0x0F39}, - {0x0F71, 0x0F7E}, - {0x0F80, 0x0F84}, - {0x0F86, 0x0F87}, - {0x0F8D, 0x0FBC}, - {0x0FC6, 0x0FC6}, - {0x102D, 0x1030}, - {0x1032, 0x1037}, - {0x1039, 0x103A}, - {0x103D, 0x103E}, - {0x1058, 0x1059}, - {0x105E, 0x1060}, - {0x1071, 0x1074}, - {0x1082, 0x1082}, - {0x1085, 0x1086}, - {0x108D, 0x108D}, - {0x109D, 0x109D}, - {0x135D, 0x135F}, - {0x1712, 0x1714}, - {0x1732, 0x1733}, - {0x1752, 0x1753}, - {0x1772, 0x1773}, - {0x17B4, 0x17B5}, - {0x17B7, 0x17BD}, - {0x17C6, 0x17C6}, - {0x17C9, 0x17D3}, - {0x17DD, 0x17DD}, - {0x180B, 0x180F}, - {0x1885, 0x1886}, - {0x18A9, 0x18A9}, - {0x1920, 0x1922}, - {0x1927, 0x1928}, - {0x1932, 0x1932}, - {0x1939, 0x193B}, - {0x1A17, 0x1A18}, - {0x1A1B, 0x1A1B}, - {0x1A56, 0x1A56}, - {0x1A58, 0x1A60}, - {0x1A62, 0x1A62}, - {0x1A65, 0x1A6C}, - {0x1A73, 0x1A7F}, - {0x1AB0, 0x1B03}, - {0x1B34, 0x1B34}, - {0x1B36, 0x1B3A}, - {0x1B3C, 0x1B3C}, - {0x1B42, 0x1B42}, - {0x1B6B, 0x1B73}, - {0x1B80, 0x1B81}, - {0x1BA2, 0x1BA5}, - {0x1BA8, 0x1BA9}, - {0x1BAB, 0x1BAD}, - {0x1BE6, 0x1BE6}, - {0x1BE8, 0x1BE9}, - {0x1BED, 0x1BED}, - {0x1BEF, 0x1BF1}, - {0x1C2C, 0x1C33}, - {0x1C36, 0x1C37}, - {0x1CD0, 0x1CD2}, - {0x1CD4, 0x1CE0}, - {0x1CE2, 0x1CE8}, - {0x1CED, 0x1CED}, - {0x1CF4, 0x1CF4}, - {0x1CF8, 0x1CF9}, - {0x1DC0, 0x1DFF}, - {0x200B, 0x200F}, - {0x202A, 0x202E}, - {0x2060, 0x206F}, - {0x20D0, 0x20F0}, - {0x2CEF, 0x2CF1}, - {0x2D7F, 0x2D7F}, - {0x2DE0, 0x2DFF}, - {0x302A, 0x302D}, - {0x3099, 0x309A}, - {0xA66F, 0xA672}, - {0xA674, 0xA67D}, - {0xA69E, 0xA69F}, - {0xA6F0, 0xA6F1}, - {0xA802, 0xA802}, - {0xA806, 0xA806}, - {0xA80B, 0xA80B}, - {0xA825, 0xA826}, - {0xA82C, 0xA82C}, - {0xA8C4, 0xA8C5}, - {0xA8E0, 0xA8F1}, - {0xA8FF, 0xA8FF}, - {0xA926, 0xA92D}, - {0xA947, 0xA951}, - {0xA980, 0xA982}, - {0xA9B3, 0xA9B3}, - {0xA9B6, 0xA9B9}, - {0xA9BC, 0xA9BD}, - {0xA9E5, 0xA9E5}, - {0xAA29, 0xAA2E}, - {0xAA31, 0xAA32}, - {0xAA35, 0xAA36}, - {0xAA43, 0xAA43}, - {0xAA4C, 0xAA4C}, - {0xAA7C, 0xAA7C}, - {0xAAB0, 0xAAB0}, - {0xAAB2, 0xAAB4}, - {0xAAB7, 0xAAB8}, - {0xAABE, 0xAABF}, - {0xAAC1, 0xAAC1}, - {0xAAEC, 0xAAED}, - {0xAAF6, 0xAAF6}, - {0xABE5, 0xABE5}, - {0xABE8, 0xABE8}, - {0xABED, 0xABED}, - {0xFB1E, 0xFB1E}, - {0xFE00, 0xFE0F}, - {0xFE20, 0xFE2F}, - {0xFEFF, 0xFEFF}, - {0xFFF9, 0xFFFB}, - {0x101FD, 0x101FD}, - {0x102E0, 0x102E0}, - {0x10376, 0x1037A}, - {0x10A01, 0x10A0F}, - {0x10A38, 0x10A3F}, - {0x10AE5, 0x10AE6}, - {0x10D24, 0x10D27}, - {0x10EAB, 0x10EAC}, - {0x10EFD, 0x10EFF}, - {0x10F46, 0x10F50}, - {0x10F82, 0x10F85}, - {0x11001, 0x11001}, - {0x11038, 0x11046}, - {0x11070, 0x11070}, - {0x11073, 0x11074}, - {0x1107F, 0x11081}, - {0x110B3, 0x110B6}, - {0x110B9, 0x110BA}, - {0x110BD, 0x110BD}, - {0x110C2, 0x110CD}, - {0x11100, 0x11102}, - {0x11127, 0x1112B}, - {0x1112D, 0x11134}, - {0x11173, 0x11173}, - {0x11180, 0x11181}, - {0x111B6, 0x111BE}, - {0x111C9, 0x111CC}, - {0x111CF, 0x111CF}, - {0x1122F, 0x11231}, - {0x11234, 0x11234}, - {0x11236, 0x11237}, - {0x1123E, 0x1123E}, - {0x11241, 0x11241}, - {0x112DF, 0x112DF}, - {0x112E3, 0x112EA}, - {0x11300, 0x11301}, - {0x1133B, 0x1133C}, - {0x11340, 0x11340}, - {0x11366, 0x11374}, - {0x11438, 0x1143F}, - {0x11442, 0x11444}, - {0x11446, 0x11446}, - {0x1145E, 0x1145E}, - {0x114B3, 0x114B8}, - {0x114BA, 0x114BA}, - {0x114BF, 0x114C0}, - {0x114C2, 0x114C3}, - {0x115B2, 0x115B5}, - {0x115BC, 0x115BD}, - {0x115BF, 0x115C0}, - {0x115DC, 0x115DD}, - {0x11633, 0x1163A}, - {0x1163D, 0x1163D}, - {0x1163F, 0x11640}, - {0x116AB, 0x116AB}, - {0x116AD, 0x116AD}, - {0x116B0, 0x116B5}, - {0x116B7, 0x116B7}, - {0x1171D, 0x1171F}, - {0x11722, 0x11725}, - {0x11727, 0x1172B}, - {0x1182F, 0x11837}, - {0x11839, 0x1183A}, - {0x1193B, 0x1193C}, - {0x1193E, 0x1193E}, - {0x11943, 0x11943}, - {0x119D4, 0x119DB}, - {0x119E0, 0x119E0}, - {0x11A01, 0x11A0A}, - {0x11A33, 0x11A38}, - {0x11A3B, 0x11A3E}, - {0x11A47, 0x11A47}, - {0x11A51, 0x11A56}, - {0x11A59, 0x11A5B}, - {0x11A8A, 0x11A96}, - {0x11A98, 0x11A99}, - {0x11C30, 0x11C3D}, - {0x11C3F, 0x11C3F}, - {0x11C92, 0x11CA7}, - {0x11CAA, 0x11CB0}, - {0x11CB2, 0x11CB3}, - {0x11CB5, 0x11CB6}, - {0x11D31, 0x11D45}, - {0x11D47, 0x11D47}, - {0x11D90, 0x11D91}, - {0x11D95, 0x11D95}, - {0x11D97, 0x11D97}, - {0x11EF3, 0x11EF4}, - {0x11F00, 0x11F01}, - {0x11F36, 0x11F3A}, - {0x11F40, 0x11F40}, - {0x11F42, 0x11F42}, - {0x13430, 0x13440}, - {0x13447, 0x13455}, - {0x16AF0, 0x16AF4}, - {0x16B30, 0x16B36}, - {0x16F4F, 0x16F4F}, - {0x16F8F, 0x16F92}, - {0x16FE4, 0x16FE4}, - {0x1BC9D, 0x1BC9E}, - {0x1BCA0, 0x1CF46}, - {0x1D167, 0x1D169}, - {0x1D173, 0x1D182}, - {0x1D185, 0x1D18B}, - {0x1D1AA, 0x1D1AD}, - {0x1D242, 0x1D244}, - {0x1DA00, 0x1DA36}, - {0x1DA3B, 0x1DA6C}, - {0x1DA75, 0x1DA75}, - {0x1DA84, 0x1DA84}, - {0x1DA9B, 0x1DAAF}, - {0x1E000, 0x1E02A}, - {0x1E08F, 0x1E08F}, - {0x1E130, 0x1E136}, - {0x1E2AE, 0x1E2AE}, - {0x1E2EC, 0x1E2EF}, - {0x1E4EC, 0x1E4EF}, - {0x1E8D0, 0x1E8D6}, - {0x1E944, 0x1E94A}, - {0xE0001, 0xE01EF}, - }; - - static const struct mbinterval east_asian_fw[] = { - {0x1100, 0x115F}, - {0x231A, 0x231B}, - {0x2329, 0x232A}, - {0x23E9, 0x23EC}, - {0x23F0, 0x23F0}, - {0x23F3, 0x23F3}, - {0x25FD, 0x25FE}, - {0x2614, 0x2615}, - {0x2648, 0x2653}, - {0x267F, 0x267F}, - {0x2693, 0x2693}, - {0x26A1, 0x26A1}, - {0x26AA, 0x26AB}, - {0x26BD, 0x26BE}, - {0x26C4, 0x26C5}, - {0x26CE, 0x26CE}, - {0x26D4, 0x26D4}, - {0x26EA, 0x26EA}, - {0x26F2, 0x26F3}, - {0x26F5, 0x26F5}, - {0x26FA, 0x26FA}, - {0x26FD, 0x26FD}, - {0x2705, 0x2705}, - {0x270A, 0x270B}, - {0x2728, 0x2728}, - {0x274C, 0x274C}, - {0x274E, 0x274E}, - {0x2753, 0x2755}, - {0x2757, 0x2757}, - {0x2795, 0x2797}, - {0x27B0, 0x27B0}, - {0x27BF, 0x27BF}, - {0x2B1B, 0x2B1C}, - {0x2B50, 0x2B50}, - {0x2B55, 0x2B55}, - {0x2E80, 0x2E99}, - {0x2E9B, 0x2EF3}, - {0x2F00, 0x2FD5}, - {0x2FF0, 0x303E}, - {0x3041, 0x3096}, - {0x3099, 0x30FF}, - {0x3105, 0x312F}, - {0x3131, 0x318E}, - {0x3190, 0x31E3}, - {0x31EF, 0x321E}, - {0x3220, 0x3247}, - {0x3250, 0x4DBF}, - {0x4E00, 0xA48C}, - {0xA490, 0xA4C6}, - {0xA960, 0xA97C}, - {0xAC00, 0xD7A3}, - {0xF900, 0xFAFF}, - {0xFE10, 0xFE19}, - {0xFE30, 0xFE52}, - {0xFE54, 0xFE66}, - {0xFE68, 0xFE6B}, - {0xFF01, 0xFF60}, - {0xFFE0, 0xFFE6}, - {0x16FE0, 0x16FE4}, - {0x16FF0, 0x16FF1}, - {0x17000, 0x187F7}, - {0x18800, 0x18CD5}, - {0x18D00, 0x18D08}, - {0x1AFF0, 0x1AFF3}, - {0x1AFF5, 0x1AFFB}, - {0x1AFFD, 0x1AFFE}, - {0x1B000, 0x1B122}, - {0x1B150, 0x1B152}, - {0x1B164, 0x1B167}, - {0x1B170, 0x1B2FB}, - {0x1F004, 0x1F004}, - {0x1F0CF, 0x1F0CF}, - {0x1F18E, 0x1F18E}, - {0x1F191, 0x1F19A}, - {0x1F200, 0x1F202}, - {0x1F210, 0x1F23B}, - {0x1F240, 0x1F248}, - {0x1F250, 0x1F251}, - {0x1F260, 0x1F265}, - {0x1F300, 0x1F320}, - {0x1F32D, 0x1F335}, - {0x1F337, 0x1F37C}, - {0x1F37E, 0x1F393}, - {0x1F3A0, 0x1F3CA}, - {0x1F3CF, 0x1F3D3}, - {0x1F3E0, 0x1F3F0}, - {0x1F3F4, 0x1F3F4}, - {0x1F3F8, 0x1F43E}, - {0x1F440, 0x1F440}, - {0x1F442, 0x1F4FC}, - {0x1F4FF, 0x1F53D}, - {0x1F54B, 0x1F54E}, - {0x1F550, 0x1F567}, - {0x1F57A, 0x1F57A}, - {0x1F595, 0x1F596}, - {0x1F5A4, 0x1F5A4}, - {0x1F5FB, 0x1F64F}, - {0x1F680, 0x1F6C5}, - {0x1F6CC, 0x1F6CC}, - {0x1F6D0, 0x1F6D2}, - {0x1F6D5, 0x1F6D7}, - {0x1F6DD, 0x1F6DF}, - {0x1F6EB, 0x1F6EC}, - {0x1F6F4, 0x1F6FC}, - {0x1F7E0, 0x1F7EB}, - {0x1F7F0, 0x1F7F0}, - {0x1F90C, 0x1F93A}, - {0x1F93C, 0x1F945}, - {0x1F947, 0x1F9FF}, - {0x1FA70, 0x1FA74}, - {0x1FA78, 0x1FA7C}, - {0x1FA80, 0x1FA86}, - {0x1FA90, 0x1FAAC}, - {0x1FAB0, 0x1FABA}, - {0x1FAC0, 0x1FAC5}, - {0x1FAD0, 0x1FAD9}, - {0x1FAE0, 0x1FAE7}, - {0x1FAF0, 0x1FAF6}, - {0x20000, 0x2FFFD}, - {0x30000, 0x3FFFD}, - }; +#include "unicode_nonspacing_table.h" +#include "unicode_east_asian_fw_table.h" /* test for 8-bit control characters */ if (ucs == 0) @@ -2010,6 +1583,11 @@ pg_big5_verifychar(const unsigned char *s, int len) if (len < l) return -1; + if (l == 2 && + s[0] == NONUTF8_INVALID_BYTE0 && + s[1] == NONUTF8_INVALID_BYTE1) + return -1; + while (--l > 0) { if (*++s == '\0') @@ -2059,6 +1637,11 @@ pg_gbk_verifychar(const unsigned char *s, int len) if (len < l) return -1; + if (l == 2 && + s[0] == NONUTF8_INVALID_BYTE0 && + s[1] == NONUTF8_INVALID_BYTE1) + return -1; + while (--l > 0) { if (*++s == '\0') @@ -2108,6 +1691,11 @@ pg_uhc_verifychar(const unsigned char *s, int len) if (len < l) return -1; + if (l == 2 && + s[0] == NONUTF8_INVALID_BYTE0 && + s[1] == NONUTF8_INVALID_BYTE1) + return -1; + while (--l > 0) { if (*++s == '\0') @@ -2631,6 +2219,19 @@ pg_eucjp_increment(unsigned char *charptr, int length) /* + * Fills the provided buffer with two bytes such that: + * pg_encoding_mblen(dst) == 2 && pg_encoding_verifymbstr(dst) == 0 + */ +void +pg_encoding_set_invalid(int encoding, char *dst) +{ + Assert(pg_encoding_max_length(encoding) > 1); + + dst[0] = (encoding == PG_UTF8 ? 0xc0 : NONUTF8_INVALID_BYTE0); + dst[1] = NONUTF8_INVALID_BYTE1; +} + +/* *------------------------------------------------------------------- * encoding info table *------------------------------------------------------------------- @@ -2683,10 +2284,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) @@ -2697,8 +2315,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()). */ int pg_encoding_mblen_bounded(int encoding, const char *mbstr) @@ -2751,7 +2389,13 @@ pg_encoding_max_length(int encoding) { Assert(PG_VALID_ENCODING(encoding)); - return pg_wchar_table[encoding].maxmblen; + /* + * Check for the encoding despite the assert, due to some mingw versions + * otherwise issuing bogus warnings. + */ + return PG_VALID_ENCODING(encoding) ? + pg_wchar_table[encoding].maxmblen : + pg_wchar_table[PG_SQL_ASCII].maxmblen; } #ifndef FRONTEND diff --git a/src/pcp_con/pcp_worker.c b/src/pcp_con/pcp_worker.c index a9d02e011..72bf68d84 100644 --- a/src/pcp_con/pcp_worker.c +++ b/src/pcp_con/pcp_worker.c @@ -933,9 +933,9 @@ inform_node_info(PCP_CONNECTION *frontend, char *buf) snprintf(standby_delay_by_time_str, sizeof(standby_delay_by_time_str), "%d", bi->standby_delay_by_time); - snprintf(standby_delay_str, sizeof(standby_delay_str), UINT64_FORMAT, bi->standby_delay); + snprintf(standby_delay_str, sizeof(standby_delay_str), "%lld", (long long) bi->standby_delay); - snprintf(status_changed_time_str, sizeof(status_changed_time_str), UINT64_FORMAT, bi->status_changed_time); + snprintf(status_changed_time_str, sizeof(status_changed_time_str), "%lld", (long long) bi->status_changed_time); pcp_write(frontend, "i", 1); wsize = htonl(sizeof(code) + diff --git a/src/pcp_con/recovery.c b/src/pcp_con/recovery.c index 8ad4a2fd5..84e4ddc17 100644 --- a/src/pcp_con/recovery.c +++ b/src/pcp_con/recovery.c @@ -482,7 +482,7 @@ connect_backend_libpq(BackendInfo *backend) port_str, NULL, NULL, - pool_config->recovery_database, + dbname, pool_config->recovery_user, password ? password : ""); diff --git a/src/pgpool.spec b/src/pgpool.spec index 6795c7f5f..c93eb37a3 100644 --- a/src/pgpool.spec +++ b/src/pgpool.spec @@ -21,7 +21,8 @@ %endif %global _varrundir %{_localstatedir}/run/pgpool -%global _varlogdir %{_localstatedir}/log/pgpool_log +%global _varlogdir %{_localstatedir}/log/pgpool +%global _varlibdir %{_localstatedir}/lib/pgpool Summary: Pgpool is a connection pooling/replication server for PostgreSQL Name: pgpool-II-pg%{pg_version} @@ -45,6 +46,7 @@ Patch1: pgpool_socket_dir.patch Patch2: pcp_unix_domain_path.patch %endif Patch3: pgpool_log.patch +Patch4: pgpool.conf.sample.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: postgresql%{pg_version}-devel pam-devel openssl-devel jade libxslt docbook-dtds docbook-style-xsl docbook-style-dsssl openldap-devel %if %{rhel} >= 9 @@ -71,7 +73,7 @@ Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscripts %endif -Obsoletes: postgresql-pgpool +Obsoletes: postgresql-pgpool < %{version} # original pgpool archive name %define archive_name pgpool-II-%{version} @@ -107,6 +109,7 @@ PostgreSQL extensions libraries and sql files for pgpool-II. %patch2 -p0 %endif %patch3 -p0 +%patch4 -p0 %build %configure --with-pgsql=%{pghome} \ @@ -177,6 +180,7 @@ install -m 755 %{SOURCE1} %{buildroot}%{_initrddir}/pgpool %endif mkdir -p %{buildroot}%{_varlogdir} +mkdir -p %{buildroot}%{_varlibdir} install -d %{buildroot}%{_sysconfdir}/sysconfig %if 0%{rhel} && 0%{rhel} <= 6 @@ -290,6 +294,7 @@ fi %{_initrddir}/pgpool %endif %attr(0755,postgres,postgres) %dir %{_varlogdir} +%attr(0755,postgres,postgres) %dir %{_varlibdir} %defattr(600,postgres,postgres,-) %{_sysconfdir}/%{short_name}/pgpool.conf.sample %{_sysconfdir}/%{short_name}/pcp.conf.sample @@ -340,6 +345,8 @@ fi %{pghome}/share/extension/pgpool_adm--1.3--1.4.sql %{pghome}/share/extension/pgpool_adm--1.5.sql %{pghome}/share/extension/pgpool_adm--1.4--1.5.sql +%{pghome}/share/extension/pgpool_adm--1.6.sql +%{pghome}/share/extension/pgpool_adm--1.5--1.6.sql %{pghome}/share/extension/pgpool_adm.control %{pghome}/lib/pgpool_adm.so # From PostgreSQL 9.4 pgpool-regclass.so is not needed anymore @@ -360,6 +367,10 @@ fi %endif %changelog +* Tue Oct 14 2025 Taiki Koshino <koshino@sraoss.co.jp> 4.7.0 +- Change the value of log_directory parameter to '/var/log/pgpool'. +- Create '/var/lib/pgpool' and set it to work_dir. + * Wed Nov 2 2022 Bo Peng <pengbo@sraoss.co.jp> 4.4.0 - Change /lib/tmpfiles.d/ file from /var/run to /run - Install /etc/sudoers.d/pgpool diff --git a/src/protocol/CommandComplete.c b/src/protocol/CommandComplete.c index ef144ca31..a3b8f0ea1 100644 --- a/src/protocol/CommandComplete.c +++ b/src/protocol/CommandComplete.c @@ -5,7 +5,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2024 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -111,8 +111,8 @@ CommandComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, bool c if (session_context->query_context && session_context->query_context->parse_tree && is_start_transaction_query(session_context->query_context->parse_tree)) - TSTATE(backend, i) = 'T'; /* we are inside a transaction */ { + TSTATE(backend, i) = 'T'; /* we are inside a transaction */ ereport(DEBUG1, (errmsg("processing command complete"), errdetail("set transaction state to T"))); diff --git a/src/protocol/child.c b/src/protocol/child.c index cf2161806..c34f05728 100644 --- a/src/protocol/child.c +++ b/src/protocol/child.c @@ -772,8 +772,11 @@ read_startup_packet(POOL_CONNECTION *cp) } /* The database defaults to their user name. */ - if (sp->database == NULL || sp->database[0] == '\0') + if (sp->database == NULL) + sp->database = pstrdup(sp->user); + else if (sp->database[0] == '\0') { + pfree(sp->database); sp->database = pstrdup(sp->user); } @@ -838,50 +841,7 @@ connect_using_existing_connection(POOL_CONNECTION *frontend, if (MAJOR(backend) == 3) { - char command_buf[1024]; - - /* - * If we have received application_name in the start up packet, we - * send SET command to backend. Also we add or replace existing - * application_name data. - */ - if (sp->application_name) - { - snprintf(command_buf, sizeof(command_buf), "SET application_name TO '%s'", sp->application_name); - - for (i = 0; i < NUM_BACKENDS; i++) - { - if (VALID_BACKEND(i)) - { - /* - * We want to catch and ignore errors in do_command if a - * backend is just going down right now. Otherwise - * do_command raises an error and disconnects the - * connection to frontend. We can safely ignore error from - * "SET application_name" command if the backend goes - * down. - */ - PG_TRY(); - { - do_command(frontend, CONNECTION(backend, i), - command_buf, MAJOR(backend), - MAIN_CONNECTION(backend)->pid, - MAIN_CONNECTION(backend)->key, - MAIN_CONNECTION(backend)->keylen, 0); - } - PG_CATCH(); - { - /* ignore the error message */ - MemoryContextSwitchTo(oldContext); - FlushErrorState(); - } - PG_END_TRY(); - } - } - pool_add_param(&MAIN(backend)->params, "application_name", sp->application_name); - set_application_name_with_string(sp->application_name); - } - + /* Send parameter status message to frontend. */ send_params(frontend, backend); } @@ -1337,6 +1297,8 @@ send_params(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) pool_write(frontend, &sendlen, sizeof(sendlen)); pool_write(frontend, name, strlen(name) + 1); pool_write(frontend, value, strlen(value) + 1); + elog(DEBUG1, "send parameter status message to frontend: \"%s\" = \"%s\"", + name, value); } if (pool_flush(frontend)) diff --git a/src/protocol/pool_connection_pool.c b/src/protocol/pool_connection_pool.c index c3b369dc2..b16ccc39e 100644 --- a/src/protocol/pool_connection_pool.c +++ b/src/protocol/pool_connection_pool.c @@ -302,10 +302,10 @@ pool_create_cp(void) ereport(DEBUG1, (errmsg("creating connection pool"), - errdetail("user: %s database: %s closetime: %ld", + errdetail("user: %s database: %s closetime: %lld", CONNECTION_SLOT(p, main_node_id)->sp->user, CONNECTION_SLOT(p, main_node_id)->sp->database, - CONNECTION_SLOT(p, main_node_id)->closetime))); + (long long) CONNECTION_SLOT(p, main_node_id)->closetime))); if (CONNECTION_SLOT(p, main_node_id)->closetime < closetime) { @@ -366,7 +366,7 @@ pool_connection_pool_timer(POOL_CONNECTION_POOL *backend) ereport(DEBUG1, (errmsg("setting backend connection close timer"), - errdetail("close time %ld", time(NULL)))); + errdetail("close time %lld", (long long) time(NULL)))); /* Set connection close time */ for (i = 0; i < NUM_BACKENDS; i++) @@ -424,7 +424,7 @@ pool_backend_timer(void) now = time(NULL); ereport(DEBUG1, - (errmsg("backend timer handler called at %ld", now))); + (errmsg("backend timer handler called at %lld", (long long) now))); for (i = 0; i < pool_config->max_pool; i++, p++) { @@ -442,8 +442,8 @@ pool_backend_timer(void) ereport(DEBUG1, (errmsg("backend timer handler called"), - errdetail("expire time: %ld", - MAIN_CONNECTION(p)->closetime + pool_config->connection_life_time))); + errdetail("expire time: %lld", + (long long) (MAIN_CONNECTION(p)->closetime + pool_config->connection_life_time)))); if (now >= (MAIN_CONNECTION(p)->closetime + pool_config->connection_life_time)) { diff --git a/src/protocol/pool_process_query.c b/src/protocol/pool_process_query.c index 467e50baa..0dacbcbc4 100644 --- a/src/protocol/pool_process_query.c +++ b/src/protocol/pool_process_query.c @@ -879,6 +879,14 @@ SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, pool_write(CONNECTION(backend, i), &kind, 1); pool_write_and_flush(CONNECTION(backend, i), &sendlen, sizeof(sendlen)); + /* If sync message, emit log */ + if (kind == 'S') + { + char *str = "Sync"; + + per_node_statement_log(backend, i, str); + per_node_statement_notice(backend, i, str); + } } } return POOL_CONTINUE; @@ -3847,9 +3855,10 @@ read_kind_from_backend(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, /* * If we are in in streaming replication mode and we doing an extended * query, check the kind we just read. If it's one of 'D' (data row), 'E' - * (error), or 'N' (notice), and the head of the pending message queue was - * 'execute', the message must not be pulled out so that next Command - * Complete message from backend matches the execute message. + * (error), 'N' (notice), 'H' (CopyOutResponse), 'd' (CopyData) or 'c' + * (CopyDone) and the head of the pending message queue was 'execute', the + * message must not be pulled out so that next Command Complete message + * from backend matches the execute message. * * Also if it's 't' (parameter description) and the pulled message was * 'describe', the message must not be pulled out so that the row @@ -3858,7 +3867,9 @@ read_kind_from_backend(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, if (SL_MODE && pool_is_doing_extended_query_message() && msg) { if ((msg->type == POOL_EXECUTE && - (*decided_kind == 'D' || *decided_kind == 'E' || *decided_kind == 'N')) || + (*decided_kind == 'D' || *decided_kind == 'E' || + *decided_kind == 'N' || *decided_kind == 'H' || + *decided_kind == 'd' || *decided_kind == 'c')) || (msg->type == POOL_DESCRIBE && *decided_kind == 't')) { ereport(DEBUG5, @@ -5296,6 +5307,7 @@ pool_push_pending_data(POOL_CONNECTION *backend) { pool_push(backend, buf, len); pfree(buf); + buf = NULL; } data_pushed = true; if (kind == 'E') diff --git a/src/protocol/pool_proto_modules.c b/src/protocol/pool_proto_modules.c index 6fad3353c..9f31442b7 100644 --- a/src/protocol/pool_proto_modules.c +++ b/src/protocol/pool_proto_modules.c @@ -1609,7 +1609,7 @@ Parse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, } } - if (REPLICATION || SLONY) + if (REPLICATION) { /* * We must synchronize because Parse message acquires table locks. @@ -1721,9 +1721,26 @@ Bind(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, parse_msg = pool_get_sent_message('P', pstmt_name, POOL_SENT_MESSAGE_CREATED); if (!parse_msg) { - ereport(FATAL, - (errmsg("unable to bind"), - errdetail("cannot get parse message \"%s\"", pstmt_name))); + char *errmessage; + + /* send error message to frontend */ + errmessage = psprintf("prepared statement \"%s\" does not exist", + pstmt_name); + pool_send_error_message(frontend, MAJOR(cp), "XX000", errmessage, + "", "", __FILE__, __LINE__); + pfree(errmessage); + + /* + * Since we do not receive an error response from backend, we need + * similar treatement in case of error response. + */ + pool_set_ignore_till_sync(); + pool_unset_query_in_progress(); + pool_unset_suspend_reading_from_frontend(); + if (SL_MODE) + pool_discard_except_sync_and_ready_for_query(frontend, backend); + + return POOL_CONTINUE; } bind_msg = pool_create_sent_message('B', len, contents, @@ -3829,9 +3846,9 @@ pi_set(int node_id) ProcessInfo *pi = pool_get_my_process_info(); if (node_id < BITS_PER_TYPE(uint64)) - pi->node_ids[0] |= (1 << node_id); + pi->node_ids[0] |= ((uint64) 1 << node_id); else - pi->node_ids[1] |= (1 << (node_id - BITS_PER_TYPE(uint64))); + pi->node_ids[1] |= ((uint64) 1 << (node_id - BITS_PER_TYPE(uint64))); } /* @@ -3843,9 +3860,9 @@ is_pi_set(uint64 *node_ids, int node_id) int set; if (node_id < BITS_PER_TYPE(uint64)) - set = node_ids[0] & (1 << node_id); + set = node_ids[0] & ((uint64) 1 << node_id); else - set = node_ids[1] & (1 << (node_id - BITS_PER_TYPE(uint64))); + set = node_ids[1] & ((uint64) 1 << (node_id - BITS_PER_TYPE(uint64))); return set != 0; } diff --git a/src/query_cache/pool_memqcache.c b/src/query_cache/pool_memqcache.c index 40ad93e1a..f38f71146 100644 --- a/src/query_cache/pool_memqcache.c +++ b/src/query_cache/pool_memqcache.c @@ -280,7 +280,7 @@ pool_commit_cache(POOL_CONNECTION_POOL *backend, char *query, char *data, size_t memqcache_expire = pool_config->memqcache_expire; ereport(DEBUG1, (errmsg("committing SELECT results to cache storage"), - errdetail("memqcache_expire = %ld", memqcache_expire))); + errdetail("memqcache_expire = %lld", (long long) memqcache_expire))); if (pool_is_shmem_cache()) { @@ -390,7 +390,7 @@ pool_catalog_commit_cache(POOL_CONNECTION_POOL *backend, char *query, char *data memqcache_expire = pool_config->relcache_expire; ereport(DEBUG1, (errmsg("committing relation cache to cache storage"), - errdetail("memqcache_expire = %ld", memqcache_expire))); + errdetail("memqcache_expire = %lld", (long long) memqcache_expire))); if (pool_is_shmem_cache()) { @@ -537,10 +537,12 @@ pool_fetch_cache(POOL_CONNECTION_POOL *backend, const char *query, char **buf, s memcpy(p, ptr, *len); +#ifdef USE_MEMCACHED if (!pool_is_shmem_cache()) { free(ptr); } +#endif ereport(DEBUG1, (errmsg("fetching from cache storage"), @@ -2900,8 +2902,8 @@ pool_find_item_on_shmem_cache(POOL_QUERY_HASH *query_hash) { ereport(DEBUG1, (errmsg("memcache finding item"), - errdetail("cache expired: now: %ld timestamp: %ld", - now, cih->timestamp + cih->expire))); + errdetail("cache expired: now: %lld timestamp: %lld", + (long long) now, (long long) (cih->timestamp + cih->expire)))); pool_delete_item_shmem_cache(c); return NULL; } @@ -3135,7 +3137,7 @@ pool_shmem_lock(POOL_MEMQ_LOCK_TYPE type) { char *path; - path = psprintf("%s/%s", pool_config->logdir, QUERY_CACHE_LOCK_FILE); + path = psprintf("%s/%s", pool_config->work_dir, QUERY_CACHE_LOCK_FILE); memq_lock_fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); if (memq_lock_fd == -1) { @@ -4872,8 +4874,8 @@ query_cache_delete_by_stmt(char *query, POOL_CONNECTION_POOL *backend) else pool_delete_item_shmem_cache(cacheid); } -#ifdef USE_MEMCACHED else +#ifdef USE_MEMCACHED { if (delete_cache_on_memcached(key) == 0) rtn = false; diff --git a/src/redhat/pcp_unix_domain_path.patch b/src/redhat/pcp_unix_domain_path.patch index 5b2b10685..0576b369c 100644 --- a/src/redhat/pcp_unix_domain_path.patch +++ b/src/redhat/pcp_unix_domain_path.patch @@ -1,16 +1,16 @@ -*** src/include/pcp/pcp_stream.h 2020-07-31 09:24:10.835496879 +0900 ---- pcp_stream.h 2020-07-31 09:24:02.598396128 +0900 +*** src/include/pcp/pcp_stream.h 2025-08-15 16:47:16.214748366 +0900 +--- pcp_stream.h 2025-08-15 16:47:07.339772297 +0900 *************** *** 49,54 **** - extern int pcp_write(PCP_CONNECTION * pc, void *buf, int len); - extern int pcp_flush(PCP_CONNECTION * pc); + extern int pcp_write(PCP_CONNECTION *pc, void *buf, int len); + extern int pcp_flush(PCP_CONNECTION *pc); ! #define UNIX_DOMAIN_PATH "/tmp" #endif /* PCP_STREAM_H */ --- 49,54 ---- - extern int pcp_write(PCP_CONNECTION * pc, void *buf, int len); - extern int pcp_flush(PCP_CONNECTION * pc); + extern int pcp_write(PCP_CONNECTION *pc, void *buf, int len); + extern int pcp_flush(PCP_CONNECTION *pc); ! #define UNIX_DOMAIN_PATH "/var/run/postgresql" diff --git a/src/redhat/pgpool.conf.sample.patch b/src/redhat/pgpool.conf.sample.patch index 515f26fc3..ada1bef3f 100644 --- a/src/redhat/pgpool.conf.sample.patch +++ b/src/redhat/pgpool.conf.sample.patch @@ -1,10 +1,10 @@ -*** src/sample/pgpool.conf.sample 2014-10-21 16:03:55.605775451 +0900 ---- pgpool.conf.sample.new 2014-10-21 16:04:15.557776162 +0900 +*** src/sample/pgpool.conf.sample 2025-09-30 17:44:36.223222257 +0900 +--- pgpool.conf.sample 2025-09-30 17:46:22.952860803 +0900 *************** -*** 58,72 **** - +*** 82,96 **** + # - Backend Connection Settings - - + ! #backend_hostname0 = 'host1' # Host name or IP address to connect to for backend 0 ! #backend_port0 = 5432 @@ -15,12 +15,12 @@ # Data directory for backend 0 ! #backend_flag0 = 'ALLOW_TO_FAILOVER' # Controls various backend behavior - # ALLOW_TO_FAILOVER or DISALLOW_TO_FAILOVER - #backend_hostname1 = 'host2' ---- 58,72 ---- - + # ALLOW_TO_FAILOVER, DISALLOW_TO_FAILOVER + # or ALWAYS_PRIMARY +--- 82,96 ---- + # - Backend Connection Settings - - + ! backend_hostname0 = 'localhost' # Host name or IP address to connect to for backend 0 ! backend_port0 = 5432 @@ -31,28 +31,22 @@ # Data directory for backend 0 ! backend_flag0 = 'ALLOW_TO_FAILOVER' # Controls various backend behavior - # ALLOW_TO_FAILOVER or DISALLOW_TO_FAILOVER - #backend_hostname1 = 'host2' + # ALLOW_TO_FAILOVER, DISALLOW_TO_FAILOVER + # or ALWAYS_PRIMARY *************** -*** 214,220 **** - pid_file_name = '/var/run/pgpool/pgpool.pid' - # PID file name - # Can be specified as relative to the" +*** 351,357 **** # location of pgpool.conf file or # as an absolute path # (change requires restart) -! logdir = '/tmp' - # Directory of pgPool status file +! #work_dir = '/tmp' + # Directory for pgpool_status and lock files. # (change requires restart) - ---- 214,220 ---- - pid_file_name = '/var/run/pgpool/pgpool.pid' - # PID file name - # Can be specified as relative to the" + +--- 351,357 ---- # location of pgpool.conf file or - # or as absolute path + # as an absolute path # (change requires restart) -! logdir = '/var/log/pgpool' - # Directory of pgPool status file +! work_dir = '/var/lib/pgpool' + # Directory for pgpool_status and lock files. # (change requires restart) diff --git a/src/redhat/pgpool_log.patch b/src/redhat/pgpool_log.patch index aaab1e8d7..198aa8fdd 100644 --- a/src/redhat/pgpool_log.patch +++ b/src/redhat/pgpool_log.patch @@ -1,7 +1,7 @@ -*** src/sample/pgpool.conf.sample 2022-02-10 12:49:15.079700949 +0900 ---- pgpool.conf.sample 2022-02-22 11:05:17.073517397 +0900 +*** src/sample/pgpool.conf.sample 2025-08-15 17:12:42.964631588 +0900 +--- pgpool.conf.sample 2025-08-15 17:17:21.762879829 +0900 *************** -*** 186,192 **** +*** 231,237 **** # - Where to log - @@ -9,7 +9,7 @@ # Where to log # Valid values are combinations of stderr, # and syslog. Default to stderr. ---- 186,192 ---- +--- 231,237 ---- # - Where to log - @@ -18,7 +18,7 @@ # Valid values are combinations of stderr, # and syslog. Default to stderr. *************** -*** 252,268 **** +*** 305,321 **** # panic # This is used when logging to stderr: @@ -36,7 +36,7 @@ # log file name pattern, # can include strftime() escapes ---- 252,268 ---- +--- 305,321 ---- # panic # This is used when logging to stderr: @@ -47,7 +47,7 @@ # -- Only used if logging_collector is on --- -! log_directory = '/var/log/pgpool_log' +! log_directory = '/var/log/pgpool' # directory where log files are written, # can be absolute ! log_filename = 'pgpool-%a.log' @@ -55,7 +55,7 @@ # can include strftime() escapes *************** -*** 270,276 **** +*** 323,329 **** # creation mode for log files, # begin with 0 to use octal notation @@ -63,7 +63,7 @@ # If on, an existing log file with the # same name as the new log file will be # truncated rather than appended to. ---- 270,276 ---- +--- 323,329 ---- # creation mode for log files, # begin with 0 to use octal notation @@ -72,7 +72,7 @@ # same name as the new log file will be # truncated rather than appended to. *************** -*** 280,290 **** +*** 333,343 **** # off, meaning append to existing files # in all cases. @@ -84,7 +84,7 @@ # Automatic rotation of logfiles will # happen after that much (KB) log output. # 0 disables size based rotation. ---- 280,290 ---- +--- 333,343 ---- # off, meaning append to existing files # in all cases. @@ -92,7 +92,7 @@ # Automatic rotation of logfiles will # happen after that (minutes)time. # 0 disables time based rotation. -! log_rotation_size = 0 +! log_rotation_size = 0 # Automatic rotation of logfiles will # happen after that much (KB) log output. # 0 disables size based rotation. diff --git a/src/redhat/pgpool_socket_dir.patch b/src/redhat/pgpool_socket_dir.patch index 40554ddda..de1101331 100644 --- a/src/redhat/pgpool_socket_dir.patch +++ b/src/redhat/pgpool_socket_dir.patch @@ -1,5 +1,5 @@ -*** src/sample/pgpool.conf.sample 2023-11-07 20:38:38.890984731 +0900 ---- pgpool.conf.sample 2023-11-09 13:22:19.179462724 +0900 +*** src/sample/pgpool.conf.sample 2025-08-15 11:18:51.825595514 +0900 +--- pgpool.conf.sample 2025-08-15 17:04:49.381908570 +0900 *************** *** 40,46 **** #port = 9999 @@ -35,7 +35,7 @@ # The Debian package defaults to # /var/run/postgresql *************** -*** 736,742 **** +*** 744,750 **** # Authentication key for watchdog communication # (change requires restart) @@ -43,7 +43,7 @@ # Unix domain socket path for watchdog IPC socket # The Debian package defaults to # /var/run/postgresql ---- 736,742 ---- +--- 744,750 ---- # Authentication key for watchdog communication # (change requires restart) diff --git a/src/rewrite/pool_timestamp.c b/src/rewrite/pool_timestamp.c index 01402bfa6..32de3f309 100644 --- a/src/rewrite/pool_timestamp.c +++ b/src/rewrite/pool_timestamp.c @@ -5,7 +5,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2023 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -74,7 +74,8 @@ static char *get_current_timestamp(POOL_CONNECTION_POOL *backend); static Node *makeTsExpr(TSRewriteContext *ctx); static TypeCast *makeTypeCastFromSvfOp(SQLValueFunctionOp op); static A_Const *makeStringConstFromQuery(POOL_CONNECTION_POOL *backend, char *expression); -bool raw_expression_tree_walker(Node *node, bool (*walker) (), void *context); + +/* bool raw_expression_tree_walker(Node *node, walker, void *context); */ POOL_RELCACHE *ts_relcache; @@ -522,7 +523,7 @@ rewrite_timestamp_insert(InsertStmt *i_stmt, TSRewriteContext *ctx) rewrite_timestamp_walker, (void *) ctx); raw_expression_tree_walker( - (Node *) i_stmt->returningList, + (Node *) i_stmt->returningClause, rewrite_timestamp_walker, (void *) ctx); rewrite = ctx->rewrite; @@ -742,7 +743,7 @@ rewrite_timestamp_update(UpdateStmt *u_stmt, TSRewriteContext *ctx) rewrite_timestamp_walker, (void *) ctx); raw_expression_tree_walker( - (Node *) u_stmt->returningList, + (Node *) u_stmt->returningClause, rewrite_timestamp_walker, (void *) ctx); rewrite = ctx->rewrite; @@ -880,7 +881,7 @@ rewrite_timestamp(POOL_CONNECTION_POOL *backend, Node *node, rewrite_timestamp_walker, (void *) &ctx); raw_expression_tree_walker( - (Node *) d_stmt->returningList, + (Node *) d_stmt->returningClause, rewrite_timestamp_walker, (void *) &ctx); raw_expression_tree_walker( @@ -1370,9 +1371,10 @@ makeTypeCastFromSvfOp(SQLValueFunctionOp op) */ bool raw_expression_tree_walker(Node *node, - bool (*walker) (), + tree_walker_callback walker, void *context) { +#define WALK(n,c) walker((Node *) (n), c) ListCell *temp; /* @@ -1406,17 +1408,17 @@ raw_expression_tree_walker(Node *node, /* we assume the colnames list isn't interesting */ break; case T_RangeVar: - return walker(((RangeVar *) node)->alias, context); + return WALK(((RangeVar *) node)->alias, context); case T_GroupingFunc: - return walker(((GroupingFunc *) node)->args, context); + return WALK(((GroupingFunc *) node)->args, context); case T_SubLink: { SubLink *sublink = (SubLink *) node; - if (walker(sublink->testexpr, context)) + if (WALK(sublink->testexpr, context)) return true; /* we assume the operName is not interesting */ - if (walker(sublink->subselect, context)) + if (WALK(sublink->subselect, context)) return true; } break; @@ -1424,7 +1426,7 @@ raw_expression_tree_walker(Node *node, { CaseExpr *caseexpr = (CaseExpr *) node; - if (walker(caseexpr->arg, context)) + if (WALK(caseexpr->arg, context)) return true; /* we assume walker doesn't care about CaseWhens, either */ foreach(temp, caseexpr->args) @@ -1432,48 +1434,48 @@ raw_expression_tree_walker(Node *node, CaseWhen *when = (CaseWhen *) lfirst(temp); Assert(IsA(when, CaseWhen)); - if (walker(when->expr, context)) + if (WALK(when->expr, context)) return true; - if (walker(when->result, context)) + if (WALK(when->result, context)) return true; } - if (walker(caseexpr->defresult, context)) + if (WALK(caseexpr->defresult, context)) return true; } break; case T_RowExpr: /* Assume colnames isn't interesting */ - return walker(((RowExpr *) node)->args, context); + return WALK(((RowExpr *) node)->args, context); case T_CoalesceExpr: - return walker(((CoalesceExpr *) node)->args, context); + return WALK(((CoalesceExpr *) node)->args, context); case T_MinMaxExpr: - return walker(((MinMaxExpr *) node)->args, context); + return WALK(((MinMaxExpr *) node)->args, context); case T_XmlExpr: { XmlExpr *xexpr = (XmlExpr *) node; - if (walker(xexpr->named_args, context)) + if (WALK(xexpr->named_args, context)) return true; /* we assume walker doesn't care about arg_names */ - if (walker(xexpr->args, context)) + if (WALK(xexpr->args, context)) return true; } break; case T_NullTest: - return walker(((NullTest *) node)->arg, context); + return WALK(((NullTest *) node)->arg, context); case T_BooleanTest: - return walker(((BooleanTest *) node)->arg, context); + return WALK(((BooleanTest *) node)->arg, context); case T_JoinExpr: { JoinExpr *join = (JoinExpr *) node; - if (walker(join->larg, context)) + if (WALK(join->larg, context)) return true; - if (walker(join->rarg, context)) + if (WALK(join->rarg, context)) return true; - if (walker(join->quals, context)) + if (WALK(join->quals, context)) return true; - if (walker(join->alias, context)) + if (WALK(join->alias, context)) return true; /* using list is deemed uninteresting */ } @@ -1482,18 +1484,18 @@ raw_expression_tree_walker(Node *node, { IntoClause *into = (IntoClause *) node; - if (walker(into->rel, context)) + if (WALK(into->rel, context)) return true; /* colNames, options are deemed uninteresting */ /* viewQuery should be null in raw parsetree, but check it */ - if (walker(into->viewQuery, context)) + if (WALK(into->viewQuery, context)) return true; } break; case T_List: foreach(temp, (List *) node) { - if (walker((Node *) lfirst(temp), context)) + if (WALK((Node *) lfirst(temp), context)) return true; } break; @@ -1501,11 +1503,11 @@ raw_expression_tree_walker(Node *node, { MergeWhenClause *mergeWhenClause = (MergeWhenClause *) node; - if (walker(mergeWhenClause->condition, context)) + if (WALK(mergeWhenClause->condition, context)) return true; - if (walker(mergeWhenClause->targetList, context)) + if (WALK(mergeWhenClause->targetList, context)) return true; - if (walker(mergeWhenClause->values, context)) + if (WALK(mergeWhenClause->values, context)) return true; } break; @@ -1513,9 +1515,9 @@ raw_expression_tree_walker(Node *node, { MergeAction *action = (MergeAction *) node; - if (walker(action->targetList, context)) + if (WALK(action->targetList, context)) return true; - if (walker(action->qual, context)) + if (WALK(action->qual, context)) return true; } break; @@ -1523,17 +1525,17 @@ raw_expression_tree_walker(Node *node, { InsertStmt *stmt = (InsertStmt *) node; - if (walker(stmt->relation, context)) + if (WALK(stmt->relation, context)) return true; - if (walker(stmt->cols, context)) + if (WALK(stmt->cols, context)) return true; - if (walker(stmt->selectStmt, context)) + if (WALK(stmt->selectStmt, context)) return true; - if (walker(stmt->onConflictClause, context)) + if (WALK(stmt->onConflictClause, context)) return true; - if (walker(stmt->returningList, context)) + if (WALK(stmt->returningClause, context)) return true; - if (walker(stmt->withClause, context)) + if (WALK(stmt->withClause, context)) return true; } break; @@ -1541,15 +1543,15 @@ raw_expression_tree_walker(Node *node, { DeleteStmt *stmt = (DeleteStmt *) node; - if (walker(stmt->relation, context)) + if (WALK(stmt->relation, context)) return true; - if (walker(stmt->usingClause, context)) + if (WALK(stmt->usingClause, context)) return true; - if (walker(stmt->whereClause, context)) + if (WALK(stmt->whereClause, context)) return true; - if (walker(stmt->returningList, context)) + if (WALK(stmt->returningClause, context)) return true; - if (walker(stmt->withClause, context)) + if (WALK(stmt->withClause, context)) return true; } break; @@ -1557,17 +1559,17 @@ raw_expression_tree_walker(Node *node, { UpdateStmt *stmt = (UpdateStmt *) node; - if (walker(stmt->relation, context)) + if (WALK(stmt->relation, context)) return true; - if (walker(stmt->targetList, context)) + if (WALK(stmt->targetList, context)) return true; - if (walker(stmt->whereClause, context)) + if (WALK(stmt->whereClause, context)) return true; - if (walker(stmt->fromClause, context)) + if (WALK(stmt->fromClause, context)) return true; - if (walker(stmt->returningList, context)) + if (WALK(stmt->returningClause, context)) return true; - if (walker(stmt->withClause, context)) + if (WALK(stmt->withClause, context)) return true; } break; @@ -1575,37 +1577,37 @@ raw_expression_tree_walker(Node *node, { SelectStmt *stmt = (SelectStmt *) node; - if (walker(stmt->distinctClause, context)) + if (WALK(stmt->distinctClause, context)) return true; - if (walker(stmt->intoClause, context)) + if (WALK(stmt->intoClause, context)) return true; - if (walker(stmt->targetList, context)) + if (WALK(stmt->targetList, context)) return true; - if (walker(stmt->fromClause, context)) + if (WALK(stmt->fromClause, context)) return true; - if (walker(stmt->whereClause, context)) + if (WALK(stmt->whereClause, context)) return true; - if (walker(stmt->groupClause, context)) + if (WALK(stmt->groupClause, context)) return true; - if (walker(stmt->havingClause, context)) + if (WALK(stmt->havingClause, context)) return true; - if (walker(stmt->windowClause, context)) + if (WALK(stmt->windowClause, context)) return true; - if (walker(stmt->valuesLists, context)) + if (WALK(stmt->valuesLists, context)) return true; - if (walker(stmt->sortClause, context)) + if (WALK(stmt->sortClause, context)) return true; - if (walker(stmt->limitOffset, context)) + if (WALK(stmt->limitOffset, context)) return true; - if (walker(stmt->limitCount, context)) + if (WALK(stmt->limitCount, context)) return true; - if (walker(stmt->lockingClause, context)) + if (WALK(stmt->lockingClause, context)) return true; - if (walker(stmt->withClause, context)) + if (WALK(stmt->withClause, context)) return true; - if (walker(stmt->larg, context)) + if (WALK(stmt->larg, context)) return true; - if (walker(stmt->rarg, context)) + if (WALK(stmt->rarg, context)) return true; } break; @@ -1613,9 +1615,9 @@ raw_expression_tree_walker(Node *node, { A_Expr *expr = (A_Expr *) node; - if (walker(expr->lexpr, context)) + if (WALK(expr->lexpr, context)) return true; - if (walker(expr->rexpr, context)) + if (WALK(expr->rexpr, context)) return true; /* operator name is deemed uninteresting */ } @@ -1624,7 +1626,7 @@ raw_expression_tree_walker(Node *node, { BoolExpr *expr = (BoolExpr *) node; - if (walker(expr->args, context)) + if (WALK(expr->args, context)) return true; } break; @@ -1635,26 +1637,26 @@ raw_expression_tree_walker(Node *node, { FuncCall *fcall = (FuncCall *) node; - if (walker(fcall->args, context)) + if (WALK(fcall->args, context)) return true; - if (walker(fcall->agg_order, context)) + if (WALK(fcall->agg_order, context)) return true; - if (walker(fcall->agg_filter, context)) + if (WALK(fcall->agg_filter, context)) return true; - if (walker(fcall->over, context)) + if (WALK(fcall->over, context)) return true; /* function name is deemed uninteresting */ } break; case T_NamedArgExpr: - return walker(((NamedArgExpr *) node)->arg, context); + return WALK(((NamedArgExpr *) node)->arg, context); case T_A_Indices: { A_Indices *indices = (A_Indices *) node; - if (walker(indices->lidx, context)) + if (WALK(indices->lidx, context)) return true; - if (walker(indices->uidx, context)) + if (WALK(indices->uidx, context)) return true; } break; @@ -1662,51 +1664,51 @@ raw_expression_tree_walker(Node *node, { A_Indirection *indir = (A_Indirection *) node; - if (walker(indir->arg, context)) + if (WALK(indir->arg, context)) return true; - if (walker(indir->indirection, context)) + if (WALK(indir->indirection, context)) return true; } break; case T_A_ArrayExpr: - return walker(((A_ArrayExpr *) node)->elements, context); + return WALK(((A_ArrayExpr *) node)->elements, context); case T_ResTarget: { ResTarget *rt = (ResTarget *) node; - if (walker(rt->indirection, context)) + if (WALK(rt->indirection, context)) return true; - if (walker(rt->val, context)) + if (WALK(rt->val, context)) return true; } break; case T_MultiAssignRef: - return walker(((MultiAssignRef *) node)->source, context); + return WALK(((MultiAssignRef *) node)->source, context); case T_TypeCast: { TypeCast *tc = (TypeCast *) node; - if (walker(tc->arg, context)) + if (WALK(tc->arg, context)) return true; - if (walker(tc->typeName, context)) + if (WALK(tc->typeName, context)) return true; } break; case T_CollateClause: - return walker(((CollateClause *) node)->arg, context); + return WALK(((CollateClause *) node)->arg, context); case T_SortBy: - return walker(((SortBy *) node)->node, context); + return WALK(((SortBy *) node)->node, context); case T_WindowDef: { WindowDef *wd = (WindowDef *) node; - if (walker(wd->partitionClause, context)) + if (WALK(wd->partitionClause, context)) return true; - if (walker(wd->orderClause, context)) + if (WALK(wd->orderClause, context)) return true; - if (walker(wd->startOffset, context)) + if (WALK(wd->startOffset, context)) return true; - if (walker(wd->endOffset, context)) + if (WALK(wd->endOffset, context)) return true; } break; @@ -1714,9 +1716,9 @@ raw_expression_tree_walker(Node *node, { RangeSubselect *rs = (RangeSubselect *) node; - if (walker(rs->subquery, context)) + if (WALK(rs->subquery, context)) return true; - if (walker(rs->alias, context)) + if (WALK(rs->alias, context)) return true; } break; @@ -1724,11 +1726,11 @@ raw_expression_tree_walker(Node *node, { RangeFunction *rf = (RangeFunction *) node; - if (walker(rf->functions, context)) + if (WALK(rf->functions, context)) return true; - if (walker(rf->alias, context)) + if (WALK(rf->alias, context)) return true; - if (walker(rf->coldeflist, context)) + if (WALK(rf->coldeflist, context)) return true; } break; @@ -1736,12 +1738,12 @@ raw_expression_tree_walker(Node *node, { RangeTableSample *rts = (RangeTableSample *) node; - if (walker(rts->relation, context)) + if (WALK(rts->relation, context)) return true; /* method name is deemed uninteresting */ - if (walker(rts->args, context)) + if (WALK(rts->args, context)) return true; - if (walker(rts->repeatable, context)) + if (WALK(rts->repeatable, context)) return true; } break; @@ -1749,9 +1751,9 @@ raw_expression_tree_walker(Node *node, { TypeName *tn = (TypeName *) node; - if (walker(tn->typmods, context)) + if (WALK(tn->typmods, context)) return true; - if (walker(tn->arrayBounds, context)) + if (WALK(tn->arrayBounds, context)) return true; /* type name itself is deemed uninteresting */ } @@ -1760,38 +1762,38 @@ raw_expression_tree_walker(Node *node, { ColumnDef *coldef = (ColumnDef *) node; - if (walker(coldef->typeName, context)) + if (WALK(coldef->typeName, context)) return true; - if (walker(coldef->raw_default, context)) + if (WALK(coldef->raw_default, context)) return true; - if (walker(coldef->collClause, context)) + if (WALK(coldef->collClause, context)) return true; /* for now, constraints are ignored */ } break; case T_GroupingSet: - return walker(((GroupingSet *) node)->content, context); + return WALK(((GroupingSet *) node)->content, context); case T_LockingClause: - return walker(((LockingClause *) node)->lockedRels, context); + return WALK(((LockingClause *) node)->lockedRels, context); case T_XmlSerialize: { XmlSerialize *xs = (XmlSerialize *) node; - if (walker(xs->expr, context)) + if (WALK(xs->expr, context)) return true; - if (walker(xs->typeName, context)) + if (WALK(xs->typeName, context)) return true; } break; case T_WithClause: - return walker(((WithClause *) node)->ctes, context); + return WALK(((WithClause *) node)->ctes, context); case T_InferClause: { InferClause *stmt = (InferClause *) node; - if (walker(stmt->indexElems, context)) + if (WALK(stmt->indexElems, context)) return true; - if (walker(stmt->whereClause, context)) + if (WALK(stmt->whereClause, context)) return true; } break; @@ -1799,16 +1801,16 @@ raw_expression_tree_walker(Node *node, { OnConflictClause *stmt = (OnConflictClause *) node; - if (walker(stmt->infer, context)) + if (WALK(stmt->infer, context)) return true; - if (walker(stmt->targetList, context)) + if (WALK(stmt->targetList, context)) return true; - if (walker(stmt->whereClause, context)) + if (WALK(stmt->whereClause, context)) return true; } break; case T_CommonTableExpr: - return walker(((CommonTableExpr *) node)->ctequery, context); + return WALK(((CommonTableExpr *) node)->ctequery, context); default: /* diff --git a/src/sample/pgpool.conf.sample-stream b/src/sample/pgpool.conf.sample-stream index bec929dcd..797906491 100644 --- a/src/sample/pgpool.conf.sample-stream +++ b/src/sample/pgpool.conf.sample-stream @@ -1,5 +1,5 @@ # -------------------------------- -# Pgpool-II 4.7 configuration file +# Pgpool-II 4.8 configuration file # -------------------------------- # # This file consists of lines of the form: @@ -20,7 +20,7 @@ #------------------------------------------------------------------------------ # BACKEND CLUSTERING MODE # Choose one of: streaming_replication, native_replication, -# logical_replication, slony, raw or snapshot_isolation +# logical_replication, raw or snapshot_isolation # (change requires restart) #------------------------------------------------------------------------------ @@ -244,7 +244,7 @@ backend_clustering_mode = streaming_replication # Log connections #log_disconnections = off # Log disconnections -#log_pcp_processes = on +#log_pcp_processes = off # Log PCP Processes #log_hostname = off # Hostname will be shown in ps status @@ -351,8 +351,8 @@ backend_clustering_mode = streaming_replication # location of pgpool.conf file or # as an absolute path # (change requires restart) -#logdir = '/tmp' - # Directory of pgPool status file +#work_dir = '/tmp' + # Directory for pgpool_status and lock files. # (change requires restart) diff --git a/src/sample/scripts/recovery_1st_stage.sample b/src/sample/scripts/recovery_1st_stage.sample index f62500f47..9cbe33c8a 100755 --- a/src/sample/scripts/recovery_1st_stage.sample +++ b/src/sample/scripts/recovery_1st_stage.sample @@ -49,7 +49,7 @@ ssh -T ${SSH_OPTIONS} ${POSTGRESQL_STARTUP_USER}@$DEST_NODE_HOST " set -o errexit - [ -d \"${DEST_NODE_PGDATA}\" ] && rm -rf ${DEST_NODE_PGDATA} + [ -d \"${DEST_NODE_PGDATA}\" ] && rm -rf \"${DEST_NODE_PGDATA}\" ${PGHOME}/bin/pg_basebackup -h $PRIMARY_NODE_HOST -U $REPLUSER -p $PRIMARY_NODE_PORT -D $DEST_NODE_PGDATA -X stream diff --git a/src/sql/pgpool_adm/Makefile b/src/sql/pgpool_adm/Makefile index 6dde6ccf6..ce996da8d 100644 --- a/src/sql/pgpool_adm/Makefile +++ b/src/sql/pgpool_adm/Makefile @@ -10,7 +10,7 @@ pgpool_adm--1.0--1.1.sql pgpool_adm--1.1--1.2.sql pgpool_adm--1.2--1.3.sql \ pgpool_adm--1.4.sql pgpool_adm--1.3--1.4.sql \ pgpool_adm--1.5.sql pgpool_adm--1.4--1.5.sql \ pgpool_adm--1.6.sql pgpool_adm--1.5--1.6.sql -SHLIB_LINK = -L../../libs/pcp/.libs -lpcp -Wl,--as-needed -Wl,-rpath,'${prefix}/lib',--enable-new-dtags +SHLIB_LINK = -L../../libs/pcp/.libs -lpcp # if you are using PostgreSQL 8.0 or later, # using pg_config is recommended. # if you are not, comment out following line and... diff --git a/src/streaming_replication/pool_worker_child.c b/src/streaming_replication/pool_worker_child.c index 4f8f823a3..5bf19c37d 100644 --- a/src/streaming_replication/pool_worker_child.c +++ b/src/streaming_replication/pool_worker_child.c @@ -106,7 +106,7 @@ static volatile bool follow_primary_lock_acquired; * worker child main loop */ void -do_worker_child(void) +do_worker_child(void *params) { sigjmp_buf local_sigjmp_buf; MemoryContext WorkerMemoryContext; diff --git a/src/test/pgpool_setup.in b/src/test/pgpool_setup.in index 926b8f8ac..cf7b2f24d 100644 --- a/src/test/pgpool_setup.in +++ b/src/test/pgpool_setup.in @@ -23,7 +23,6 @@ # -m r: create an installation as native replication mode. # -m n: create an installation as raw mode. # -m l: create an installation as logical replication mode. -# -m y: create an installation as slony mode. # -m i: create an installation as snapshot isolation mode. # -n num_clusters: create num_clusters PostgreSQL database cluster nodes # -p base_port: specify base port. pgpool port is base_port. @@ -126,7 +125,7 @@ vstr=`$INITDB -V|awk '{print $3}'|sed 's/\./ /g'` #vstr="11.1" # check if alpha or beta -echo $vstr|egrep "[a-z]" > /dev/null +echo $vstr|grep -E "[a-z]" > /dev/null if [ $? = 0 ];then vstr=`echo $vstr|sed 's/\([0-9]*\).*/\1/'` major1=`echo $vstr|awk '{print $1}'` @@ -245,6 +244,8 @@ if [ a"$failed_node_id" = a"$old_primary_node_id" -o a"$old_primary_node_id" = a echo $pg_ctl -D $new_primary_db_cluster promote >>$log # let standby take over $pg_ctl -D $new_primary_db_cluster promote >>$log # let standby take over sleep 2 + echo psql -p $new_main_port_number -c "CHECKPOINT" postgres + psql -p $new_main_port_number -c "CHECKPOINT" postgres fi date >> $log echo "failover script ended" >> $log @@ -322,10 +323,12 @@ new_primary_db_cluster=${10} mydir=__MYDIR__ log=$mydir/log/failover.log pg_ctl=__PGBIN__/pg_ctl +pg_rewind=__PGBIN__/pg_rewind PCP_PORT=__PCPPORT__ pgversion=__PGVERSION__ export PCPPASSFILE=__PCPPASSFILE__ PGPOOL_BIN=__PGPOOL_INSTALL_DIR__/bin +PGSUPERUSER=__PGSUPERUSER__ echo "follow primary script started for node: $node_id" >> $log date >> $log @@ -341,6 +344,9 @@ then if [ $pgversion -ge 120 ];then sed -i "s/port=[0-9]*/port=$new_primary_port_number/" $db_cluster/myrecovery.conf sed -i "/restore_command/s/data[0-9]/`basename $new_primary_db_cluster`/" $db_cluster/myrecovery.conf + # we need to restore WAL from old primay while running pg_rewind + cp $db_cluster/myrecovery.conf /tmp/myrecovery.rewind.conf + sed -i "/restore_command/s/data[0-9]/data$old_primary_node_id/" /tmp/myrecovery.rewind.conf else # if recovery.conf is not found, rename recovery.done. if [ ! -f $db_cluster/recovery.conf ];then @@ -350,10 +356,25 @@ then sed -i "/restore_command/s/data[0-9]/`basename $new_primary_db_cluster`/" $db_cluster/recovery.conf fi + echo "stopping the target server" >> $log + $pg_ctl -w -m f -D $db_cluster stop >> $log 2>&1 + + # Make backup copy of postgresql.conf since pg_rewind/pg_basebackup unconditionally copies + # $main_db_cluster/postgresql.conf. + cp $db_cluster/postgresql.conf /tmp/ + cp $db_cluster/myrecovery.conf /tmp/ + + # Run pg_rewind + echo "pg_rewind starts" >> $log + echo $pg_rewind -P -c --config-file=/tmp/myrecovery.rewind.conf -D $db_cluster --source-server="host=localhost port=$new_primary_port_number user=$PGSUPERUSER dbname=postgres" >> $log + $pg_rewind -P -c --config-file=/tmp/myrecovery.rewind.conf -D $db_cluster --source-server="host=localhost port=$new_primary_port_number user=$PGSUPERUSER dbname=postgres" >> $log 2>&1 + cp /tmp/postgresql.conf $db_cluster/ + cp /tmp/myrecovery.conf $db_cluster/ + touch $db_cluster/standby.signal - echo "restart the target server" >> $log - $pg_ctl -w -m f -D $db_cluster restart >> $log 2>&1 + echo "start the target server" >> $log + $pg_ctl -w -m f -D $db_cluster start >> $log 2>&1 $pg_ctl -D $db_cluster status >>$log 2>&1 if [ $? != 0 ] @@ -383,6 +404,7 @@ EOF -e "/__PCPPORT__/s/__PCPPORT__/$PCP_PORT/" \ -e "/__PGVERSION__/s/__PGVERSION__/$PGVERSION/" \ -e "/__PGPOOL_INSTALL_DIR__/s@__PGPOOL_INSTALL_DIR__@$PGPOOL_INSTALL_DIR@" \ + -e "/__PGSUPERUSER__/s/__PGSUPERUSER__/$WHOAMI/" \ $FOLLOW_PRIMARY_SCRIPT chmod 755 $FOLLOW_PRIMARY_SCRIPT @@ -1171,7 +1193,7 @@ EOF ################################################################################ function usage() { - echo "usage: $0 [-m r|s|n|l|y|i] [-n num_clusters] [-p base_port] [-pg pg_base_port][--no-stop] [-d] [-s] [-r] [-e] [-t] [-c]";exit 1 + echo "usage: $0 [-m r|s|n|l|i] [-n num_clusters] [-p base_port] [-pg pg_base_port][--no-stop] [-d] [-s] [-r] [-e] [-t] [-c]";exit 1 } #------------------------------------------- @@ -1195,7 +1217,6 @@ do s ) MODE="s";; n ) MODE="n";; l ) MODE="l";; - y ) MODE="y";; i ) MODE="i";; * ) usage;; esac @@ -1247,9 +1268,6 @@ case $MODE in l ) MODENAME="logical replication mode" CLUSTERING_MODE_STR="logical_replication" ;; - y ) MODENAME="slony mode" - CLUSTERING_MODE_STR="slony" - ;; i ) MODENAME="snapshot isolation mode" CLUSTERING_MODE_STR="snapshot_isolation" ;; @@ -1380,7 +1398,7 @@ chmod 0600 $PCP_PASS_FILE test ! -d run && mkdir run echo "pid_file_name = '$BASEDIR/run/pgpool.pid'" >> $CONF test ! -d log && mkdir log -echo "logdir = '$BASEDIR/log'" >> $CONF +echo "work_dir = '$BASEDIR/log'" >> $CONF if [ "$PGPOOLDEBUG" = "true" ];then echo '$PGPOOL_INSTALL_DIR/bin/pgpool -d -D -n -f $dir/etc/pgpool.conf -F $dir/etc/pcp.conf -a $dir/etc/pool_hba.conf 2>&1 | cat > $dir/log/pgpool.log &' >> $STARTALL diff --git a/src/test/regression/regress.sh b/src/test/regression/regress.sh index c192a385e..a0a98b1a1 100755 --- a/src/test/regression/regress.sh +++ b/src/test/regression/regress.sh @@ -204,6 +204,10 @@ fi for i in $dirs do + # skip if it's not a directory + if [ ! -d $i ];then + continue; + fi cd $i # skip the test if there's no test.sh diff --git a/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c b/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c index 917ca8803..da5b9b70c 100644 --- a/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c +++ b/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c @@ -90,7 +90,9 @@ Pgversion(POOL_CONNECTION_POOL *backend) } POOL_RELCACHE * -pool_create_relcache(int cachesize, char *sql, func_ptr register_func, func_ptr unregister_func, bool issessionlocal) +pool_create_relcache(int cachesize, char *sql, + void *(*register_func) (), void *(*unregister_func) (), + bool issessionlocal) { return (POOL_RELCACHE *) 1; } diff --git a/src/test/regression/tests/010.rewrite_timestamp/timestamp/run-test b/src/test/regression/tests/010.rewrite_timestamp/timestamp/run-test index 9b1a6e293..d81102f3b 100755 --- a/src/test/regression/tests/010.rewrite_timestamp/timestamp/run-test +++ b/src/test/regression/tests/010.rewrite_timestamp/timestamp/run-test @@ -23,12 +23,12 @@ if ARGV.size != 1 end file = ARGV.shift -if !(File.exists? file) +if !(File.exist? file) STDERR.puts "run-test: file does not exist: #{file}" exit 1 end -if !(File.exists? RESULT_DIRECTORY) +if !(File.exist? RESULT_DIRECTORY) Dir.mkdir RESULT_DIRECTORY else Dir["#{RESULT_DIRECTORY}/*.out"].each do |f| @@ -36,7 +36,7 @@ else end end -File.unlink DIFF_FILE if File.exists? DIFF_FILE +File.unlink DIFF_FILE if File.exist? DIFF_FILE begin IO.foreach(file) do |testcase| diff --git a/src/test/regression/tests/011.watchdog_quorum_failover/test.sh b/src/test/regression/tests/011.watchdog_quorum_failover/test.sh index 9a5830617..2958d5e17 100755 --- a/src/test/regression/tests/011.watchdog_quorum_failover/test.sh +++ b/src/test/regression/tests/011.watchdog_quorum_failover/test.sh @@ -57,7 +57,7 @@ echo -n "creating standby pgpool..." cat standby.conf >> $STANDBY_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool2.pid'" >> $STANDBY_DIR/etc/pgpool.conf -echo "logdir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf echo 1 > $STANDBY_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand $PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY_DIR/etc/pgpool.conf -F $STANDBY_DIR/etc/pcp.conf -a $STANDBY_DIR/etc/pool_hba.conf > $STANDBY_DIR/log/pgpool.log 2>&1 & @@ -69,7 +69,7 @@ echo -n "creating standby2 pgpool..." cat standby2.conf >> $STANDBY2_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool3.pid'" >> $STANDBY2_DIR/etc/pgpool.conf -echo "logdir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf echo 2 > $STANDBY2_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand $PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY2_DIR/etc/pgpool.conf -F $STANDBY2_DIR/etc/pcp.conf -a $STANDBY2_DIR/etc/pool_hba.conf > $STANDBY2_DIR/log/pgpool.log 2>&1 & diff --git a/src/test/regression/tests/012.watchdog_failover_when_quorum_exists/test.sh b/src/test/regression/tests/012.watchdog_failover_when_quorum_exists/test.sh index ccccb86c6..e14e18134 100755 --- a/src/test/regression/tests/012.watchdog_failover_when_quorum_exists/test.sh +++ b/src/test/regression/tests/012.watchdog_failover_when_quorum_exists/test.sh @@ -59,7 +59,7 @@ echo -n "creating standby pgpool..." cat standby.conf >> $STANDBY_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool2.pid'" >> $STANDBY_DIR/etc/pgpool.conf -echo "logdir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf echo 1 > $STANDBY_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand #$PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY_DIR/etc/pgpool.conf -F $STANDBY_DIR/etc/pcp.conf -a $STANDBY_DIR/etc/pool_hba.conf > $STANDBY_DIR/log/pgpool.log 2>&1 & @@ -71,7 +71,7 @@ echo -n "creating standby2 pgpool..." cat standby2.conf >> $STANDBY2_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool3.pid'" >> $STANDBY2_DIR/etc/pgpool.conf -echo "logdir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf echo 2 > $STANDBY2_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand #$PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY2_DIR/etc/pgpool.conf -F $STANDBY2_DIR/etc/pcp.conf -a $STANDBY2_DIR/etc/pool_hba.conf > $STANDBY2_DIR/log/pgpool.log 2>&1 & diff --git a/src/test/regression/tests/013.watchdog_failover_require_consensus/test.sh b/src/test/regression/tests/013.watchdog_failover_require_consensus/test.sh index d74a827e9..b51af66a3 100755 --- a/src/test/regression/tests/013.watchdog_failover_require_consensus/test.sh +++ b/src/test/regression/tests/013.watchdog_failover_require_consensus/test.sh @@ -59,7 +59,7 @@ echo -n "creating standby pgpool..." cat standby.conf >> $STANDBY_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool2.pid'" >> $STANDBY_DIR/etc/pgpool.conf -echo "logdir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf echo 1 > $STANDBY_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand $PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY_DIR/etc/pgpool.conf -F $STANDBY_DIR/etc/pcp.conf -a $STANDBY_DIR/etc/pool_hba.conf > $STANDBY_DIR/log/pgpool.log 2>&1 & @@ -70,7 +70,7 @@ echo -n "creating standby2 pgpool..." cat standby2.conf >> $STANDBY2_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool3.pid'" >> $STANDBY2_DIR/etc/pgpool.conf -echo "logdir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf echo 2 > $STANDBY2_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand $PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY2_DIR/etc/pgpool.conf -F $STANDBY2_DIR/etc/pcp.conf -a $STANDBY2_DIR/etc/pool_hba.conf > $STANDBY2_DIR/log/pgpool.log 2>&1 & diff --git a/src/test/regression/tests/015.watchdog_master_and_backend_fail/test.sh b/src/test/regression/tests/015.watchdog_master_and_backend_fail/test.sh index 3b517a98d..f0dad0766 100755 --- a/src/test/regression/tests/015.watchdog_master_and_backend_fail/test.sh +++ b/src/test/regression/tests/015.watchdog_master_and_backend_fail/test.sh @@ -59,7 +59,7 @@ echo -n "creating standby pgpool..." cat standby.conf >> $STANDBY_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool2.pid'" >> $STANDBY_DIR/etc/pgpool.conf -echo "logdir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY_DIR/log" >> $STANDBY_DIR/etc/pgpool.conf echo 1 > $STANDBY_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand $PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY_DIR/etc/pgpool.conf -F $STANDBY_DIR/etc/pcp.conf -a $STANDBY_DIR/etc/pool_hba.conf > $STANDBY_DIR/log/pgpool.log 2>&1 & @@ -70,7 +70,7 @@ echo -n "creating standby2 pgpool..." cat standby2.conf >> $STANDBY2_DIR/etc/pgpool.conf # since we are using the same pgpool-II conf as of leader. so change the pid file path in standby pgpool conf echo "pid_file_name = '$PWD/pgpool3.pid'" >> $STANDBY2_DIR/etc/pgpool.conf -echo "logdir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf +echo "work_dir = $STANDBY2_DIR/log" >> $STANDBY2_DIR/etc/pgpool.conf echo 2 > $STANDBY2_DIR/etc/pgpool_node_id # start the standby pgpool-II by hand $PGPOOL_INSTALL_DIR/bin/pgpool -D -n -f $STANDBY2_DIR/etc/pgpool.conf -F $STANDBY2_DIR/etc/pcp.conf -a $STANDBY2_DIR/etc/pool_hba.conf > $STANDBY2_DIR/log/pgpool.log 2>&1 & diff --git a/src/test/regression/tests/023.ssl_connection/test.sh b/src/test/regression/tests/023.ssl_connection/test.sh index 17e375339..2b5f3b693 100755 --- a/src/test/regression/tests/023.ssl_connection/test.sh +++ b/src/test/regression/tests/023.ssl_connection/test.sh @@ -65,7 +65,13 @@ $PSQL -h localhost test <<EOF > result \q EOF -grep SSL result +# PostgreSQL 18 or later prints tablular output for \conninfo. +# For SSL, "SSL Connection | true (or false)" +if [ $PGVERSION -ge 18 ];then + grep "SSL Connection" result|grep true +else + grep SSL result +fi if [ $? != 0 ];then echo "Checking SSL connection between frontend and Pgpool-II failed." @@ -75,7 +81,11 @@ fi echo "Checking SSL connection between frontend and Pgpool-II was ok." -grep SSL result |grep TLSv1.2 +if [ $PGVERSION -ge 18 ];then + grep "SSL Protocol" result|grep TLSv1.2 +else + grep SSL result |grep TLSv1.2 +fi # if SSl protocol version TLSv1.2 if [ $? = 0 ];then @@ -99,4 +109,53 @@ fi echo "Checking SSL connection between Pgpool-II and backend was ok." ./shutdownall + +# Checking ssl_ecdh_curve. Set bad value to see if SSL connection fails. +echo "ssl_ecdh_curve = 'badcurve'" >> etc/pgpool.conf + +./startall +wait_for_pgpool_startup + +$PSQL -h localhost test <<EOF > result +\conninfo +\q +EOF + +if [ $PGVERSION -ge 18 ];then + grep "SSL Connection" result|grep true +else + grep SSL result +fi + +if [ $? = 0 ];then + echo "Checking SSL connection between frontend and Pgpool-II succeeded despite bad ssl_ecdh_curve." + ./shutdownall + exit 1 +fi + +echo "Checking SSL connection between frontend and Pgpool-II failed due to bad ssl_ecdh_curve as expected." +./shutdownall + +# Make sure that SSL connection succeeds with good ssl_ecdh_curve +echo "ssl_ecdh_curve = 'prime256v1'" >> etc/pgpool.conf + +./startall +wait_for_pgpool_startup + +$PSQL -h localhost test <<EOF > result +\conninfo +\q +EOF + +grep SSL result + +if [ $? = 0 ];then + echo "Checking SSL connection between frontend and Pgpool-II succeeded with good ssl_ecdh_curve." + ./shutdownall +else + echo "Checking SSL connection between frontend and Pgpool-II failed with good ssl_ecdh_curve." + ./shutdownall + exit 1 +fi + exit 0 diff --git a/src/test/regression/tests/034.promote_node/test.sh b/src/test/regression/tests/034.promote_node/test.sh index 547e97821..07f35e46b 100755 --- a/src/test/regression/tests/034.promote_node/test.sh +++ b/src/test/regression/tests/034.promote_node/test.sh @@ -38,7 +38,7 @@ wait_for_pgpool_startup # check to see if alll nodes are up echo -n "starting to check follow primary results: " date -cnt=60 +cnt=120 while [ $cnt -gt 0 ] do # check to see if primary is now node 3 diff --git a/src/test/regression/tests/037.failover_session/test.sh b/src/test/regression/tests/037.failover_session/test.sh index b75377140..7fc9845d8 100755 --- a/src/test/regression/tests/037.failover_session/test.sh +++ b/src/test/regression/tests/037.failover_session/test.sh @@ -60,6 +60,8 @@ else echo "pgbench suceeded. test1 ok." r1=ok fi +# give pgpool chance to complete the failover +sleep 5 ./shutdownall echo "=== test2: backend_weight2 = 0 and pgbench with -C option" diff --git a/src/test/regression/tests/039.log_backend_messages/test.sh b/src/test/regression/tests/039.log_backend_messages/test.sh index d89ba5494..6fe672e46 100755 --- a/src/test/regression/tests/039.log_backend_messages/test.sh +++ b/src/test/regression/tests/039.log_backend_messages/test.sh @@ -23,17 +23,25 @@ do echo > result - # We set backend_weight0 to 0 to send ready queries to backend 1. + # We set backend_weight0 to send read queries to backend 1. # We set client_min_messages to log so that log messages appear on # the client screen. # We set connection_cache to off so that each time client connects # to pgpool, it receives ready for query from backend. + # We set synchronous_commit = remote_apply, and synchronous_standby_names = 'server1' + # in streaming replication mode so that updation to primary is replicated to standby with no lag. cat >> etc/pgpool.conf <<EOF backend_weight0 = 0 client_min_messages = log log_per_node_statement = off connection_cache = off EOF + if [ $mode = "s" ];then + cat >> data0/postgresql.conf <<EOF +synchronous_commit = remote_apply +synchronous_standby_names = 'server1' +EOF + fi for option in none terse verbose do echo "==== mode: $mode option: $option ===" >> result diff --git a/src/test/regression/tests/040.client_auth/test.sh b/src/test/regression/tests/040.client_auth/test.sh index 964e9293e..c0b2c3331 100755 --- a/src/test/regression/tests/040.client_auth/test.sh +++ b/src/test/regression/tests/040.client_auth/test.sh @@ -278,9 +278,9 @@ function do_auth add_user $username $pg_hba $PGPORT - # for logical replication and slony, we need to manually + # for logical replication, we need to manually # add PostgreSQL user to node 1. - if [ $mode = 'l' -o $mode = 'y' ];then + if [ $mode = 'l' ];then add_user $username $pg_hba "11003" fi add_pool_hba $username $pool_hba $PGPOOL_VERSION_DIGIT diff --git a/src/test/regression/tests/050.bug58/.gitignore b/src/test/regression/tests/100.bug58/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/050.bug58/.gitignore +++ b/src/test/regression/tests/100.bug58/.gitignore diff --git a/src/test/regression/tests/050.bug58/test.sh b/src/test/regression/tests/100.bug58/test.sh index 15afb7c69..15afb7c69 100755 --- a/src/test/regression/tests/050.bug58/test.sh +++ b/src/test/regression/tests/100.bug58/test.sh diff --git a/src/test/regression/tests/051.bug60/.gitignore b/src/test/regression/tests/101.bug60/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/051.bug60/.gitignore +++ b/src/test/regression/tests/101.bug60/.gitignore diff --git a/src/test/regression/tests/051.bug60/bug.sql b/src/test/regression/tests/101.bug60/bug.sql index 134199bd7..134199bd7 100644 --- a/src/test/regression/tests/051.bug60/bug.sql +++ b/src/test/regression/tests/101.bug60/bug.sql diff --git a/src/test/regression/tests/051.bug60/database-clean.sql b/src/test/regression/tests/101.bug60/database-clean.sql index a32da02a4..a32da02a4 100644 --- a/src/test/regression/tests/051.bug60/database-clean.sql +++ b/src/test/regression/tests/101.bug60/database-clean.sql diff --git a/src/test/regression/tests/051.bug60/database-setup.sql b/src/test/regression/tests/101.bug60/database-setup.sql index 1fccbaab5..1fccbaab5 100644 --- a/src/test/regression/tests/051.bug60/database-setup.sql +++ b/src/test/regression/tests/101.bug60/database-setup.sql diff --git a/src/test/regression/tests/051.bug60/test.sh b/src/test/regression/tests/101.bug60/test.sh index 4032153b9..4032153b9 100755 --- a/src/test/regression/tests/051.bug60/test.sh +++ b/src/test/regression/tests/101.bug60/test.sh diff --git a/src/test/regression/tests/052.do_query/.gitignore b/src/test/regression/tests/102.do_query/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/052.do_query/.gitignore +++ b/src/test/regression/tests/102.do_query/.gitignore diff --git a/src/test/regression/tests/052.do_query/test.sh b/src/test/regression/tests/102.do_query/test.sh index 9370b7b3b..9370b7b3b 100755 --- a/src/test/regression/tests/052.do_query/test.sh +++ b/src/test/regression/tests/102.do_query/test.sh diff --git a/src/test/regression/tests/053.insert_lock_hangs/.gitignore b/src/test/regression/tests/103.insert_lock_hangs/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/053.insert_lock_hangs/.gitignore +++ b/src/test/regression/tests/103.insert_lock_hangs/.gitignore diff --git a/src/test/regression/tests/053.insert_lock_hangs/test.sh b/src/test/regression/tests/103.insert_lock_hangs/test.sh index daa811762..daa811762 100755 --- a/src/test/regression/tests/053.insert_lock_hangs/test.sh +++ b/src/test/regression/tests/103.insert_lock_hangs/test.sh diff --git a/src/test/regression/tests/054.postgres_fdw/.gitignore b/src/test/regression/tests/104.postgres_fdw/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/054.postgres_fdw/.gitignore +++ b/src/test/regression/tests/104.postgres_fdw/.gitignore diff --git a/src/test/regression/tests/054.postgres_fdw/test.sh b/src/test/regression/tests/104.postgres_fdw/test.sh index b3b6f556f..b3b6f556f 100755 --- a/src/test/regression/tests/054.postgres_fdw/test.sh +++ b/src/test/regression/tests/104.postgres_fdw/test.sh diff --git a/src/test/regression/tests/055.backend_all_down/.gitignore b/src/test/regression/tests/105.backend_all_down/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/055.backend_all_down/.gitignore +++ b/src/test/regression/tests/105.backend_all_down/.gitignore diff --git a/src/test/regression/tests/055.backend_all_down/test.sh b/src/test/regression/tests/105.backend_all_down/test.sh index ba7dadd32..ba7dadd32 100755 --- a/src/test/regression/tests/055.backend_all_down/test.sh +++ b/src/test/regression/tests/105.backend_all_down/test.sh diff --git a/src/test/regression/tests/056.bug63/.gitignore b/src/test/regression/tests/106.bug63/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/056.bug63/.gitignore +++ b/src/test/regression/tests/106.bug63/.gitignore diff --git a/src/test/regression/tests/056.bug63/jdbctest2.java b/src/test/regression/tests/106.bug63/jdbctest2.java index 8f8b6efa8..8f8b6efa8 100644 --- a/src/test/regression/tests/056.bug63/jdbctest2.java +++ b/src/test/regression/tests/106.bug63/jdbctest2.java diff --git a/src/test/regression/tests/056.bug63/test.sh b/src/test/regression/tests/106.bug63/test.sh index 483826895..483826895 100755 --- a/src/test/regression/tests/056.bug63/test.sh +++ b/src/test/regression/tests/106.bug63/test.sh diff --git a/src/test/regression/tests/057.bug61/.gitignore b/src/test/regression/tests/107.bug61/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/057.bug61/.gitignore +++ b/src/test/regression/tests/107.bug61/.gitignore diff --git a/src/test/regression/tests/057.bug61/test.sh b/src/test/regression/tests/107.bug61/test.sh index 1b6515153..1b6515153 100755 --- a/src/test/regression/tests/057.bug61/test.sh +++ b/src/test/regression/tests/107.bug61/test.sh diff --git a/src/test/regression/tests/058.bug68/.gitignore b/src/test/regression/tests/108.bug68/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/058.bug68/.gitignore +++ b/src/test/regression/tests/108.bug68/.gitignore diff --git a/src/test/regression/tests/058.bug68/jdbctest3.java b/src/test/regression/tests/108.bug68/jdbctest3.java index 20cfb1aae..20cfb1aae 100644 --- a/src/test/regression/tests/058.bug68/jdbctest3.java +++ b/src/test/regression/tests/108.bug68/jdbctest3.java diff --git a/src/test/regression/tests/058.bug68/test.sh b/src/test/regression/tests/108.bug68/test.sh index 54b7d4968..54b7d4968 100755 --- a/src/test/regression/tests/058.bug68/test.sh +++ b/src/test/regression/tests/108.bug68/test.sh diff --git a/src/test/regression/tests/059.bug92/.gitignore b/src/test/regression/tests/109.bug92/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/059.bug92/.gitignore +++ b/src/test/regression/tests/109.bug92/.gitignore diff --git a/src/test/regression/tests/059.bug92/jdbctest.java b/src/test/regression/tests/109.bug92/jdbctest.java index dd3720b8b..dd3720b8b 100644 --- a/src/test/regression/tests/059.bug92/jdbctest.java +++ b/src/test/regression/tests/109.bug92/jdbctest.java diff --git a/src/test/regression/tests/059.bug92/test.sh b/src/test/regression/tests/109.bug92/test.sh index e430f6a77..e430f6a77 100755 --- a/src/test/regression/tests/059.bug92/test.sh +++ b/src/test/regression/tests/109.bug92/test.sh diff --git a/src/test/regression/tests/060.memory_leak/.gitignore b/src/test/regression/tests/110.memory_leak/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/060.memory_leak/.gitignore +++ b/src/test/regression/tests/110.memory_leak/.gitignore diff --git a/src/test/regression/tests/060.memory_leak/test.sh b/src/test/regression/tests/110.memory_leak/test.sh index 05f80de92..05f80de92 100755 --- a/src/test/regression/tests/060.memory_leak/test.sh +++ b/src/test/regression/tests/110.memory_leak/test.sh diff --git a/src/test/regression/tests/061.cancel_query/.gitignore b/src/test/regression/tests/111.cancel_query/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/061.cancel_query/.gitignore +++ b/src/test/regression/tests/111.cancel_query/.gitignore diff --git a/src/test/regression/tests/061.cancel_query/test.sh b/src/test/regression/tests/111.cancel_query/test.sh index 969deaea2..969deaea2 100755 --- a/src/test/regression/tests/061.cancel_query/test.sh +++ b/src/test/regression/tests/111.cancel_query/test.sh diff --git a/src/test/regression/tests/062.select_error_hangs/.gitignore b/src/test/regression/tests/112.select_error_hangs/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/062.select_error_hangs/.gitignore +++ b/src/test/regression/tests/112.select_error_hangs/.gitignore diff --git a/src/test/regression/tests/062.select_error_hangs/test.sh b/src/test/regression/tests/112.select_error_hangs/test.sh index 522a3599f..522a3599f 100755 --- a/src/test/regression/tests/062.select_error_hangs/test.sh +++ b/src/test/regression/tests/112.select_error_hangs/test.sh diff --git a/src/test/regression/tests/063.tables_with_space/.gitignore b/src/test/regression/tests/113.tables_with_space/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/063.tables_with_space/.gitignore +++ b/src/test/regression/tests/113.tables_with_space/.gitignore diff --git a/src/test/regression/tests/063.tables_with_space/test.sh b/src/test/regression/tests/113.tables_with_space/test.sh index a40708307..a40708307 100755 --- a/src/test/regression/tests/063.tables_with_space/test.sh +++ b/src/test/regression/tests/113.tables_with_space/test.sh diff --git a/src/test/regression/tests/064.bug153/.gitignore b/src/test/regression/tests/114.bug153/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/064.bug153/.gitignore +++ b/src/test/regression/tests/114.bug153/.gitignore diff --git a/src/test/regression/tests/064.bug153/test.sh b/src/test/regression/tests/114.bug153/test.sh index bc9eb1687..bc9eb1687 100755 --- a/src/test/regression/tests/064.bug153/test.sh +++ b/src/test/regression/tests/114.bug153/test.sh diff --git a/src/test/regression/tests/065.bug152/.gitignore b/src/test/regression/tests/115.bug152/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/065.bug152/.gitignore +++ b/src/test/regression/tests/115.bug152/.gitignore diff --git a/src/test/regression/tests/065.bug152/Main.java b/src/test/regression/tests/115.bug152/Main.java index 5d9736071..5d9736071 100644 --- a/src/test/regression/tests/065.bug152/Main.java +++ b/src/test/regression/tests/115.bug152/Main.java diff --git a/src/test/regression/tests/065.bug152/run.sh b/src/test/regression/tests/115.bug152/run.sh index e6e1eead7..e6e1eead7 100644 --- a/src/test/regression/tests/065.bug152/run.sh +++ b/src/test/regression/tests/115.bug152/run.sh diff --git a/src/test/regression/tests/065.bug152/test.sh b/src/test/regression/tests/115.bug152/test.sh index 9dcbddcde..9dcbddcde 100755 --- a/src/test/regression/tests/065.bug152/test.sh +++ b/src/test/regression/tests/115.bug152/test.sh diff --git a/src/test/regression/tests/066.bug230/.gitignore b/src/test/regression/tests/116.bug230/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/066.bug230/.gitignore +++ b/src/test/regression/tests/116.bug230/.gitignore diff --git a/src/test/regression/tests/066.bug230/Sample.java b/src/test/regression/tests/116.bug230/Sample.java index 47b7f98cf..47b7f98cf 100644 --- a/src/test/regression/tests/066.bug230/Sample.java +++ b/src/test/regression/tests/116.bug230/Sample.java diff --git a/src/test/regression/tests/066.bug230/test.sh b/src/test/regression/tests/116.bug230/test.sh index 1a1d123ea..1a1d123ea 100755 --- a/src/test/regression/tests/066.bug230/test.sh +++ b/src/test/regression/tests/116.bug230/test.sh diff --git a/src/test/regression/tests/067.bug231/.gitignore b/src/test/regression/tests/117.bug231/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/067.bug231/.gitignore +++ b/src/test/regression/tests/117.bug231/.gitignore diff --git a/src/test/regression/tests/067.bug231/TestReplGap.java b/src/test/regression/tests/117.bug231/TestReplGap.java index 2aaa17dbf..2aaa17dbf 100644 --- a/src/test/regression/tests/067.bug231/TestReplGap.java +++ b/src/test/regression/tests/117.bug231/TestReplGap.java diff --git a/src/test/regression/tests/067.bug231/test.sh b/src/test/regression/tests/117.bug231/test.sh index 02b6a86de..02b6a86de 100755 --- a/src/test/regression/tests/067.bug231/test.sh +++ b/src/test/regression/tests/117.bug231/test.sh diff --git a/src/test/regression/tests/068.memqcache_bug/.gitignore b/src/test/regression/tests/118.memqcache_bug/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/068.memqcache_bug/.gitignore +++ b/src/test/regression/tests/118.memqcache_bug/.gitignore diff --git a/src/test/regression/tests/068.memqcache_bug/Sample.java b/src/test/regression/tests/118.memqcache_bug/Sample.java index bacf9a9c8..bacf9a9c8 100644 --- a/src/test/regression/tests/068.memqcache_bug/Sample.java +++ b/src/test/regression/tests/118.memqcache_bug/Sample.java diff --git a/src/test/regression/tests/068.memqcache_bug/test.sh b/src/test/regression/tests/118.memqcache_bug/test.sh index 05746cf7a..05746cf7a 100755 --- a/src/test/regression/tests/068.memqcache_bug/test.sh +++ b/src/test/regression/tests/118.memqcache_bug/test.sh diff --git a/src/test/regression/tests/069.memory_leak_extended/.gitignore b/src/test/regression/tests/119.memory_leak_extended/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/069.memory_leak_extended/.gitignore +++ b/src/test/regression/tests/119.memory_leak_extended/.gitignore diff --git a/src/test/regression/tests/069.memory_leak_extended/test.sh b/src/test/regression/tests/119.memory_leak_extended/test.sh index 87802608f..87802608f 100755 --- a/src/test/regression/tests/069.memory_leak_extended/test.sh +++ b/src/test/regression/tests/119.memory_leak_extended/test.sh diff --git a/src/test/regression/tests/070.memory_leak_extended_memqcache/.gitignore b/src/test/regression/tests/120.memory_leak_extended_memqcache/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/070.memory_leak_extended_memqcache/.gitignore +++ b/src/test/regression/tests/120.memory_leak_extended_memqcache/.gitignore diff --git a/src/test/regression/tests/070.memory_leak_extended_memqcache/test.sh b/src/test/regression/tests/120.memory_leak_extended_memqcache/test.sh index 4a2badb51..4a2badb51 100755 --- a/src/test/regression/tests/070.memory_leak_extended_memqcache/test.sh +++ b/src/test/regression/tests/120.memory_leak_extended_memqcache/test.sh diff --git a/src/test/regression/tests/071.execute_and_deallocate/.gitignore b/src/test/regression/tests/121.execute_and_deallocate/.gitignore index f937fcb17..f937fcb17 100644 --- a/src/test/regression/tests/071.execute_and_deallocate/.gitignore +++ b/src/test/regression/tests/121.execute_and_deallocate/.gitignore diff --git a/src/test/regression/tests/071.execute_and_deallocate/test.sh b/src/test/regression/tests/121.execute_and_deallocate/test.sh index 08b3cb7b9..08b3cb7b9 100755 --- a/src/test/regression/tests/071.execute_and_deallocate/test.sh +++ b/src/test/regression/tests/121.execute_and_deallocate/test.sh diff --git a/src/test/regression/tests/072.meqcache_bug2/extended_query_test.data b/src/test/regression/tests/122.meqcache_bug2/extended_query_test.data index 07874b0d3..07874b0d3 100644 --- a/src/test/regression/tests/072.meqcache_bug2/extended_query_test.data +++ b/src/test/regression/tests/122.meqcache_bug2/extended_query_test.data diff --git a/src/test/regression/tests/072.meqcache_bug2/test.sh b/src/test/regression/tests/122.meqcache_bug2/test.sh index 32f969115..32f969115 100755 --- a/src/test/regression/tests/072.meqcache_bug2/test.sh +++ b/src/test/regression/tests/122.meqcache_bug2/test.sh diff --git a/src/test/regression/tests/073.pg_terminate_backend/test.sh b/src/test/regression/tests/123.pg_terminate_backend/test.sh index 4e2b9ab25..4e2b9ab25 100755 --- a/src/test/regression/tests/073.pg_terminate_backend/test.sh +++ b/src/test/regression/tests/123.pg_terminate_backend/test.sh diff --git a/src/test/regression/tests/074.bug700_memqcache_segfault/expected.txt b/src/test/regression/tests/124.bug700_memqcache_segfault/expected.txt index 3964fd9fa..3964fd9fa 100644 --- a/src/test/regression/tests/074.bug700_memqcache_segfault/expected.txt +++ b/src/test/regression/tests/124.bug700_memqcache_segfault/expected.txt diff --git a/src/test/regression/tests/074.bug700_memqcache_segfault/pgproto.data b/src/test/regression/tests/124.bug700_memqcache_segfault/pgproto.data index 510bada8a..510bada8a 100644 --- a/src/test/regression/tests/074.bug700_memqcache_segfault/pgproto.data +++ b/src/test/regression/tests/124.bug700_memqcache_segfault/pgproto.data diff --git a/src/test/regression/tests/074.bug700_memqcache_segfault/test.sh b/src/test/regression/tests/124.bug700_memqcache_segfault/test.sh index a26475bae..116d5c16c 100755 --- a/src/test/regression/tests/074.bug700_memqcache_segfault/test.sh +++ b/src/test/regression/tests/124.bug700_memqcache_segfault/test.sh @@ -27,6 +27,8 @@ do echo "memory_cache_enabled = on" >> etc/pgpool.conf echo "log_min_messages = debug1" >> etc/pgpool.conf + echo "log_backend_messages = terse" >> etc/pgpool.conf + echo "log_client_messages = on" >> etc/pgpool.conf ./startall wait_for_pgpool_startup diff --git a/src/test/regression/tests/075.detach_primary_left_down_node/test.sh b/src/test/regression/tests/125.detach_primary_left_down_node/test.sh index 05fdc5317..30acec9cb 100755 --- a/src/test/regression/tests/075.detach_primary_left_down_node/test.sh +++ b/src/test/regression/tests/125.detach_primary_left_down_node/test.sh @@ -30,7 +30,7 @@ wait_for_pgpool_startup # check to see if alll nodes are up echo -n "starting to check follow primary results: " date -cnt=60 +cnt=120 while [ $cnt -gt 0 ] do $PGBIN/psql -c "show pool_nodes" test 2>&1|grep -E 'down|error' diff --git a/src/test/regression/tests/126.copy_hang/copy-out-expected b/src/test/regression/tests/126.copy_hang/copy-out-expected new file mode 100644 index 000000000..270ee35e1 --- /dev/null +++ b/src/test/regression/tests/126.copy_hang/copy-out-expected @@ -0,0 +1,37 @@ +FE=> Query (query="CREATE TEMP TABLE copy_in_test AS SELECT I FROM generate_series(1,10) AS i") +<= BE CommandComplete(SELECT 10) +<= BE ReadyForQuery(I) +FE=> Query (query="SELECT * FROM copy_in_test") +<= BE RowDescription +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE DataRow +<= BE CommandComplete(SELECT 10) +<= BE ReadyForQuery(I) +FE=> Parse(stmt="", query="COPY copy_in_test TO STDOUT") +FE=> Bind(stmt="", portal="") +FE=> Execute(portal="") +FE=> Sync +<= BE ParseComplete +<= BE BindComplete +<= BE CopyOutResponse +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyData +<= BE CopyDone +<= BE CommandComplete(COPY 10) +<= BE ReadyForQuery(I) diff --git a/src/test/regression/tests/126.copy_hang/pgproto-copy-out.data b/src/test/regression/tests/126.copy_hang/pgproto-copy-out.data new file mode 100644 index 000000000..627076530 --- /dev/null +++ b/src/test/regression/tests/126.copy_hang/pgproto-copy-out.data @@ -0,0 +1,9 @@ +'Q' "CREATE TEMP TABLE copy_in_test AS SELECT I FROM generate_series(1,10) AS i" +'Y' +'Q' "SELECT * FROM copy_in_test" +'Y' +'P' "" "COPY copy_in_test TO STDOUT" 0 +'B' "" "" 0 0 0 +'E' "" 0 +'S' +'Y' diff --git a/src/test/regression/tests/076.copy_hang/pgproto.data b/src/test/regression/tests/126.copy_hang/pgproto.data index ce6eeebc1..ce6eeebc1 100644 --- a/src/test/regression/tests/076.copy_hang/pgproto.data +++ b/src/test/regression/tests/126.copy_hang/pgproto.data diff --git a/src/test/regression/tests/076.copy_hang/test.sh b/src/test/regression/tests/126.copy_hang/test.sh index 9e0f4c0ce..6ed70a72e 100755 --- a/src/test/regression/tests/076.copy_hang/test.sh +++ b/src/test/regression/tests/126.copy_hang/test.sh @@ -64,4 +64,20 @@ if [ ! $? -eq 0 ];then ./shutdownall exit 1 fi + +# +# Test case for COPY OUT in extended query protocol mode segfaults. +# since this creates temp table, prevent load balance +echo "backend_weight1 = 0" >> etc/pgpool.conf +echo "backend_weight2 = 0" >> etc/pgpool.conf +# reload pgpool.conf and wait until the effect is apparent +./pgpool_reload +sleep 1 +# run test script +$PGPROTO -d test -f ../pgproto-copy-out.data > copy-out-result 2>&1 +cmp ../copy-out-expected copy-out-result +if [ ! $? -eq 0 ];then + ./shutdownall + exit 1 +fi ./shutdownall diff --git a/src/test/regression/tests/077.invalid_failover_node/test.sh b/src/test/regression/tests/127.invalid_failover_node/test.sh index bfea574e2..bfea574e2 100755 --- a/src/test/regression/tests/077.invalid_failover_node/test.sh +++ b/src/test/regression/tests/127.invalid_failover_node/test.sh diff --git a/src/test/regression/tests/078.aborted_transaction/expected.txt b/src/test/regression/tests/128.aborted_transaction/expected.txt index f70e6716e..f70e6716e 100644 --- a/src/test/regression/tests/078.aborted_transaction/expected.txt +++ b/src/test/regression/tests/128.aborted_transaction/expected.txt diff --git a/src/test/regression/tests/078.aborted_transaction/test.sh b/src/test/regression/tests/128.aborted_transaction/test.sh index 7c8eca387..7c8eca387 100755 --- a/src/test/regression/tests/078.aborted_transaction/test.sh +++ b/src/test/regression/tests/128.aborted_transaction/test.sh diff --git a/src/test/regression/tests/079.multi_prepare/expected.txt b/src/test/regression/tests/129.multi_prepare/expected.txt index 58ac94ffd..58ac94ffd 100644 --- a/src/test/regression/tests/079.multi_prepare/expected.txt +++ b/src/test/regression/tests/129.multi_prepare/expected.txt diff --git a/src/test/regression/tests/079.multi_prepare/pgproto.data b/src/test/regression/tests/129.multi_prepare/pgproto.data index aeef45bf7..aeef45bf7 100644 --- a/src/test/regression/tests/079.multi_prepare/pgproto.data +++ b/src/test/regression/tests/129.multi_prepare/pgproto.data diff --git a/src/test/regression/tests/079.multi_prepare/test.sh b/src/test/regression/tests/129.multi_prepare/test.sh index 970fca630..970fca630 100755 --- a/src/test/regression/tests/079.multi_prepare/test.sh +++ b/src/test/regression/tests/129.multi_prepare/test.sh diff --git a/src/test/regression/tests/080.declare/expected.txt b/src/test/regression/tests/130.declare/expected.txt index 414f4e406..414f4e406 100644 --- a/src/test/regression/tests/080.declare/expected.txt +++ b/src/test/regression/tests/130.declare/expected.txt diff --git a/src/test/regression/tests/080.declare/pgproto.data b/src/test/regression/tests/130.declare/pgproto.data index 5cfadf410..5cfadf410 100644 --- a/src/test/regression/tests/080.declare/pgproto.data +++ b/src/test/regression/tests/130.declare/pgproto.data diff --git a/src/test/regression/tests/080.declare/test.sh b/src/test/regression/tests/130.declare/test.sh index 65e00d571..65e00d571 100755 --- a/src/test/regression/tests/080.declare/test.sh +++ b/src/test/regression/tests/130.declare/test.sh diff --git a/src/test/regression/tests/081.detach_primary_all_down/test.sh b/src/test/regression/tests/131.detach_primary_all_down/test.sh index e97dcf923..e97dcf923 100755 --- a/src/test/regression/tests/081.detach_primary_all_down/test.sh +++ b/src/test/regression/tests/131.detach_primary_all_down/test.sh diff --git a/src/test/regression/tests/082.guard_against_bad_protocol/pgproto.data b/src/test/regression/tests/132.guard_against_bad_protocol/pgproto.data index 4b5bae6d0..4b5bae6d0 100644 --- a/src/test/regression/tests/082.guard_against_bad_protocol/pgproto.data +++ b/src/test/regression/tests/132.guard_against_bad_protocol/pgproto.data diff --git a/src/test/regression/tests/082.guard_against_bad_protocol/pgproto2.data b/src/test/regression/tests/132.guard_against_bad_protocol/pgproto2.data index f4edbb4b5..f4edbb4b5 100644 --- a/src/test/regression/tests/082.guard_against_bad_protocol/pgproto2.data +++ b/src/test/regression/tests/132.guard_against_bad_protocol/pgproto2.data diff --git a/src/test/regression/tests/082.guard_against_bad_protocol/test.sh b/src/test/regression/tests/132.guard_against_bad_protocol/test.sh index f1d16e6f3..f1d16e6f3 100755 --- a/src/test/regression/tests/082.guard_against_bad_protocol/test.sh +++ b/src/test/regression/tests/132.guard_against_bad_protocol/test.sh diff --git a/src/test/regression/tests/README b/src/test/regression/tests/README new file mode 100644 index 000000000..b1e074fe9 --- /dev/null +++ b/src/test/regression/tests/README @@ -0,0 +1,6 @@ +All test directory names should have following format: + +3-digit-numbers '.' (dot) test-names + +For the 3-digit-number, range 000-099 are reserved for tests of +features. Range 100- are reserved for tests for bugs. diff --git a/src/test/watchdog_setup.in b/src/test/watchdog_setup.in index d84a5b619..c64152451 100644 --- a/src/test/watchdog_setup.in +++ b/src/test/watchdog_setup.in @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2013-2021 PgPool Global Development Group +# Copyright (c) 2013-2025 PgPool Global Development Group # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby @@ -18,10 +18,11 @@ # this tool for production environment! # Note that this script uses pgpool_setup as a work horse. # -# usage: watchdog_setup [-wn num_pgpool][-wp watchdog_base_port][-m r|s|n|i][-n num_clusters][-p base_port][--no-stop][-d] +# usage: watchdog_setup [-wn num_pgpool][-wp watchdog_base_port][-m r|s|n|i][-n num_clusters][-p base_port][--no-stop][-vip [ip]][-d] # -wn num_pgpool: create num_pgpool pgpool nodes. The default is 3. Must be greater than 1. # -wp watchdog_base_port: starting port number. The default is # 50000. +# -vip [ip]: allow to assign "ip" being set to delegate_ip. If "ip" is omitted, "127.0.0.1" is assumed. #------------------------------------------- # Configuration section #------------------------------------------- @@ -40,6 +41,9 @@ export PGBASEPORT=`expr $W_BASE_PORT + 1000` # number of ports used in a single pgpool-II installation. # (port, pcp_port, wd_port, wd_heartbeat_port) num_ports_per_node=4 + +# default vip +DEFAULT_VIP="127.0.0.1" #------------------------------------------- # End of configuration section #------------------------------------------- @@ -198,6 +202,13 @@ EOF n=`expr $n + 1` done + if [ "$VIP" != "" ];then + echo "delegate_ip = '$VIP'" >> $conf + echo "if_up_cmd = '/usr/bin/echo \"if_up_cmd executed\"'" >> $conf + echo "if_down_cmd = 'usr/bin/echo \"if_down_cmd executed\"'" >> $conf + echo "arping_cmd = '/usr/bin/true'" >> $conf + fi + echo "$id" >> $node_id_file } @@ -208,17 +219,18 @@ EOF ################################################################################ function usage() { - echo "usage: $0 [-wn num_pgpool][-wp watchdog_base_port][-m r|s|n|i] [-n num_clusters] [-p base_port] [-pg pg_base_port][--no-stop] [-d]";exit 1 + echo "usage: $0 [-wn num_pgpool][-wp watchdog_base_port][-m r|s|n|i] [-n num_clusters] [-p base_port] [-pg pg_base_port][--no-stop] -vip [ip]] [-d]";exit 1 } #------------------------------------------- # Argument check -# usage: $0 [-wn num_pgpool][-wp watchdog_base_port][-m r|s|n][-n num_clusters][-p base_port][-pg pg_base_port][--no-stop][-d] +# usage: $0 [-wn num_pgpool][-wp watchdog_base_port][-m r|s|n][-n num_clusters][-p base_port][-pg pg_base_port][--no-stop][-vip [ip]][-d] #------------------------------------------- # # default mode is streaming replication mode MODE="s" NO_STOP="false" +VIP="" while [ $# -gt 0 ] do @@ -257,9 +269,23 @@ do elif [ $1 = "--no-stop" ];then shift NO_STOP="true" + + elif [ $1 = "-vip" ];then + if [ $# = 1 ];then + # there's no more argument. set the default vip + VIP=$DEFAULT_VIP + else + if [[ $2 =~ -.* ]];then + # next argument given. set the default vip + VIP=$DEFAULT_VIP + else + # VIP is specified + shift + VIP=$1 + fi + fi elif [ $1 = "-d" ];then export PGPOOLDEBUG="true" - shift; elif [ $1 = "--help" -o $1 = "-o" ];then usage exit diff --git a/src/tools/pgenc/pg_enc.c b/src/tools/pgenc/pg_enc.c index 83c6d3b4f..7e5143843 100644 --- a/src/tools/pgenc/pg_enc.c +++ b/src/tools/pgenc/pg_enc.c @@ -5,7 +5,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2022 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -98,7 +98,7 @@ main(int argc, char *argv[]) { switch (opt) { - case 'p': /* prompt for postgres password */ + case 'p': /* prompt for password to be encrypted */ prompt = true; break; @@ -246,6 +246,7 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } stpncpy(enc_key, buf, sizeof(enc_key)); + pool_key = enc_key; } else { diff --git a/src/tools/pgindent/README.pgpool b/src/tools/pgindent/README.pgpool index a47c237e4..152e51653 100644 --- a/src/tools/pgindent/README.pgpool +++ b/src/tools/pgindent/README.pgpool @@ -9,8 +9,18 @@ The steps to run pgindent are as follows: 2. Or, if you want to generate typedefs.list from scratch, run find_typedes: cd pgpool2 + autoreconf -fi + make clean + # find_typedef needs to refer to the latest object files + make src/tools/find_typedef src > src/tools/pgindent/typedefs.list 3. Run pgindent by using run_pgindent. cd pgpool2/src tools/pgindent/run_pgindent + +4. Commit the change. + +5. Add an entry to .git-blame-ignore-revs. + (How to add an entry is described in the file). +
\ No newline at end of file diff --git a/src/tools/pgindent/enums.list b/src/tools/pgindent/enums.list index 5668af69f..5aa369e01 100644 --- a/src/tools/pgindent/enums.list +++ b/src/tools/pgindent/enums.list @@ -60,4 +60,4 @@ WDCommandStatus fe_scram_state_enum scram_state_enum ExplainFormat -RowCompareType +CompareType diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index d7309565d..939200965 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1,4 +1,4 @@ -ASN1_ITEM +ATAlterConstraint A_ArrayExpr A_Const A_Expr @@ -100,6 +100,7 @@ ColumnRef CommandDest CommentStmt CommonTableExpr +CompareType CompositeTypeStmt ConfigBoolAssignFunc ConfigContext @@ -182,9 +183,14 @@ DropTableSpaceStmt DropUserMappingStmt DropdbStmt EC_KEY +ENGINE +EVP_CIPHER EVP_CIPHER_CTX +EVP_MD ErrorContextCallback ErrorData +ErrorSaveContext +ExecStatusType ExecuteStmt ExplainStmt Expr @@ -274,6 +280,7 @@ JsonWrapper KeyAction KeyActions LDAP +LDAPControl LDAPMessage LDAPURLDesc LOAD_BALANCE_STATUS @@ -316,6 +323,7 @@ NotifyStmt NullIfExpr NullTest NullTestType +OPENSSL_INIT_SETTINGS ObjectType ObjectWithArgs Oid @@ -449,11 +457,14 @@ RenameStmt ReplicaIdentityStmt ResTarget ReturnStmt +ReturningClause +ReturningExpr +ReturningOption +ReturningOptionKind RoleSpec RoleSpecType RoleStmtType RowCompareExpr -RowCompareType RowDesc RowExpr RowMarkClause @@ -465,6 +476,8 @@ SQLValueFunction SQLValueFunctionOp SSL SSL_CTX +SSL_METHOD +SSL_verify_cb ScalarArrayOpExpr ScanKeywordHashFunc ScanKeywordList @@ -477,12 +490,8 @@ SetOperation SetOperationStmt SetQuantifier SetToDefault -SinglePartitionSpec Size SockAddr -Sockbuf -Sockbuf_IO -Sockbuf_IO_Desc SocketConnection SortBy SortByDir @@ -528,6 +537,7 @@ VacuumParams VacuumRelation VacuumStmt Var +VarReturningType VarShowHook VariableSetKind VariableSetStmt @@ -576,6 +586,7 @@ WindowFuncRunCondition WithCheckOption WithClause X509 +X509_NAME X509_STORE X509_STORE_CTX XmlExpr @@ -586,6 +597,7 @@ YYSTYPE YY_BUFFER_STATE YY_CHAR _IO_lock_t +__CONST_SOCKADDR_ARG __SOCKADDR_ARG __blkcnt_t __blksize_t @@ -627,13 +639,12 @@ __uint16_t __uint32_t __uint64_t __uint8_t +__useconds_t base_yy_extra_type ber_int_t ber_len_t -ber_slen_t bitmapword bits32 -bool check_network_data config_group config_type @@ -646,7 +657,6 @@ fe_scram_state fe_scram_state_enum flex_int16_t flex_uint8_t -func_ptr gid_t hashkit_hash_fn hashkit_st @@ -660,13 +670,13 @@ int64 int64_t int8 intptr_t -jmp_buf json_object_entry json_settings json_state json_type json_uchar json_value +key_t list_sort_comparator mb2wchar_with_len_converter mbchar_verifier @@ -688,6 +698,7 @@ memcached_result_st memcached_return memcached_return_t memcached_server_distribution_t +memcached_server_list_st memcached_server_st memcached_st memcached_string_st @@ -696,6 +707,7 @@ memcached_trigger_key_fn mode_t packet_types pam_handle_t +pem_password_cb pg_enc pg_enc2name pg_on_exit_callback @@ -732,6 +744,7 @@ size_t socklen_t ssize_t time_t +tree_walker_callback uid_t uint16 uint16_t @@ -751,5 +764,6 @@ yy_state_fast_t yy_state_t yy_state_type yyscan_t +yysymbol_kind_t yytype_int16 yytype_int8 diff --git a/src/utils/json.c b/src/utils/json.c index 8d156439c..ffe7a2c96 100644 --- a/src/utils/json.c +++ b/src/utils/json.c @@ -1191,7 +1191,7 @@ json_get_int_value_for_key(json_value *source, const char *key, int *value) } int -json_get_long_value_for_key(json_value *source, const char *key, long *value) +json_get_llong_value_for_key(json_value *source, const char *key, long long *value) { json_value *jNode; diff --git a/src/utils/pool_process_reporting.c b/src/utils/pool_process_reporting.c index 8e41ccafd..39087bc47 100644 --- a/src/utils/pool_process_reporting.c +++ b/src/utils/pool_process_reporting.c @@ -507,9 +507,9 @@ get_config(int *nrows) StrNCpy(status[i].desc, "path to pid file", POOLCONFIG_MAXDESCLEN); i++; - StrNCpy(status[i].name, "logdir", POOLCONFIG_MAXNAMELEN); - snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->logdir); - StrNCpy(status[i].desc, "PgPool status file logging directory", POOLCONFIG_MAXDESCLEN); + StrNCpy(status[i].name, "work_dir", POOLCONFIG_MAXNAMELEN); + snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->work_dir); + StrNCpy(status[i].desc, "directory to create pgpool_status and lock files ", POOLCONFIG_MAXDESCLEN); i++; /* CONNECTION POOLING */ @@ -1117,6 +1117,8 @@ get_config(int *nrows) StrNCpy(status[i].name, "memqcache_stats_start_time", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", ctime(&pool_get_memqcache_stats()->start_time)); + /* remove a newline added by ctime() */ + *(strchrnul(status[i].value, '\n')) = '\0'; StrNCpy(status[i].desc, "Start time of query cache stats", POOLCONFIG_MAXDESCLEN); i++; @@ -2071,7 +2073,7 @@ get_health_check_stats(int *nrows) /* status last changed */ t = bi->status_changed_time; - ereport(LOG, (errmsg("status_changed_time %ld", t))); + ereport(LOG, (errmsg("status_changed_time %lld", (long long) t))); strftime(stats[i].last_status_change, POOLCONFIG_MAXDATELEN, "%F %T", localtime(&t)); snprintf(stats[i].total_count, POOLCONFIG_MAXLONGCOUNTLEN, UINT64_FORMAT, health_check_stats[i].total_count); diff --git a/src/utils/pool_relcache.c b/src/utils/pool_relcache.c index bea2ac396..d4ebab25e 100644 --- a/src/utils/pool_relcache.c +++ b/src/utils/pool_relcache.c @@ -5,7 +5,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2023 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -48,7 +48,7 @@ static char *relation_cache_to_query_cache(POOL_SELECT_RESULT *res, size_t *size */ POOL_RELCACHE * pool_create_relcache(int cachesize, char *sql, - func_ptr register_func, func_ptr unregister_func, + void *(*register_func) (POOL_SELECT_RESULT *), void *(*unregister_func) (void *), bool issessionlocal) { POOL_RELCACHE *p; @@ -187,7 +187,7 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha { ereport(DEBUG1, (errmsg("searching relcache"), - errdetail("relcache for database:%s table:%s expired. now:%ld expiration time:%ld", dbname, table, now, relcache->cache[i].expire))); + errdetail("relcache for database:%s table:%s expired. now:%lld expiration time:%lld", dbname, table, (long long) now, (long long) relcache->cache[i].expire))); relcache->cache[i].refcnt = 0; break; diff --git a/src/utils/pool_stream.c b/src/utils/pool_stream.c index cfa3308a4..0a9cc3576 100644 --- a/src/utils/pool_stream.c +++ b/src/utils/pool_stream.c @@ -3,7 +3,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * -* Copyright (c) 2003-2023 PgPool Global Development Group +* Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -549,20 +549,19 @@ pool_write(POOL_CONNECTION *cp, void *buf, int len) static int pool_write_flush(POOL_CONNECTION *cp, void *buf, int len) { - int sts; - int wlen; + ssize_t sts; + size_t wlen; int offset; - wlen = len; - ereport(DEBUG5, - (errmsg("pool_write_flush: write size: %d", wlen))); + (errmsg("pool_write_flush: write size: %d", len))); - if (wlen == 0) + if (len <= 0) { return 0; } + wlen = len; offset = 0; for (;;) @@ -580,26 +579,25 @@ pool_write_flush(POOL_CONNECTION *cp, void *buf, int len) if (sts >= 0) { - wlen -= sts; - - if (wlen == 0) + if (wlen == sts) { /* write completed */ break; } - else if (wlen < 0) + else if (wlen < sts) { ereport(WARNING, - (errmsg("pool_write_flush: invalid write size %d", sts))); + (errmsg("pool_write_flush: invalid write size %zd", sts))); return -1; } else { + wlen -= sts; /* need to write remaining data */ ereport(DEBUG5, - (errmsg("pool_write_flush: write retry: %d", wlen))); + (errmsg("pool_write_flush: write retry: %zd", wlen))); offset += sts; continue; @@ -620,11 +618,11 @@ pool_write_flush(POOL_CONNECTION *cp, void *buf, int len) if (cp->isbackend) ereport(WARNING, (errmsg("write on backend %d failed with error :\"%m\"", cp->db_node_id), - errdetail("while trying to write data from offset: %d wlen: %d", offset, wlen))); + errdetail("while trying to write data from offset: %d wlen: %zd", offset, wlen))); else ereport(DEBUG5, (errmsg("write on frontend failed with error :\"%m\""), - errdetail("while trying to write data from offset: %d wlen: %d", offset, wlen))); + errdetail("while trying to write data from offset: %d wlen: %zd", offset, wlen))); return -1; } } @@ -639,14 +637,14 @@ pool_write_flush(POOL_CONNECTION *cp, void *buf, int len) int pool_flush_it(POOL_CONNECTION *cp) { - int sts; - int wlen; + ssize_t sts; + size_t wlen; int offset; wlen = cp->wbufpo; ereport(DEBUG5, - (errmsg("pool_flush_it: flush size: %d", wlen))); + (errmsg("pool_flush_it: flush size: %zd", wlen))); if (wlen == 0) { @@ -670,27 +668,26 @@ pool_flush_it(POOL_CONNECTION *cp) if (sts >= 0) { - wlen -= sts; - - if (wlen == 0) + if (wlen == sts) { /* write completed */ break; } - else if (wlen < 0) + else if (wlen < sts) { ereport(WARNING, - (errmsg("pool_flush_it: invalid write size %d", sts))); + (errmsg("pool_flush_it: invalid write size %zd", sts))); cp->wbufpo = 0; return -1; } else { + wlen -= sts; /* need to write remaining data */ ereport(DEBUG5, - (errmsg("pool_flush_it: write retry: %d", wlen))); + (errmsg("pool_flush_it: write retry: %zd", wlen))); offset += sts; continue; @@ -711,11 +708,11 @@ pool_flush_it(POOL_CONNECTION *cp) if (cp->isbackend) ereport(WARNING, (errmsg("write on backend %d failed with error :\"%m\"", cp->db_node_id), - errdetail("while trying to write data from offset: %d wlen: %d", offset, wlen))); + errdetail("while trying to write data from offset: %d wlen: %zd", offset, wlen))); else ereport(DEBUG5, (errmsg("write on frontend failed with error :\"%m\""), - errdetail("while trying to write data from offset: %d wlen: %d", offset, wlen))); + errdetail("while trying to write data from offset: %d wlen: %zd", offset, wlen))); cp->wbufpo = 0; return -1; } diff --git a/src/watchdog/watchdog.c b/src/watchdog/watchdog.c index d57d83526..aa6fe7e41 100644 --- a/src/watchdog/watchdog.c +++ b/src/watchdog/watchdog.c @@ -590,7 +590,7 @@ static bool get_authhash_for_node(WatchdogNode *wdNode, char *authhash); static bool verify_authhash_for_node(WatchdogNode *wdNode, char *authhash); static void print_watchdog_node_info(WatchdogNode *wdNode); -static List *wd_create_recv_socket(int port); +static List *wd_create_recv_socket(char *hostname, int port); static void wd_check_config(void); static pid_t watchdog_main(void); static pid_t fork_watchdog_child(void); @@ -658,7 +658,7 @@ wd_check_config(void) MAX_PASSWORD_SIZE))); if (pool_config->wd_lifecheck_method == LIFECHECK_BY_HB) { - if (pool_config->num_hb_dest_if <= 0) + if (pool_config->num_hb_local_if <= 0 || pool_config->num_hb_dest_if <= 0) ereport(ERROR, (errmsg("invalid life-check configuration. no heartbeat interfaces defined"))); } @@ -865,7 +865,7 @@ clear_command_node_result(WDCommandNodeResult *nodeResult) } static List * -wd_create_recv_socket(int port) +wd_create_recv_socket(char *hostname, int port) { int one = 1; int sock = -1; @@ -886,7 +886,7 @@ wd_create_recv_socket(int port) hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; - if ((gai_ret = getaddrinfo(NULL, portstr, &hints, &res)) != 0) + if ((gai_ret = getaddrinfo(!hostname ? NULL : hostname, portstr, &hints, &res)) != 0) { ereport(ERROR, (errmsg("getaddrinfo failed with error \"%s\"", gai_strerror(gai_ret)))); @@ -1299,7 +1299,7 @@ watchdog_main(void) /* initialize all the local structures for watchdog */ wd_cluster_initialize(); /* create a server socket for incoming watchdog connections */ - g_wd_recv_socks = wd_create_recv_socket(g_cluster.localNode->wd_port); + g_wd_recv_socks = wd_create_recv_socket(g_cluster.localNode->hostname, g_cluster.localNode->wd_port); /* open the command server */ g_cluster.command_server_sock = wd_create_command_server_socket(); @@ -1983,6 +1983,10 @@ read_sockets(fd_set *rmask, int pending_fds_count) return count; } +/* + * write watchdog IP command along with result data + * returns true on success + */ static bool write_ipc_command_with_result_data(WDCommandData *ipcCommand, char type, char *data, int len) { @@ -2133,7 +2137,7 @@ read_ipc_socket_and_process(int sock, bool *remove_socket) data_len = strlen(data) + 1; } - if (write_ipc_command_with_result_data(ipcCommand, res_type, data, data_len)) + if (!write_ipc_command_with_result_data(ipcCommand, res_type, data, data_len)) { ereport(NOTICE, (errmsg("error writing to IPC socket"))); @@ -3691,6 +3695,10 @@ update_successful_outgoing_cons(fd_set *wmask, int pending_fds_count) return count; } +/* + * write packet to watchdog communication socket + * returns true on success. + */ static bool write_packet_to_socket(int sock, WDPacketData *pkt, bool ipcPacket) { @@ -6755,8 +6763,8 @@ watchdog_state_machine_nw_isolation(WD_EVENTS event, WatchdogNode *wdNode, WDPac static bool beacon_message_received_from_node(WatchdogNode *wdNode, WDPacketData *pkt) { - long seconds_since_node_startup; - long seconds_since_current_state; + long long seconds_since_node_startup; + long long seconds_since_current_state; int quorum_status; int standby_nodes_count; bool escalated; @@ -7292,11 +7300,42 @@ watchdog_state_machine_standby(WD_EVENTS event, WatchdogNode *wdNode, WDPacketDa if (last_rcv_sec >= (3 * BEACON_MESSAGE_INTERVAL_SECONDS)) { - /* we have missed atleast two beacons from leader node */ + /* we have missed at least three beacons from leader node */ ereport(WARNING, (errmsg("we have not received a beacon message from leader node \"%s\" and it has not replied to our info request", WD_LEADER_NODE->nodeName), errdetail("re-initializing the cluster"))); + + /* + * Starting to set LOST status to the leader node. This needs to + * be done because there could be two leader nodes. + */ + WD_LEADER_NODE->state = WD_LOST; + ereport(LOG, + (errmsg("remote node \"%s\" is lost due to missed beacons", WD_LEADER_NODE->nodeName))); + + /* Inform the node, that it is lost for us */ + send_cluster_service_message(WD_LEADER_NODE, pkt, CLUSTER_NODE_APPEARING_LOST); + ereport(LOG, + (errmsg("watchdog cluster has lost the coordinator node"))); + + /* close all socket connections to the node */ + close_socket_connection(&WD_LEADER_NODE->client_socket); + close_socket_connection(&WD_LEADER_NODE->server_socket); + + /* clear the wait timer on the node */ + WD_LEADER_NODE->last_sent_time.tv_sec = 0; + WD_LEADER_NODE->last_sent_time.tv_usec = 0; + WD_LEADER_NODE->sending_failures_count = 0; + + node_lost_while_ipc_command(WD_LEADER_NODE); + set_cluster_leader_node(NULL); + + /* + * Finish setting LOST status to the leader node. + */ + + /* re-initialize the cluster */ set_state(WD_JOINING); } else if (last_rcv_sec >= (2 * BEACON_MESSAGE_INTERVAL_SECONDS)) @@ -8540,7 +8579,7 @@ load_watchdog_debug_test_option(void) if (wd_debug_request_file[0] == '\0') { snprintf(wd_debug_request_file, sizeof(wd_debug_request_file), - "%s/%s", pool_config->logdir, WATCHDOG_DEBUG_FILE); + "%s/%s", pool_config->work_dir, WATCHDOG_DEBUG_FILE); } fd = fopen(wd_debug_request_file, "r"); diff --git a/src/watchdog/wd_commands.c b/src/watchdog/wd_commands.c index 1539ef675..4b313e6c7 100644 --- a/src/watchdog/wd_commands.c +++ b/src/watchdog/wd_commands.c @@ -193,9 +193,9 @@ get_wd_runtime_variable_value(char *wd_authkey, char *varName) case VALUE_DATA_TYPE_LONG: { - long longVal; + long long longVal; - if (json_get_long_value_for_key(root, WD_JSON_KEY_VALUE_DATA, &longVal)) + if (json_get_llong_value_for_key(root, WD_JSON_KEY_VALUE_DATA, &longVal)) { ereport(WARNING, (errmsg("get runtime variable value from watchdog failed"), diff --git a/src/watchdog/wd_heartbeat.c b/src/watchdog/wd_heartbeat.c index a9e99dec9..33c378b4f 100644 --- a/src/watchdog/wd_heartbeat.c +++ b/src/watchdog/wd_heartbeat.c @@ -262,7 +262,7 @@ wd_create_hb_recv_socket(WdHbIf *hb_if) *walk, *res = NULL; - portstr = psprintf("%d", pool_config->wd_heartbeat_port); + portstr = psprintf("%d", hb_if->dest_port); memset(&hints, 0x00, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -270,7 +270,7 @@ wd_create_hb_recv_socket(WdHbIf *hb_if) hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; - if ((gai_ret = getaddrinfo(NULL, portstr, &hints, &res)) != 0) + if ((gai_ret = getaddrinfo(hb_if->addr[0] == '\0' ? NULL : hb_if->addr, portstr, &hints, &res)) != 0) { ereport(WARNING, (errmsg("getaddrinfo() failed with error \"%s\"", gai_strerror(gai_ret)))); @@ -285,7 +285,7 @@ wd_create_hb_recv_socket(WdHbIf *hb_if) if (n == 0) { ereport(ERROR, (errmsg("failed to create watchdog heartbeat receive socket"), - errdetail("getaddrinfo() result is empty: no sockets can be created because no available local address with port:%d", pool_config->wd_heartbeat_port))); + errdetail("getaddrinfo() result is empty: no sockets can be created because no available local address with port:%d", hb_if->dest_port))); return NULL; } else @@ -380,7 +380,7 @@ wd_create_hb_recv_socket(WdHbIf *hb_if) } ereport(LOG, (errmsg("creating watchdog heartbeat receive socket."), - errdetail("creating socket on %s:%d", buf, pool_config->wd_heartbeat_port))); + errdetail("creating socket on %s:%d", buf, hb_if->dest_port))); bind_is_done = 0; for (bind_tries = 0; !bind_is_done && bind_tries < MAX_BIND_TRIES; bind_tries++) @@ -850,8 +850,8 @@ packet_to_string_hb(WdHbPacket *pkt, char *str, int maxlen) { int len; - len = snprintf(str, maxlen, "tv_sec=%ld tv_usec=%ld from=%s", - pkt->send_time.tv_sec, pkt->send_time.tv_usec, pkt->from); + len = snprintf(str, maxlen, "tv_sec=%lld tv_usec=%lld from=%s", + (long long) pkt->send_time.tv_sec, (long long) pkt->send_time.tv_usec, pkt->from); return len; } diff --git a/src/watchdog/wd_json_data.c b/src/watchdog/wd_json_data.c index d5741b3e7..91dd26a86 100644 --- a/src/watchdog/wd_json_data.c +++ b/src/watchdog/wd_json_data.c @@ -533,6 +533,7 @@ get_watchdog_node_from_json(char *json_data, int data_len, char **authkey) { json_value *root = NULL; char *ptr; + long long longVal; WatchdogNode *wdNode = palloc0(sizeof(WatchdogNode)); root = json_parse(json_data, data_len); @@ -540,19 +541,20 @@ get_watchdog_node_from_json(char *json_data, int data_len, char **authkey) if (root == NULL || root->type != json_object) goto ERROR_EXIT; - if (json_get_long_value_for_key(root, "StartupTimeSecs", &wdNode->startup_time.tv_sec)) + if (json_get_llong_value_for_key(root, "StartupTimeSecs", &longVal)) { bool escalated; - long seconds_since_node_startup; - long seconds_since_current_state; + long long seconds_since_node_startup; + long long seconds_since_current_state; struct timeval current_time; + wdNode->startup_time.tv_sec = longVal; gettimeofday(¤t_time, NULL); /* The new version does not have StartupTimeSecs Key */ - if (json_get_long_value_for_key(root, "SecondsSinceStartup", &seconds_since_node_startup)) + if (json_get_llong_value_for_key(root, "SecondsSinceStartup", &seconds_since_node_startup)) goto ERROR_EXIT; - if (json_get_long_value_for_key(root, "SecondsSinceCurrentState", &seconds_since_current_state)) + if (json_get_llong_value_for_key(root, "SecondsSinceCurrentState", &seconds_since_current_state)) goto ERROR_EXIT; if (json_get_bool_value_for_key(root, "Escalated", &escalated)) goto ERROR_EXIT; @@ -643,8 +645,8 @@ ERROR_EXIT: bool parse_beacon_message_json(char *json_data, int data_len, int *state, - long *seconds_since_node_startup, - long *seconds_since_current_state, + long long *seconds_since_node_startup, + long long *seconds_since_current_state, int *quorumStatus, int *standbyNodesCount, bool *escalated) @@ -658,9 +660,9 @@ parse_beacon_message_json(char *json_data, int data_len, if (json_get_int_value_for_key(root, "State", state)) goto ERROR_EXIT; - if (json_get_long_value_for_key(root, "SecondsSinceStartup", seconds_since_node_startup)) + if (json_get_llong_value_for_key(root, "SecondsSinceStartup", seconds_since_node_startup)) goto ERROR_EXIT; - if (json_get_long_value_for_key(root, "SecondsSinceCurrentState", seconds_since_current_state)) + if (json_get_llong_value_for_key(root, "SecondsSinceCurrentState", seconds_since_current_state)) goto ERROR_EXIT; if (json_get_bool_value_for_key(root, "Escalated", escalated)) goto ERROR_EXIT; diff --git a/src/watchdog/wd_lifecheck.c b/src/watchdog/wd_lifecheck.c index b62a9b493..86caf9b4b 100644 --- a/src/watchdog/wd_lifecheck.c +++ b/src/watchdog/wd_lifecheck.c @@ -133,11 +133,14 @@ lifecheck_child_name(pid_t pid) { int i; - for (i = 0; i < pool_config->num_hb_dest_if; i++) + for (i = 0; i < pool_config->num_hb_local_if; i++) { if (g_hb_receiver_pid && pid == g_hb_receiver_pid[i]) return "heartBeat receiver"; - else if (g_hb_sender_pid && pid == g_hb_sender_pid[i]) + } + for (i = 0; i < pool_config->num_hb_dest_if; i++) + { + if (g_hb_sender_pid && pid == g_hb_sender_pid[i]) return "heartBeat sender"; } /* Check if it was a ping to trusted server process */ @@ -211,13 +214,13 @@ wd_reaper_lifecheck(pid_t pid, int status) if (g_hb_receiver_pid == NULL && g_hb_sender_pid == NULL) return -1; - for (i = 0; i < pool_config->num_hb_dest_if; i++) + for (i = 0; i < pool_config->num_hb_local_if; i++) { if (g_hb_receiver_pid && pid == g_hb_receiver_pid[i]) { if (restart_child) { - g_hb_receiver_pid[i] = wd_hb_receiver(1, &(pool_config->hb_dest_if[i])); + g_hb_receiver_pid[i] = wd_hb_receiver(1, &(pool_config->hb_local_if[i])); ereport(LOG, (errmsg("fork a new %s process with pid: %d", proc_name, g_hb_receiver_pid[i]))); } @@ -226,8 +229,11 @@ wd_reaper_lifecheck(pid_t pid, int status) return g_hb_receiver_pid[i]; } + } - else if (g_hb_sender_pid && pid == g_hb_sender_pid[i]) + for (i = 0; i < pool_config->num_hb_dest_if; i++) + { + if (g_hb_sender_pid && pid == g_hb_sender_pid[i]) { if (restart_child) { @@ -253,17 +259,21 @@ lifecheck_kill_all_children(int sig) && g_hb_receiver_pid && g_hb_sender_pid) { int i; + pid_t pid_child; - for (i = 0; i < pool_config->num_hb_dest_if; i++) + for (i = 0; i < pool_config->num_hb_local_if; i++) { - pid_t pid_child = g_hb_receiver_pid[i]; + pid_child = g_hb_receiver_pid[i]; if (pid_child > 0) { kill(pid_child, sig); ret = true; } + } + for (i = 0; i < pool_config->num_hb_dest_if; i++) + { pid_child = g_hb_sender_pid[i]; if (pid_child > 0) @@ -378,6 +388,7 @@ lifecheck_main(void) { sigjmp_buf local_sigjmp_buf; int i; + bool need_life_check_warning = false; ereport(DEBUG1, (errmsg("I am watchdog lifecheck child with pid:%d", getpid()))); @@ -424,6 +435,14 @@ lifecheck_main(void) /* wait until ready to go */ while (WD_OK != is_wd_lifecheck_ready()) { + /* + * For the first time we do not emit warning since it is likely the + * life check is not ready. + */ + if (need_life_check_warning) + ereport(WARNING, + (errmsg("watchdog: lifecheck has not started yet"))); + need_life_check_warning = true; sleep(pool_config->wd_interval * 10); } @@ -468,14 +487,17 @@ spawn_lifecheck_children(void) { int i; - g_hb_receiver_pid = palloc0(sizeof(pid_t) * pool_config->num_hb_dest_if); + g_hb_receiver_pid = palloc0(sizeof(pid_t) * pool_config->num_hb_local_if); g_hb_sender_pid = palloc0(sizeof(pid_t) * pool_config->num_hb_dest_if); - for (i = 0; i < pool_config->num_hb_dest_if; i++) + for (i = 0; i < pool_config->num_hb_local_if; i++) { /* heartbeat receiver process */ - g_hb_receiver_pid[i] = wd_hb_receiver(1, &(pool_config->hb_dest_if[i])); + g_hb_receiver_pid[i] = wd_hb_receiver(1, &(pool_config->hb_local_if[i])); + } + for (i = 0; i < pool_config->num_hb_dest_if; i++) + { /* heartbeat sender process */ g_hb_sender_pid[i] = wd_hb_sender(1, &(pool_config->hb_dest_if[i])); } @@ -642,7 +664,14 @@ load_watchdog_nodes_from_json(char *json_data, int len) json_value_free(root); } - +/*---------- + * is_wd_lifecheck_ready + * + * Check all registered watchdog nodes and returns WD_OK if: + * query mode: wd_ping_pgpool returns WD_OK + * hearbeat mode: has received from and + * sent to all node the heartbeat message + */ static int is_wd_lifecheck_ready(void) { @@ -680,7 +709,7 @@ is_wd_lifecheck_ready(void) { ereport(DEBUG1, (errmsg("watchdog checking life check is ready"), - errdetail("pgpool:%d at \"%s:%d\" has not send the heartbeat signal yet", + errdetail("pgpool:%d at \"%s:%d\" has not received from or sent to the heartbeat signal yet", i, node->hostName, node->pgpoolPort))); rtn = WD_NG; } diff --git a/src/watchdog/wd_ping.c b/src/watchdog/wd_ping.c index 2386950f4..ef4bf8724 100644 --- a/src/watchdog/wd_ping.c +++ b/src/watchdog/wd_ping.c @@ -6,7 +6,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2022 PgPool Global Development Group + * Copyright (c) 2003-2025 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -41,6 +41,8 @@ #define WD_MAX_PING_RESULT 256 static double get_result(char *ping_data); +static bool wd_get_ping_result(char *hostname, int exit_status, int outfd); +static pid_t wd_issue_ping_command(char *hostname, int *outfd); /** * check if IP address can be pinged. @@ -95,7 +97,7 @@ wd_is_ip_exists(char *ip) * function issues the ping command using the execv system call * and return the pid of the process. */ -pid_t +static pid_t wd_issue_ping_command(char *hostname, int *outfd) { int status; @@ -254,7 +256,7 @@ wd_trusted_server_command(char *hostname) * The function is helper function and can be used with the * wd_issue_ping_command() function to identify if the ping command * was successful */ -bool +static bool wd_get_ping_result(char *hostname, int exit_status, int outfd) { /* First check the exit status of ping process */ |
