prestogres 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -0
- data/LICENSE +202 -0
- data/NOTICE +22 -0
- data/README.md +217 -0
- data/Rakefile +13 -0
- data/VERSION +1 -0
- data/bin/prestogres +254 -0
- data/config/pcp.conf.sample +28 -0
- data/config/pgpool.conf +678 -0
- data/config/pool_hba.conf +84 -0
- data/config/pool_passwd +0 -0
- data/config/postgresql.conf +2 -0
- data/ext/.gitignore +6 -0
- data/ext/depend +26 -0
- data/ext/extconf.rb +4 -0
- data/ext/prestogres_config.c +12 -0
- data/pgpool2/.gitignore +36 -0
- data/pgpool2/AUTHORS +4 -0
- data/pgpool2/COPYING +12 -0
- data/pgpool2/ChangeLog +1 -0
- data/pgpool2/INSTALL +1 -0
- data/pgpool2/Makefile.am +159 -0
- data/pgpool2/Makefile.in +1187 -0
- data/pgpool2/NEWS +4960 -0
- data/pgpool2/README +1 -0
- data/pgpool2/README.euc_jp +1 -0
- data/pgpool2/README.online-recovery +62 -0
- data/pgpool2/TODO +103 -0
- data/pgpool2/ac_func_accept_argtypes.m4 +85 -0
- data/pgpool2/aclocal.m4 +1088 -0
- data/pgpool2/c-compiler.m4 +134 -0
- data/pgpool2/c-library.m4 +325 -0
- data/pgpool2/child.c +2097 -0
- data/pgpool2/config.guess +1532 -0
- data/pgpool2/config.h.in +332 -0
- data/pgpool2/config.sub +1640 -0
- data/pgpool2/configure +15752 -0
- data/pgpool2/configure.in +392 -0
- data/pgpool2/depcomp +522 -0
- data/pgpool2/doc/basebackup.sh +17 -0
- data/pgpool2/doc/pgpool-de.html +4220 -0
- data/pgpool2/doc/pgpool-en.html +5738 -0
- data/pgpool2/doc/pgpool-fr.html +4118 -0
- data/pgpool2/doc/pgpool-ja.css +198 -0
- data/pgpool2/doc/pgpool-ja.html +11279 -0
- data/pgpool2/doc/pgpool-zh_cn.html +4445 -0
- data/pgpool2/doc/pgpool.css +280 -0
- data/pgpool2/doc/pgpool_remote_start +13 -0
- data/pgpool2/doc/recovery.conf.sample +117 -0
- data/pgpool2/doc/tutorial-en.html +707 -0
- data/pgpool2/doc/tutorial-ja.html +422 -0
- data/pgpool2/doc/tutorial-memqcache-en.html +325 -0
- data/pgpool2/doc/tutorial-memqcache-ja.html +370 -0
- data/pgpool2/doc/tutorial-memqcache-zh_cn.html +322 -0
- data/pgpool2/doc/tutorial-watchdog-en.html +306 -0
- data/pgpool2/doc/tutorial-watchdog-ja.html +343 -0
- data/pgpool2/doc/tutorial-watchdog-zh_cn.html +301 -0
- data/pgpool2/doc/tutorial-zh_cn.html +537 -0
- data/pgpool2/doc/watchdog.png +0 -0
- data/pgpool2/doc/wd-en.html +236 -0
- data/pgpool2/doc/wd-en.jpg +0 -0
- data/pgpool2/doc/wd-ja.html +219 -0
- data/pgpool2/doc/wd-ja.jpg +0 -0
- data/pgpool2/doc/wd-zh_cn.html +201 -0
- data/pgpool2/doc/where_to_send_queries.odg +0 -0
- data/pgpool2/doc/where_to_send_queries.pdf +0 -0
- data/pgpool2/general.m4 +166 -0
- data/pgpool2/getopt_long.c +200 -0
- data/pgpool2/getopt_long.h +44 -0
- data/pgpool2/install-sh +251 -0
- data/pgpool2/ltmain.sh +8406 -0
- data/pgpool2/m4/libtool.m4 +7360 -0
- data/pgpool2/m4/ltoptions.m4 +368 -0
- data/pgpool2/m4/ltsugar.m4 +123 -0
- data/pgpool2/m4/ltversion.m4 +23 -0
- data/pgpool2/m4/lt~obsolete.m4 +92 -0
- data/pgpool2/main.c +2971 -0
- data/pgpool2/md5.c +444 -0
- data/pgpool2/md5.h +28 -0
- data/pgpool2/missing +360 -0
- data/pgpool2/mkinstalldirs +40 -0
- data/pgpool2/parser/Makefile.am +50 -0
- data/pgpool2/parser/Makefile.in +559 -0
- data/pgpool2/parser/copyfuncs.c +3310 -0
- data/pgpool2/parser/gram.c +39100 -0
- data/pgpool2/parser/gram.h +940 -0
- data/pgpool2/parser/gram.y +13408 -0
- data/pgpool2/parser/gramparse.h +74 -0
- data/pgpool2/parser/keywords.c +32 -0
- data/pgpool2/parser/keywords.h +39 -0
- data/pgpool2/parser/kwlist.h +425 -0
- data/pgpool2/parser/kwlookup.c +88 -0
- data/pgpool2/parser/list.c +1156 -0
- data/pgpool2/parser/makefuncs.c +518 -0
- data/pgpool2/parser/makefuncs.h +83 -0
- data/pgpool2/parser/memnodes.h +79 -0
- data/pgpool2/parser/nodes.c +29 -0
- data/pgpool2/parser/nodes.h +609 -0
- data/pgpool2/parser/outfuncs.c +5790 -0
- data/pgpool2/parser/parsenodes.h +2615 -0
- data/pgpool2/parser/parser.c +262 -0
- data/pgpool2/parser/parser.h +46 -0
- data/pgpool2/parser/pg_class.h +158 -0
- data/pgpool2/parser/pg_config_manual.h +273 -0
- data/pgpool2/parser/pg_list.h +352 -0
- data/pgpool2/parser/pg_trigger.h +147 -0
- data/pgpool2/parser/pg_wchar.h +492 -0
- data/pgpool2/parser/pool_memory.c +342 -0
- data/pgpool2/parser/pool_memory.h +77 -0
- data/pgpool2/parser/pool_parser.h +222 -0
- data/pgpool2/parser/pool_string.c +121 -0
- data/pgpool2/parser/pool_string.h +37 -0
- data/pgpool2/parser/primnodes.h +1280 -0
- data/pgpool2/parser/scan.c +4094 -0
- data/pgpool2/parser/scan.l +1451 -0
- data/pgpool2/parser/scanner.h +120 -0
- data/pgpool2/parser/scansup.c +221 -0
- data/pgpool2/parser/scansup.h +28 -0
- data/pgpool2/parser/snprintf.c +1102 -0
- data/pgpool2/parser/stringinfo.c +294 -0
- data/pgpool2/parser/stringinfo.h +178 -0
- data/pgpool2/parser/value.c +78 -0
- data/pgpool2/parser/value.h +62 -0
- data/pgpool2/parser/wchar.c +2048 -0
- data/pgpool2/pcp.conf.sample +28 -0
- data/pgpool2/pcp/Makefile.am +40 -0
- data/pgpool2/pcp/Makefile.in +771 -0
- data/pgpool2/pcp/libpcp_ext.h +250 -0
- data/pgpool2/pcp/md5.c +444 -0
- data/pgpool2/pcp/md5.h +28 -0
- data/pgpool2/pcp/pcp.c +1652 -0
- data/pgpool2/pcp/pcp.h +61 -0
- data/pgpool2/pcp/pcp_attach_node.c +172 -0
- data/pgpool2/pcp/pcp_detach_node.c +185 -0
- data/pgpool2/pcp/pcp_error.c +87 -0
- data/pgpool2/pcp/pcp_node_count.c +160 -0
- data/pgpool2/pcp/pcp_node_info.c +198 -0
- data/pgpool2/pcp/pcp_pool_status.c +166 -0
- data/pgpool2/pcp/pcp_proc_count.c +166 -0
- data/pgpool2/pcp/pcp_proc_info.c +261 -0
- data/pgpool2/pcp/pcp_promote_node.c +185 -0
- data/pgpool2/pcp/pcp_recovery_node.c +172 -0
- data/pgpool2/pcp/pcp_stop_pgpool.c +179 -0
- data/pgpool2/pcp/pcp_stream.c +385 -0
- data/pgpool2/pcp/pcp_stream.h +52 -0
- data/pgpool2/pcp/pcp_systemdb_info.c +194 -0
- data/pgpool2/pcp/pcp_watchdog_info.c +211 -0
- data/pgpool2/pcp_child.c +1493 -0
- data/pgpool2/pg_md5.c +305 -0
- data/pgpool2/pgpool.8.in +121 -0
- data/pgpool2/pgpool.conf +553 -0
- data/pgpool2/pgpool.conf.sample +666 -0
- data/pgpool2/pgpool.conf.sample-master-slave +665 -0
- data/pgpool2/pgpool.conf.sample-replication +664 -0
- data/pgpool2/pgpool.conf.sample-stream +664 -0
- data/pgpool2/pgpool.spec +264 -0
- data/pgpool2/pgpool_adm/TODO +7 -0
- data/pgpool2/pgpool_adm/pgpool_adm--1.0.sql +85 -0
- data/pgpool2/pgpool_adm/pgpool_adm.c +558 -0
- data/pgpool2/pgpool_adm/pgpool_adm.control +5 -0
- data/pgpool2/pgpool_adm/pgpool_adm.h +46 -0
- data/pgpool2/pgpool_adm/pgpool_adm.sql.in +85 -0
- data/pgpool2/pool.h +655 -0
- data/pgpool2/pool_auth.c +1390 -0
- data/pgpool2/pool_config.c +5007 -0
- data/pgpool2/pool_config.h +284 -0
- data/pgpool2/pool_config.l +3281 -0
- data/pgpool2/pool_config_md5.c +29 -0
- data/pgpool2/pool_connection_pool.c +812 -0
- data/pgpool2/pool_error.c +242 -0
- data/pgpool2/pool_globals.c +27 -0
- data/pgpool2/pool_hba.c +1723 -0
- data/pgpool2/pool_hba.conf.sample +67 -0
- data/pgpool2/pool_ip.c +567 -0
- data/pgpool2/pool_ip.h +65 -0
- data/pgpool2/pool_ipc.h +38 -0
- data/pgpool2/pool_lobj.c +242 -0
- data/pgpool2/pool_lobj.h +32 -0
- data/pgpool2/pool_memqcache.c +3818 -0
- data/pgpool2/pool_memqcache.h +268 -0
- data/pgpool2/pool_params.c +163 -0
- data/pgpool2/pool_passwd.c +249 -0
- data/pgpool2/pool_passwd.h +41 -0
- data/pgpool2/pool_path.c +193 -0
- data/pgpool2/pool_path.h +81 -0
- data/pgpool2/pool_process_context.c +247 -0
- data/pgpool2/pool_process_context.h +62 -0
- data/pgpool2/pool_process_query.c +5001 -0
- data/pgpool2/pool_process_reporting.c +1671 -0
- data/pgpool2/pool_process_reporting.h +44 -0
- data/pgpool2/pool_proto2.c +671 -0
- data/pgpool2/pool_proto_modules.c +3524 -0
- data/pgpool2/pool_proto_modules.h +185 -0
- data/pgpool2/pool_query_cache.c +1020 -0
- data/pgpool2/pool_query_context.c +1871 -0
- data/pgpool2/pool_query_context.h +105 -0
- data/pgpool2/pool_relcache.c +284 -0
- data/pgpool2/pool_relcache.h +78 -0
- data/pgpool2/pool_rewrite_outfuncs.c +9060 -0
- data/pgpool2/pool_rewrite_query.c +715 -0
- data/pgpool2/pool_rewrite_query.h +192 -0
- data/pgpool2/pool_select_walker.c +1150 -0
- data/pgpool2/pool_select_walker.h +68 -0
- data/pgpool2/pool_sema.c +161 -0
- data/pgpool2/pool_session_context.c +952 -0
- data/pgpool2/pool_session_context.h +203 -0
- data/pgpool2/pool_shmem.c +185 -0
- data/pgpool2/pool_signal.c +158 -0
- data/pgpool2/pool_signal.h +61 -0
- data/pgpool2/pool_ssl.c +339 -0
- data/pgpool2/pool_stream.c +962 -0
- data/pgpool2/pool_stream.h +61 -0
- data/pgpool2/pool_system.c +659 -0
- data/pgpool2/pool_timestamp.c +1215 -0
- data/pgpool2/pool_timestamp.h +38 -0
- data/pgpool2/pool_type.h +171 -0
- data/pgpool2/pool_worker_child.c +384 -0
- data/pgpool2/ps_status.c +404 -0
- data/pgpool2/recovery.c +435 -0
- data/pgpool2/redhat/pgpool.conf.sample.patch +52 -0
- data/pgpool2/redhat/pgpool.init +201 -0
- data/pgpool2/redhat/pgpool.sysconfig +7 -0
- data/pgpool2/redhat/rpm_installer/basebackup-replication.sh +53 -0
- data/pgpool2/redhat/rpm_installer/basebackup-stream.sh +55 -0
- data/pgpool2/redhat/rpm_installer/config_for_script +17 -0
- data/pgpool2/redhat/rpm_installer/failover.sh +64 -0
- data/pgpool2/redhat/rpm_installer/getsources.sh +141 -0
- data/pgpool2/redhat/rpm_installer/install.sh +1363 -0
- data/pgpool2/redhat/rpm_installer/pgpool_recovery_pitr +47 -0
- data/pgpool2/redhat/rpm_installer/pgpool_remote_start +15 -0
- data/pgpool2/redhat/rpm_installer/recovery.conf +4 -0
- data/pgpool2/redhat/rpm_installer/uninstall.sh +57 -0
- data/pgpool2/sample/dist_def_pgbench.sql +73 -0
- data/pgpool2/sample/pgpool.pam +3 -0
- data/pgpool2/sample/pgpool_recovery +20 -0
- data/pgpool2/sample/pgpool_recovery_pitr +19 -0
- data/pgpool2/sample/pgpool_remote_start +13 -0
- data/pgpool2/sample/replicate_def_pgbench.sql +18 -0
- data/pgpool2/sql/insert_lock.sql +15 -0
- data/pgpool2/sql/pgpool-recovery/pgpool-recovery.c +280 -0
- data/pgpool2/sql/pgpool-recovery/pgpool-recovery.sql.in +19 -0
- data/pgpool2/sql/pgpool-recovery/pgpool_recovery--1.0.sql +24 -0
- data/pgpool2/sql/pgpool-recovery/pgpool_recovery.control +5 -0
- data/pgpool2/sql/pgpool-recovery/uninstall_pgpool-recovery.sql +3 -0
- data/pgpool2/sql/pgpool-regclass/pgpool-regclass.c +206 -0
- data/pgpool2/sql/pgpool-regclass/pgpool-regclass.sql.in +4 -0
- data/pgpool2/sql/pgpool-regclass/pgpool_regclass--1.0.sql +7 -0
- data/pgpool2/sql/pgpool-regclass/pgpool_regclass.control +5 -0
- data/pgpool2/sql/pgpool-regclass/uninstall_pgpool-regclass.sql +1 -0
- data/pgpool2/sql/system_db.sql +38 -0
- data/pgpool2/strlcpy.c +85 -0
- data/pgpool2/test/C/test_extended.c +98 -0
- data/pgpool2/test/jdbc/.cvsignore +2 -0
- data/pgpool2/test/jdbc/AutoCommitTest.java +45 -0
- data/pgpool2/test/jdbc/BatchTest.java +55 -0
- data/pgpool2/test/jdbc/ColumnTest.java +60 -0
- data/pgpool2/test/jdbc/CreateTempTableTest.java +48 -0
- data/pgpool2/test/jdbc/InsertTest.java +34 -0
- data/pgpool2/test/jdbc/LockTest.java +36 -0
- data/pgpool2/test/jdbc/PgpoolTest.java +75 -0
- data/pgpool2/test/jdbc/README.euc_jp +73 -0
- data/pgpool2/test/jdbc/RunTest.java +83 -0
- data/pgpool2/test/jdbc/SelectTest.java +37 -0
- data/pgpool2/test/jdbc/UpdateTest.java +32 -0
- data/pgpool2/test/jdbc/expected/CreateTempTable +1 -0
- data/pgpool2/test/jdbc/expected/autocommit +10 -0
- data/pgpool2/test/jdbc/expected/batch +1 -0
- data/pgpool2/test/jdbc/expected/column +100 -0
- data/pgpool2/test/jdbc/expected/insert +1 -0
- data/pgpool2/test/jdbc/expected/lock +100 -0
- data/pgpool2/test/jdbc/expected/select +2 -0
- data/pgpool2/test/jdbc/expected/update +1 -0
- data/pgpool2/test/jdbc/pgpool.properties +7 -0
- data/pgpool2/test/jdbc/prepare.sql +54 -0
- data/pgpool2/test/jdbc/run.sh +6 -0
- data/pgpool2/test/parser/.cvsignore +6 -0
- data/pgpool2/test/parser/README +32 -0
- data/pgpool2/test/parser/expected/copy.out +17 -0
- data/pgpool2/test/parser/expected/create.out +64 -0
- data/pgpool2/test/parser/expected/cursor.out +37 -0
- data/pgpool2/test/parser/expected/delete.out +10 -0
- data/pgpool2/test/parser/expected/drop.out +12 -0
- data/pgpool2/test/parser/expected/insert.out +13 -0
- data/pgpool2/test/parser/expected/misc.out +28 -0
- data/pgpool2/test/parser/expected/prepare.out +4 -0
- data/pgpool2/test/parser/expected/privileges.out +31 -0
- data/pgpool2/test/parser/expected/scanner.out +30 -0
- data/pgpool2/test/parser/expected/select.out +89 -0
- data/pgpool2/test/parser/expected/transaction.out +38 -0
- data/pgpool2/test/parser/expected/update.out +11 -0
- data/pgpool2/test/parser/expected/v84.out +37 -0
- data/pgpool2/test/parser/expected/v90.out +25 -0
- data/pgpool2/test/parser/expected/var.out +22 -0
- data/pgpool2/test/parser/input/alter.sql +2 -0
- data/pgpool2/test/parser/input/copy.sql +17 -0
- data/pgpool2/test/parser/input/create.sql +64 -0
- data/pgpool2/test/parser/input/cursor.sql +37 -0
- data/pgpool2/test/parser/input/delete.sql +10 -0
- data/pgpool2/test/parser/input/drop.sql +12 -0
- data/pgpool2/test/parser/input/insert.sql +13 -0
- data/pgpool2/test/parser/input/misc.sql +28 -0
- data/pgpool2/test/parser/input/prepare.sql +4 -0
- data/pgpool2/test/parser/input/privileges.sql +31 -0
- data/pgpool2/test/parser/input/scanner.sql +34 -0
- data/pgpool2/test/parser/input/select.sql +89 -0
- data/pgpool2/test/parser/input/transaction.sql +38 -0
- data/pgpool2/test/parser/input/update.sql +11 -0
- data/pgpool2/test/parser/input/v84.sql +37 -0
- data/pgpool2/test/parser/input/v90.sql +38 -0
- data/pgpool2/test/parser/input/var.sql +22 -0
- data/pgpool2/test/parser/main.c +96 -0
- data/pgpool2/test/parser/parse_schedule +16 -0
- data/pgpool2/test/parser/pool.h +13 -0
- data/pgpool2/test/parser/run-test +62 -0
- data/pgpool2/test/pdo-test/README.euc_jp +58 -0
- data/pgpool2/test/pdo-test/SQLlist/test1.sql +3 -0
- data/pgpool2/test/pdo-test/SQLlist/test2.sql +3 -0
- data/pgpool2/test/pdo-test/collections.inc +11 -0
- data/pgpool2/test/pdo-test/def.inc +7 -0
- data/pgpool2/test/pdo-test/log.txt +0 -0
- data/pgpool2/test/pdo-test/mod/database.inc +36 -0
- data/pgpool2/test/pdo-test/mod/def.inc +0 -0
- data/pgpool2/test/pdo-test/mod/errorhandler.inc +27 -0
- data/pgpool2/test/pdo-test/pdotest.php +11 -0
- data/pgpool2/test/pdo-test/regsql.inc +56 -0
- data/pgpool2/test/pgpool_setup +898 -0
- data/pgpool2/test/regression/README +39 -0
- data/pgpool2/test/regression/clean.sh +21 -0
- data/pgpool2/test/regression/libs.sh +16 -0
- data/pgpool2/test/regression/regress.sh +166 -0
- data/pgpool2/test/regression/tests/001.load_balance/test.sh +128 -0
- data/pgpool2/test/regression/tests/002.native_replication/PgTester.java +47 -0
- data/pgpool2/test/regression/tests/002.native_replication/create.sql +6 -0
- data/pgpool2/test/regression/tests/002.native_replication/test.sh +71 -0
- data/pgpool2/test/regression/tests/003.failover/expected.r +6 -0
- data/pgpool2/test/regression/tests/003.failover/expected.s +6 -0
- data/pgpool2/test/regression/tests/003.failover/test.sh +45 -0
- data/pgpool2/test/regression/tests/004.watchdog/master.conf +12 -0
- data/pgpool2/test/regression/tests/004.watchdog/standby.conf +19 -0
- data/pgpool2/test/regression/tests/004.watchdog/test.sh +52 -0
- data/pgpool2/test/regression/tests/050.bug58/test.sh +50 -0
- data/pgpool2/test/regression/tests/051.bug60/bug.sql +12 -0
- data/pgpool2/test/regression/tests/051.bug60/database-clean.sql +6 -0
- data/pgpool2/test/regression/tests/051.bug60/database-setup.sql +28 -0
- data/pgpool2/test/regression/tests/051.bug60/test.sh +79 -0
- data/pgpool2/test/regression/tests/052.do_query/test.sh +44 -0
- data/pgpool2/test/regression/tests/053.insert_lock_hangs/test.sh +81 -0
- data/pgpool2/test/regression/tests/054.postgres_fdw/test.sh +67 -0
- data/pgpool2/test/regression/tests/055.backend_all_down/test.sh +52 -0
- data/pgpool2/test/regression/tests/056.bug63/jdbctest2.java +66 -0
- data/pgpool2/test/regression/tests/056.bug63/test.sh +47 -0
- data/pgpool2/test/regression/tests/057.bug61/test.sh +40 -0
- data/pgpool2/test/regression/tests/058.bug68/jdbctest3.java +45 -0
- data/pgpool2/test/regression/tests/058.bug68/test.sh +47 -0
- data/pgpool2/test/timestamp/expected/insert.out +16 -0
- data/pgpool2/test/timestamp/expected/misc.out +3 -0
- data/pgpool2/test/timestamp/expected/update.out +6 -0
- data/pgpool2/test/timestamp/input/insert.sql +16 -0
- data/pgpool2/test/timestamp/input/misc.sql +3 -0
- data/pgpool2/test/timestamp/input/update.sql +6 -0
- data/pgpool2/test/timestamp/main.c +129 -0
- data/pgpool2/test/timestamp/parse_schedule +3 -0
- data/pgpool2/test/timestamp/run-test +69 -0
- data/pgpool2/version.h +1 -0
- data/pgpool2/watchdog/Makefile.am +17 -0
- data/pgpool2/watchdog/Makefile.in +505 -0
- data/pgpool2/watchdog/test/stab.c +266 -0
- data/pgpool2/watchdog/test/test.c +85 -0
- data/pgpool2/watchdog/test/wd_child_t.c +87 -0
- data/pgpool2/watchdog/test/wd_lifecheck_t.c +87 -0
- data/pgpool2/watchdog/test/wd_packet_t.c +87 -0
- data/pgpool2/watchdog/test/wd_ping_t.c +20 -0
- data/pgpool2/watchdog/watchdog.c +408 -0
- data/pgpool2/watchdog/watchdog.h +209 -0
- data/pgpool2/watchdog/wd_child.c +444 -0
- data/pgpool2/watchdog/wd_ext.h +123 -0
- data/pgpool2/watchdog/wd_heartbeat.c +577 -0
- data/pgpool2/watchdog/wd_if.c +216 -0
- data/pgpool2/watchdog/wd_init.c +126 -0
- data/pgpool2/watchdog/wd_interlock.c +347 -0
- data/pgpool2/watchdog/wd_lifecheck.c +512 -0
- data/pgpool2/watchdog/wd_list.c +429 -0
- data/pgpool2/watchdog/wd_packet.c +1159 -0
- data/pgpool2/watchdog/wd_ping.c +330 -0
- data/pgpool2/ylwrap +223 -0
- data/pgsql/presto_client.py +346 -0
- data/pgsql/prestogres.py +156 -0
- data/pgsql/setup_functions.sql +21 -0
- data/pgsql/setup_language.sql +3 -0
- data/prestogres.gemspec +23 -0
- metadata +496 -0
|
@@ -0,0 +1,1871 @@
|
|
|
1
|
+
/* -*-pgsql-c-*- */
|
|
2
|
+
/*
|
|
3
|
+
*
|
|
4
|
+
* $Header$
|
|
5
|
+
*
|
|
6
|
+
* pgpool: a language independent connection pool server for PostgreSQL
|
|
7
|
+
* written by Tatsuo Ishii
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) 2003-2013 PgPool Global Development Group
|
|
10
|
+
*
|
|
11
|
+
* Permission to use, copy, modify, and distribute this software and
|
|
12
|
+
* its documentation for any purpose and without fee is hereby
|
|
13
|
+
* granted, provided that the above copyright notice appear in all
|
|
14
|
+
* copies and that both that copyright notice and this permission
|
|
15
|
+
* notice appear in supporting documentation, and that the name of the
|
|
16
|
+
* author not be used in advertising or publicity pertaining to
|
|
17
|
+
* distribution of the software without specific, written prior
|
|
18
|
+
* permission. The author makes no representations about the
|
|
19
|
+
* suitability of this software for any purpose. It is provided "as
|
|
20
|
+
* is" without express or implied warranty.
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
#include "pool.h"
|
|
24
|
+
#include "pool_config.h"
|
|
25
|
+
#include "pool_proto_modules.h"
|
|
26
|
+
#include "pool_session_context.h"
|
|
27
|
+
#include "pool_query_context.h"
|
|
28
|
+
#include "pool_select_walker.h"
|
|
29
|
+
#include "parser/nodes.h"
|
|
30
|
+
|
|
31
|
+
#include <string.h>
|
|
32
|
+
#include <netinet/in.h>
|
|
33
|
+
#include <stdlib.h>
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Where to send query
|
|
37
|
+
*/
|
|
38
|
+
typedef enum {
|
|
39
|
+
POOL_PRIMARY,
|
|
40
|
+
POOL_STANDBY,
|
|
41
|
+
POOL_EITHER,
|
|
42
|
+
POOL_BOTH
|
|
43
|
+
} POOL_DEST;
|
|
44
|
+
|
|
45
|
+
static POOL_DEST send_to_where(Node *node, char *query);
|
|
46
|
+
static void where_to_send_deallocate(POOL_QUERY_CONTEXT *query_context, Node *node);
|
|
47
|
+
static char* remove_read_write(int len, const char *contents, int *rewritten_len);
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Create and initialize per query session context
|
|
51
|
+
*/
|
|
52
|
+
POOL_QUERY_CONTEXT *pool_init_query_context(void)
|
|
53
|
+
{
|
|
54
|
+
POOL_QUERY_CONTEXT *qc;
|
|
55
|
+
|
|
56
|
+
qc = calloc(1, sizeof(*qc));
|
|
57
|
+
if (!qc)
|
|
58
|
+
{
|
|
59
|
+
pool_error("pool_init_query_context: cannot allocate memory");
|
|
60
|
+
return NULL;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Create memory context */
|
|
64
|
+
qc->memory_context = pool_memory_create(PARSER_BLOCK_SIZE);
|
|
65
|
+
|
|
66
|
+
return qc;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
* Destroy query context
|
|
71
|
+
*/
|
|
72
|
+
void pool_query_context_destroy(POOL_QUERY_CONTEXT *query_context)
|
|
73
|
+
{
|
|
74
|
+
POOL_SESSION_CONTEXT *session_context;
|
|
75
|
+
|
|
76
|
+
if (query_context)
|
|
77
|
+
{
|
|
78
|
+
session_context = pool_get_session_context();
|
|
79
|
+
pool_unset_query_in_progress();
|
|
80
|
+
session_context->query_context = NULL;
|
|
81
|
+
pool_memory_delete(query_context->memory_context, 0);
|
|
82
|
+
free(query_context);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* Start query
|
|
88
|
+
*/
|
|
89
|
+
void pool_start_query(POOL_QUERY_CONTEXT *query_context, char *query, int len, Node *node)
|
|
90
|
+
{
|
|
91
|
+
POOL_SESSION_CONTEXT *session_context;
|
|
92
|
+
|
|
93
|
+
if (query_context)
|
|
94
|
+
{
|
|
95
|
+
session_context = pool_get_session_context();
|
|
96
|
+
query_context->original_length = len;
|
|
97
|
+
query_context->rewritten_length = -1;
|
|
98
|
+
query_context->original_query = pstrdup(query);
|
|
99
|
+
query_context->rewritten_query = NULL;
|
|
100
|
+
query_context->parse_tree = node;
|
|
101
|
+
query_context->virtual_master_node_id = my_master_node_id;
|
|
102
|
+
query_context->is_cache_safe = false;
|
|
103
|
+
if (pool_config->memory_cache_enabled)
|
|
104
|
+
query_context->temp_cache = pool_create_temp_query_cache(query);
|
|
105
|
+
pool_set_query_in_progress();
|
|
106
|
+
session_context->query_context = query_context;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
* Specify DB node to send query
|
|
112
|
+
*/
|
|
113
|
+
void pool_set_node_to_be_sent(POOL_QUERY_CONTEXT *query_context, int node_id)
|
|
114
|
+
{
|
|
115
|
+
if (!query_context)
|
|
116
|
+
{
|
|
117
|
+
pool_error("pool_set_node_to_be_sent: no query context");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS)
|
|
122
|
+
{
|
|
123
|
+
pool_error("pool_set_node_to_be_sent: invalid node id:%d", node_id);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
query_context->where_to_send[node_id] = true;
|
|
128
|
+
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
* Unspecify DB node to send query
|
|
134
|
+
*/
|
|
135
|
+
void pool_unset_node_to_be_sent(POOL_QUERY_CONTEXT *query_context, int node_id)
|
|
136
|
+
{
|
|
137
|
+
if (!query_context)
|
|
138
|
+
{
|
|
139
|
+
pool_error("pool_unset_node_to_be_sent: no query context");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS)
|
|
144
|
+
{
|
|
145
|
+
pool_error("pool_unset_node_to_be_sent: invalid node id:%d", node_id);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
query_context->where_to_send[node_id] = false;
|
|
150
|
+
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* Clear DB node map
|
|
156
|
+
*/
|
|
157
|
+
void pool_clear_node_to_be_sent(POOL_QUERY_CONTEXT *query_context)
|
|
158
|
+
{
|
|
159
|
+
if (!query_context)
|
|
160
|
+
{
|
|
161
|
+
pool_error("pool_clear_node_to_be_sent: no query context");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
memset(query_context->where_to_send, false, sizeof(query_context->where_to_send));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
* Set all DB node map entry
|
|
170
|
+
*/
|
|
171
|
+
void pool_setall_node_to_be_sent(POOL_QUERY_CONTEXT *query_context)
|
|
172
|
+
{
|
|
173
|
+
int i;
|
|
174
|
+
|
|
175
|
+
if (!query_context)
|
|
176
|
+
{
|
|
177
|
+
pool_error("pool_setall_node_to_be_sent: no query context");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
182
|
+
{
|
|
183
|
+
if (private_backend_status[i] == CON_UP ||
|
|
184
|
+
(private_backend_status[i] == CON_CONNECT_WAIT))
|
|
185
|
+
query_context->where_to_send[i] = true;
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/*
|
|
191
|
+
* Return true if multiple nodes are targets
|
|
192
|
+
*/
|
|
193
|
+
bool pool_multi_node_to_be_sent(POOL_QUERY_CONTEXT *query_context)
|
|
194
|
+
{
|
|
195
|
+
int i;
|
|
196
|
+
int cnt = 0;
|
|
197
|
+
|
|
198
|
+
if (!query_context)
|
|
199
|
+
{
|
|
200
|
+
pool_error("pool_multi_node_to_be_sent: no query context");
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
205
|
+
{
|
|
206
|
+
if (((BACKEND_INFO(i)).backend_status == CON_UP ||
|
|
207
|
+
BACKEND_INFO((i)).backend_status == CON_CONNECT_WAIT) &&
|
|
208
|
+
query_context->where_to_send[i])
|
|
209
|
+
{
|
|
210
|
+
cnt++;
|
|
211
|
+
if (cnt > 1)
|
|
212
|
+
{
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/*
|
|
221
|
+
* Return if the DB node is needed to send query
|
|
222
|
+
*/
|
|
223
|
+
bool pool_is_node_to_be_sent(POOL_QUERY_CONTEXT *query_context, int node_id)
|
|
224
|
+
{
|
|
225
|
+
if (!query_context)
|
|
226
|
+
{
|
|
227
|
+
pool_error("pool_is_node_to_be_sent: no query context");
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS)
|
|
232
|
+
{
|
|
233
|
+
pool_error("pool_is_node_to_be_sent: invalid node id:%d", node_id);
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return query_context->where_to_send[node_id];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* Returns true if the DB node is needed to send query.
|
|
242
|
+
* Intended to be called from VALID_BACKEND
|
|
243
|
+
*/
|
|
244
|
+
bool pool_is_node_to_be_sent_in_current_query(int node_id)
|
|
245
|
+
{
|
|
246
|
+
POOL_SESSION_CONTEXT *sc;
|
|
247
|
+
|
|
248
|
+
if (RAW_MODE)
|
|
249
|
+
return node_id == REAL_MASTER_NODE_ID;
|
|
250
|
+
|
|
251
|
+
sc = pool_get_session_context();
|
|
252
|
+
if (!sc)
|
|
253
|
+
return true;
|
|
254
|
+
|
|
255
|
+
if (pool_is_query_in_progress() && sc->query_context)
|
|
256
|
+
{
|
|
257
|
+
return pool_is_node_to_be_sent(sc->query_context, node_id);
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/*
|
|
263
|
+
* Returns virtual master DB node id,
|
|
264
|
+
*/
|
|
265
|
+
int pool_virtual_master_db_node_id(void)
|
|
266
|
+
{
|
|
267
|
+
POOL_SESSION_CONTEXT *sc;
|
|
268
|
+
|
|
269
|
+
sc = pool_get_session_context();
|
|
270
|
+
if (!sc)
|
|
271
|
+
{
|
|
272
|
+
return REAL_MASTER_NODE_ID;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (sc->query_context)
|
|
276
|
+
{
|
|
277
|
+
return sc->query_context->virtual_master_node_id;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/*
|
|
281
|
+
* No query context exists. If in master/slave mode, returns
|
|
282
|
+
* primary node if exists. Otherwise returns my_master_node_id,
|
|
283
|
+
* which represents the last REAL_MASTER_NODE_ID.
|
|
284
|
+
*/
|
|
285
|
+
if (MASTER_SLAVE)
|
|
286
|
+
{
|
|
287
|
+
return PRIMARY_NODE_ID;
|
|
288
|
+
}
|
|
289
|
+
return my_master_node_id;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
char rewrite_query_string_buffer[QUERY_STRING_BUFFER_LEN];
|
|
293
|
+
|
|
294
|
+
#ifndef PRESTO_RESULT_TABLE_NAME
|
|
295
|
+
#define PRESTO_RESULT_TABLE_NAME "presto_result"
|
|
296
|
+
#endif
|
|
297
|
+
|
|
298
|
+
static POOL_STATUS run_clear_query(POOL_SESSION_CONTEXT* session_context, POOL_QUERY_CONTEXT* query_context)
|
|
299
|
+
{
|
|
300
|
+
//POOL_STATUS status;
|
|
301
|
+
//POOL_SELECT_RESULT *res;
|
|
302
|
+
//POOL_CONNECTION *con;
|
|
303
|
+
//POOL_CONNECTION_POOL *backend = session_context->backend;
|
|
304
|
+
//con = CONNECTION(backend, session_context->load_balance_node_id);
|
|
305
|
+
|
|
306
|
+
// do something if multi-statement?
|
|
307
|
+
|
|
308
|
+
return POOL_CONTINUE;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
static POOL_STATUS run_system_catalog_query(POOL_SESSION_CONTEXT* session_context, POOL_QUERY_CONTEXT* query_context)
|
|
312
|
+
{
|
|
313
|
+
POOL_STATUS status;
|
|
314
|
+
POOL_SELECT_RESULT *res;
|
|
315
|
+
POOL_CONNECTION *con;
|
|
316
|
+
POOL_CONNECTION_POOL *backend = session_context->backend;
|
|
317
|
+
con = CONNECTION(backend, session_context->load_balance_node_id);
|
|
318
|
+
|
|
319
|
+
snprintf(rewrite_query_string_buffer, sizeof(rewrite_query_string_buffer),
|
|
320
|
+
"select presto_create_tables('%s', '%s', '%s')",
|
|
321
|
+
presto_server, presto_user, presto_catalog);
|
|
322
|
+
status = do_query(con, rewrite_query_string_buffer, &res, MAJOR(backend));
|
|
323
|
+
free_select_result(res);
|
|
324
|
+
|
|
325
|
+
if (status != POOL_CONTINUE) {
|
|
326
|
+
// TODO error message
|
|
327
|
+
return status;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return POOL_CONTINUE;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static char* escape_original_query(const char* original_query)
|
|
334
|
+
{
|
|
335
|
+
char* query;
|
|
336
|
+
char* c;
|
|
337
|
+
|
|
338
|
+
query = malloc(QUERY_STRING_BUFFER_LEN);
|
|
339
|
+
strlcpy(query, original_query, QUERY_STRING_BUFFER_LEN);
|
|
340
|
+
|
|
341
|
+
// remove last ;
|
|
342
|
+
c = strrchr(query, ';');
|
|
343
|
+
if (c != NULL) {
|
|
344
|
+
*c = '\0';
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// TODO escape ' character
|
|
348
|
+
|
|
349
|
+
return query;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
static POOL_STATUS run_presto_query(POOL_SESSION_CONTEXT* session_context, POOL_QUERY_CONTEXT* query_context)
|
|
353
|
+
{
|
|
354
|
+
POOL_STATUS status;
|
|
355
|
+
POOL_SELECT_RESULT *res;
|
|
356
|
+
POOL_CONNECTION *con;
|
|
357
|
+
POOL_CONNECTION_POOL *backend = session_context->backend;
|
|
358
|
+
con = CONNECTION(backend, session_context->load_balance_node_id);
|
|
359
|
+
char* query;
|
|
360
|
+
|
|
361
|
+
snprintf(rewrite_query_string_buffer, sizeof(rewrite_query_string_buffer),
|
|
362
|
+
"drop table if exists %s",
|
|
363
|
+
PRESTO_RESULT_TABLE_NAME);
|
|
364
|
+
status = do_query(con, rewrite_query_string_buffer, &res, MAJOR(backend));
|
|
365
|
+
free_select_result(res);
|
|
366
|
+
|
|
367
|
+
if (status != POOL_CONTINUE) {
|
|
368
|
+
// TODO error message
|
|
369
|
+
return status;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
query = escape_original_query(query_context->original_query);
|
|
373
|
+
snprintf(rewrite_query_string_buffer, sizeof(rewrite_query_string_buffer),
|
|
374
|
+
"select run_presto_as_temp_table('%s', '%s', '%s', '%s', '%s', '%s')",
|
|
375
|
+
presto_server, presto_user, presto_catalog, presto_schema,
|
|
376
|
+
PRESTO_RESULT_TABLE_NAME, query);
|
|
377
|
+
free(query);
|
|
378
|
+
|
|
379
|
+
status = do_query(con, rewrite_query_string_buffer, &res, MAJOR(backend));
|
|
380
|
+
free_select_result(res);
|
|
381
|
+
|
|
382
|
+
if (status != POOL_CONTINUE) {
|
|
383
|
+
// TODO error message
|
|
384
|
+
return status;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return POOL_CONTINUE;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
static void do_replace_query(POOL_QUERY_CONTEXT* query_context, const char* query)
|
|
391
|
+
{
|
|
392
|
+
char* dupq = pstrdup(query);
|
|
393
|
+
|
|
394
|
+
query_context->original_query = dupq;
|
|
395
|
+
query_context->original_length = strlen(dupq) + 1;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
static void rewrite_presto_query(POOL_QUERY_CONTEXT* query_context)
|
|
399
|
+
{
|
|
400
|
+
snprintf(rewrite_query_string_buffer, sizeof(rewrite_query_string_buffer),
|
|
401
|
+
"select * from %s", PRESTO_RESULT_TABLE_NAME);
|
|
402
|
+
do_replace_query(query_context, rewrite_query_string_buffer);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
static void rewrite_error_query(POOL_QUERY_CONTEXT* query_context, const char* message)
|
|
406
|
+
{
|
|
407
|
+
// TODO
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/*
|
|
411
|
+
* Decide where to send queries(thus expecting response)
|
|
412
|
+
*/
|
|
413
|
+
void pool_where_to_send(POOL_QUERY_CONTEXT *query_context, char *query, Node *node)
|
|
414
|
+
{
|
|
415
|
+
POOL_SESSION_CONTEXT *session_context;
|
|
416
|
+
POOL_CONNECTION_POOL *backend;
|
|
417
|
+
int i;
|
|
418
|
+
|
|
419
|
+
POOL_STATUS status;
|
|
420
|
+
const char* rewrite_error_message;
|
|
421
|
+
enum {
|
|
422
|
+
REWRITE_CLEAR,
|
|
423
|
+
REWRITE_SYSTEM_CATALOG,
|
|
424
|
+
REWRITE_PRESTO,
|
|
425
|
+
REWRITE_ERROR,
|
|
426
|
+
} rewrite_mode = REWRITE_CLEAR;
|
|
427
|
+
|
|
428
|
+
if (!query_context)
|
|
429
|
+
{
|
|
430
|
+
pool_error("pool_where_to_send: no query context");
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
session_context = pool_get_session_context();
|
|
435
|
+
backend = session_context->backend;
|
|
436
|
+
|
|
437
|
+
/*
|
|
438
|
+
* Zap out DB node map
|
|
439
|
+
*/
|
|
440
|
+
pool_clear_node_to_be_sent(query_context);
|
|
441
|
+
|
|
442
|
+
/*
|
|
443
|
+
* If there is "NO LOAD BALANCE" comment, we send only to master node.
|
|
444
|
+
*/
|
|
445
|
+
/*
|
|
446
|
+
if (!strncasecmp(query, NO_LOAD_BALANCE, NO_LOAD_BALANCE_COMMENT_SZ))
|
|
447
|
+
{
|
|
448
|
+
pool_set_node_to_be_sent(query_context,
|
|
449
|
+
MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID);
|
|
450
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
451
|
+
{
|
|
452
|
+
if (query_context->where_to_send[i])
|
|
453
|
+
{
|
|
454
|
+
query_context->virtual_master_node_id = i;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
*/
|
|
461
|
+
|
|
462
|
+
/*
|
|
463
|
+
* In raw mode, we send only to master node. Simple enough.
|
|
464
|
+
*/
|
|
465
|
+
if (RAW_MODE)
|
|
466
|
+
{
|
|
467
|
+
pool_set_node_to_be_sent(query_context, REAL_MASTER_NODE_ID);
|
|
468
|
+
}
|
|
469
|
+
else if (MASTER_SLAVE && query_context->is_multi_statement)
|
|
470
|
+
{
|
|
471
|
+
/*
|
|
472
|
+
* If we are in master/slave mode and we have multi statement
|
|
473
|
+
* query, we should send it to primary server only. Otherwise
|
|
474
|
+
* it is possible to send a write query to standby servers
|
|
475
|
+
* because we only use the first element of the multi
|
|
476
|
+
* statement query and don't care about the rest. Typical
|
|
477
|
+
* situation where we are bugged by this is, "BEGIN;DELETE
|
|
478
|
+
* FROM table;END". Note that from pgpool-II 3.1.0
|
|
479
|
+
* transactional statements such as "BEGIN" is unconditionally
|
|
480
|
+
* sent to all nodes(see send_to_where() for more details).
|
|
481
|
+
* Someday we might be able to understand all part of multi
|
|
482
|
+
* statement queries, but until that day we need this band
|
|
483
|
+
* aid.
|
|
484
|
+
*/
|
|
485
|
+
if (query_context->is_multi_statement)
|
|
486
|
+
{
|
|
487
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
488
|
+
rewrite_mode = REWRITE_CLEAR;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else if (MASTER_SLAVE)
|
|
492
|
+
{
|
|
493
|
+
POOL_DEST dest;
|
|
494
|
+
POOL_MEMORY_POOL *old_context;
|
|
495
|
+
|
|
496
|
+
old_context = pool_memory_context_switch_to(query_context->memory_context);
|
|
497
|
+
dest = send_to_where(node, query);
|
|
498
|
+
pool_memory_context_switch_to(old_context);
|
|
499
|
+
|
|
500
|
+
pool_debug("send_to_where: %d query: %s", dest, query);
|
|
501
|
+
|
|
502
|
+
/* Should be sent to primary only? */
|
|
503
|
+
if (dest == POOL_PRIMARY)
|
|
504
|
+
{
|
|
505
|
+
pool_debug("pggw: send_to_where: POOL_PRIMARY\n");
|
|
506
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
507
|
+
}
|
|
508
|
+
/* Should be sent to both primary and standby? */
|
|
509
|
+
else if (dest == POOL_BOTH)
|
|
510
|
+
{
|
|
511
|
+
pool_debug("pggw: send_to_where: POOL_BOTH\n");
|
|
512
|
+
pool_setall_node_to_be_sent(query_context);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/*
|
|
516
|
+
* Ok, we might be able to load balance the SELECT query.
|
|
517
|
+
*/
|
|
518
|
+
else
|
|
519
|
+
{
|
|
520
|
+
if (pool_config->load_balance_mode &&
|
|
521
|
+
is_select_query(node, query) /*&&
|
|
522
|
+
MAJOR(backend) == PROTO_MAJOR_V3*/)
|
|
523
|
+
{
|
|
524
|
+
/*
|
|
525
|
+
* If (we are outside of an explicit transaction) OR
|
|
526
|
+
* (the transaction has not issued a write query yet, AND
|
|
527
|
+
* transaction isolation level is not SERIALIZABLE)
|
|
528
|
+
* we might be able to load balance.
|
|
529
|
+
*/
|
|
530
|
+
if (TSTATE(backend, PRIMARY_NODE_ID) == 'I' ||
|
|
531
|
+
(!pool_is_writing_transaction() &&
|
|
532
|
+
!pool_is_failed_transaction() &&
|
|
533
|
+
pool_get_transaction_isolation() != POOL_SERIALIZABLE))
|
|
534
|
+
{
|
|
535
|
+
BackendInfo *bkinfo = pool_get_node_info(session_context->load_balance_node_id);
|
|
536
|
+
|
|
537
|
+
/*
|
|
538
|
+
* Load balance if possible
|
|
539
|
+
*/
|
|
540
|
+
|
|
541
|
+
/*
|
|
542
|
+
* If replication delay is too much, we prefer to send to the primary.
|
|
543
|
+
*/
|
|
544
|
+
if (!strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP) &&
|
|
545
|
+
pool_config->delay_threshold &&
|
|
546
|
+
bkinfo->standby_delay > pool_config->delay_threshold)
|
|
547
|
+
{
|
|
548
|
+
pool_debug("pggw: send_to_where: replication delay\n");
|
|
549
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
550
|
+
rewrite_mode = REWRITE_ERROR;
|
|
551
|
+
rewrite_error_message = "unexpected replication delay";
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/*
|
|
555
|
+
* If a writing function call is used,
|
|
556
|
+
* we prefer to send to the primary.
|
|
557
|
+
*/
|
|
558
|
+
else if (pool_has_function_call(node))
|
|
559
|
+
{
|
|
560
|
+
pool_debug("pggw: send_to_where: writing function\n");
|
|
561
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/*
|
|
565
|
+
* If system catalog is used in the SELECT, we
|
|
566
|
+
* prefer to send to the primary. Example: SELECT
|
|
567
|
+
* * FROM pg_class WHERE relname = 't1'; Because
|
|
568
|
+
* 't1' is a constant, it's hard to recognize as
|
|
569
|
+
* table name. Most use case such query is
|
|
570
|
+
* against system catalog, and the table name can
|
|
571
|
+
* be a temporary table, it's best to query
|
|
572
|
+
* against primary system catalog.
|
|
573
|
+
* Please note that this test must be done *before*
|
|
574
|
+
* test using pool_has_temp_table.
|
|
575
|
+
*/
|
|
576
|
+
else if (pool_has_system_catalog(node))
|
|
577
|
+
{
|
|
578
|
+
pool_debug("pggw: send_to_where: system catalog\n");
|
|
579
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
580
|
+
rewrite_mode = REWRITE_SYSTEM_CATALOG;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/*
|
|
584
|
+
* If temporary table is used in the SELECT,
|
|
585
|
+
* we prefer to send to the primary.
|
|
586
|
+
*/
|
|
587
|
+
else if (pool_config->check_temp_table && pool_has_temp_table(node))
|
|
588
|
+
{
|
|
589
|
+
pool_debug("pggw: send_to_where: temporary table\n");
|
|
590
|
+
pool_set_node_to_be_sent(query_context,
|
|
591
|
+
session_context->load_balance_node_id);
|
|
592
|
+
rewrite_mode = REWRITE_PRESTO;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/*
|
|
596
|
+
* If unlogged table is used in the SELECT,
|
|
597
|
+
* we prefer to send to the primary.
|
|
598
|
+
*/
|
|
599
|
+
else if (pool_has_unlogged_table(node))
|
|
600
|
+
{
|
|
601
|
+
pool_debug("pggw: send_to_where: unlogged table\n");
|
|
602
|
+
pool_set_node_to_be_sent(query_context,
|
|
603
|
+
session_context->load_balance_node_id);
|
|
604
|
+
rewrite_mode = REWRITE_PRESTO;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/*
|
|
608
|
+
* If SELECT does not read data from tables,
|
|
609
|
+
* Presto can't handle it.
|
|
610
|
+
*/
|
|
611
|
+
else if (!pool_has_relation(node))
|
|
612
|
+
{
|
|
613
|
+
pool_debug("pggw: send_to_where: no relation\n");
|
|
614
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
615
|
+
rewrite_mode = REWRITE_SYSTEM_CATALOG;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
else
|
|
619
|
+
{
|
|
620
|
+
pool_debug("pggw: send_to_where: load balance\n");
|
|
621
|
+
pool_set_node_to_be_sent(query_context,
|
|
622
|
+
session_context->load_balance_node_id);
|
|
623
|
+
rewrite_mode = REWRITE_PRESTO;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
else
|
|
627
|
+
{
|
|
628
|
+
/* Send to the primary only */
|
|
629
|
+
pool_debug("pggw: send_to_where: invalid session state\n");
|
|
630
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
631
|
+
rewrite_mode = REWRITE_ERROR;
|
|
632
|
+
rewrite_error_message = "invalid session state";
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
else
|
|
636
|
+
{
|
|
637
|
+
/* Send to the primary only */
|
|
638
|
+
pool_debug("pggw: send_to_where: non-select\n");
|
|
639
|
+
pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
|
|
640
|
+
rewrite_mode = REWRITE_ERROR;
|
|
641
|
+
rewrite_error_message = "only SELECT is supported";
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
else if (REPLICATION || PARALLEL_MODE)
|
|
646
|
+
{
|
|
647
|
+
if (pool_config->load_balance_mode &&
|
|
648
|
+
is_select_query(node, query) &&
|
|
649
|
+
MAJOR(backend) == PROTO_MAJOR_V3)
|
|
650
|
+
{
|
|
651
|
+
/*
|
|
652
|
+
* If a writing function call is used or replicate_select is true,
|
|
653
|
+
* we prefer to send to all nodes.
|
|
654
|
+
*/
|
|
655
|
+
if (pool_has_function_call(node) || pool_config->replicate_select)
|
|
656
|
+
{
|
|
657
|
+
pool_setall_node_to_be_sent(query_context);
|
|
658
|
+
}
|
|
659
|
+
/*
|
|
660
|
+
* If (we are outside of an explicit transaction) OR
|
|
661
|
+
* (the transaction has not issued a write query yet, AND
|
|
662
|
+
* transaction isolation level is not SERIALIZABLE)
|
|
663
|
+
* we might be able to load balance.
|
|
664
|
+
*/
|
|
665
|
+
else if (TSTATE(backend, MASTER_NODE_ID) == 'I' ||
|
|
666
|
+
(!pool_is_writing_transaction() &&
|
|
667
|
+
!pool_is_failed_transaction() &&
|
|
668
|
+
pool_get_transaction_isolation() != POOL_SERIALIZABLE))
|
|
669
|
+
{
|
|
670
|
+
/* load balance */
|
|
671
|
+
pool_set_node_to_be_sent(query_context,
|
|
672
|
+
session_context->load_balance_node_id);
|
|
673
|
+
}
|
|
674
|
+
else
|
|
675
|
+
{
|
|
676
|
+
/* only send to master node */
|
|
677
|
+
pool_set_node_to_be_sent(query_context, REAL_MASTER_NODE_ID);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
else
|
|
681
|
+
{
|
|
682
|
+
if (is_select_query(node, query) && !pool_config->replicate_select &&
|
|
683
|
+
!pool_has_function_call(node))
|
|
684
|
+
{
|
|
685
|
+
/* only send to master node */
|
|
686
|
+
pool_set_node_to_be_sent(query_context, REAL_MASTER_NODE_ID);
|
|
687
|
+
}
|
|
688
|
+
else
|
|
689
|
+
{
|
|
690
|
+
/* send to all nodes */
|
|
691
|
+
pool_setall_node_to_be_sent(query_context);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else
|
|
696
|
+
{
|
|
697
|
+
pool_error("pool_where_to_send: unknown mode");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/*
|
|
702
|
+
* EXECUTE?
|
|
703
|
+
*/
|
|
704
|
+
if (IsA(node, ExecuteStmt))
|
|
705
|
+
{
|
|
706
|
+
POOL_SENT_MESSAGE *msg;
|
|
707
|
+
|
|
708
|
+
msg = pool_get_sent_message('Q', ((ExecuteStmt *)node)->name);
|
|
709
|
+
if (!msg)
|
|
710
|
+
msg = pool_get_sent_message('P', ((ExecuteStmt *)node)->name);
|
|
711
|
+
if (msg)
|
|
712
|
+
pool_copy_prep_where(msg->query_context->where_to_send,
|
|
713
|
+
query_context->where_to_send);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/*
|
|
717
|
+
* DEALLOCATE?
|
|
718
|
+
*/
|
|
719
|
+
else if (IsA(node, DeallocateStmt))
|
|
720
|
+
{
|
|
721
|
+
where_to_send_deallocate(query_context, node);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
725
|
+
{
|
|
726
|
+
if (query_context->where_to_send[i])
|
|
727
|
+
{
|
|
728
|
+
query_context->virtual_master_node_id = i;
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
switch (rewrite_mode) {
|
|
734
|
+
case REWRITE_CLEAR:
|
|
735
|
+
status = run_clear_query(session_context, query_context);
|
|
736
|
+
break;
|
|
737
|
+
|
|
738
|
+
case REWRITE_SYSTEM_CATALOG:
|
|
739
|
+
status = run_system_catalog_query(session_context, query_context);
|
|
740
|
+
break;
|
|
741
|
+
|
|
742
|
+
case REWRITE_PRESTO:
|
|
743
|
+
status = run_presto_query(session_context, query_context);
|
|
744
|
+
rewrite_presto_query(query_context);
|
|
745
|
+
break;
|
|
746
|
+
|
|
747
|
+
case REWRITE_ERROR:
|
|
748
|
+
rewrite_error_query(query_context, rewrite_error_message);
|
|
749
|
+
status = POOL_CONTINUE;
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
if (status != POOL_CONTINUE) {
|
|
754
|
+
pool_error("presto-pggw: query failed");
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
pool_debug("exec status: %d POOL_CONTINUE=%d\n", status, POOL_CONTINUE);
|
|
759
|
+
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/*
|
|
764
|
+
* Send simple query and wait for response
|
|
765
|
+
* send_type:
|
|
766
|
+
* -1: do not send this node_id
|
|
767
|
+
* 0: send to all nodes
|
|
768
|
+
* >0: send to this node_id
|
|
769
|
+
*/
|
|
770
|
+
POOL_STATUS pool_send_and_wait(POOL_QUERY_CONTEXT *query_context,
|
|
771
|
+
int send_type, int node_id)
|
|
772
|
+
{
|
|
773
|
+
POOL_SESSION_CONTEXT *session_context;
|
|
774
|
+
POOL_CONNECTION *frontend;
|
|
775
|
+
POOL_CONNECTION_POOL *backend;
|
|
776
|
+
bool is_commit;
|
|
777
|
+
bool is_begin_read_write;
|
|
778
|
+
int i;
|
|
779
|
+
int len;
|
|
780
|
+
char *string;
|
|
781
|
+
|
|
782
|
+
session_context = pool_get_session_context();
|
|
783
|
+
frontend = session_context->frontend;
|
|
784
|
+
backend = session_context->backend;
|
|
785
|
+
is_commit = is_commit_or_rollback_query(query_context->parse_tree);
|
|
786
|
+
is_begin_read_write = false;
|
|
787
|
+
len = 0;
|
|
788
|
+
string = NULL;
|
|
789
|
+
|
|
790
|
+
/*
|
|
791
|
+
* If the query is BEGIN READ WRITE or
|
|
792
|
+
* BEGIN ... SERIALIZABLE in master/slave mode,
|
|
793
|
+
* we send BEGIN to slaves/standbys instead.
|
|
794
|
+
* original_query which is BEGIN READ WRITE is sent to primary.
|
|
795
|
+
* rewritten_query which is BEGIN is sent to standbys.
|
|
796
|
+
*/
|
|
797
|
+
if (pool_need_to_treat_as_if_default_transaction(query_context))
|
|
798
|
+
{
|
|
799
|
+
is_begin_read_write = true;
|
|
800
|
+
}
|
|
801
|
+
else
|
|
802
|
+
{
|
|
803
|
+
if (query_context->rewritten_query)
|
|
804
|
+
{
|
|
805
|
+
len = query_context->rewritten_length;
|
|
806
|
+
string = query_context->rewritten_query;
|
|
807
|
+
}
|
|
808
|
+
else
|
|
809
|
+
{
|
|
810
|
+
len = query_context->original_length;
|
|
811
|
+
string = query_context->original_query;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/* Send query */
|
|
816
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
817
|
+
{
|
|
818
|
+
if (!VALID_BACKEND(i))
|
|
819
|
+
continue;
|
|
820
|
+
else if (send_type < 0 && i == node_id)
|
|
821
|
+
continue;
|
|
822
|
+
else if (send_type > 0 && i != node_id)
|
|
823
|
+
continue;
|
|
824
|
+
|
|
825
|
+
/*
|
|
826
|
+
* If in master/slave mode, we do not send COMMIT/ABORT to
|
|
827
|
+
* slaves/standbys if it's in I(idle) state.
|
|
828
|
+
*/
|
|
829
|
+
if (is_commit && MASTER_SLAVE && !IS_MASTER_NODE_ID(i) && TSTATE(backend, i) == 'I')
|
|
830
|
+
{
|
|
831
|
+
pool_unset_node_to_be_sent(query_context, i);
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/*
|
|
836
|
+
* If in reset context, we send COMMIT/ABORT to nodes those
|
|
837
|
+
* are not in I(idle) state. This will ensure that
|
|
838
|
+
* transactions are closed.
|
|
839
|
+
*/
|
|
840
|
+
if (is_commit && session_context->reset_context && TSTATE(backend, i) == 'I')
|
|
841
|
+
{
|
|
842
|
+
pool_unset_node_to_be_sent(query_context, i);
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (is_begin_read_write)
|
|
847
|
+
{
|
|
848
|
+
if (REAL_PRIMARY_NODE_ID == i)
|
|
849
|
+
{
|
|
850
|
+
len = query_context->original_length;
|
|
851
|
+
string = query_context->original_query;
|
|
852
|
+
}
|
|
853
|
+
else
|
|
854
|
+
{
|
|
855
|
+
len = query_context->rewritten_length;
|
|
856
|
+
string = query_context->rewritten_query;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
per_node_statement_log(backend, i, string);
|
|
861
|
+
|
|
862
|
+
if (send_simplequery_message(CONNECTION(backend, i), len, string, MAJOR(backend)) != POOL_CONTINUE)
|
|
863
|
+
{
|
|
864
|
+
return POOL_END;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/* Wait for response */
|
|
869
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
870
|
+
{
|
|
871
|
+
if (!VALID_BACKEND(i))
|
|
872
|
+
continue;
|
|
873
|
+
else if (send_type < 0 && i == node_id)
|
|
874
|
+
continue;
|
|
875
|
+
else if (send_type > 0 && i != node_id)
|
|
876
|
+
continue;
|
|
877
|
+
|
|
878
|
+
#ifdef NOT_USED
|
|
879
|
+
/*
|
|
880
|
+
* If in master/slave mode, we do not send COMMIT/ABORT to
|
|
881
|
+
* slaves/standbys if it's in I(idle) state.
|
|
882
|
+
*/
|
|
883
|
+
if (is_commit && MASTER_SLAVE && !IS_MASTER_NODE_ID(i) && TSTATE(backend, i) == 'I')
|
|
884
|
+
{
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
#endif
|
|
888
|
+
|
|
889
|
+
if (is_begin_read_write)
|
|
890
|
+
{
|
|
891
|
+
if(REAL_PRIMARY_NODE_ID == i)
|
|
892
|
+
string = query_context->original_query;
|
|
893
|
+
else
|
|
894
|
+
string = query_context->rewritten_query;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
if (wait_for_query_response(frontend, CONNECTION(backend, i), MAJOR(backend)) != POOL_CONTINUE)
|
|
898
|
+
{
|
|
899
|
+
/* Cancel current transaction */
|
|
900
|
+
CancelPacket cancel_packet;
|
|
901
|
+
|
|
902
|
+
cancel_packet.protoVersion = htonl(PROTO_CANCEL);
|
|
903
|
+
cancel_packet.pid = MASTER_CONNECTION(backend)->pid;
|
|
904
|
+
cancel_packet.key= MASTER_CONNECTION(backend)->key;
|
|
905
|
+
cancel_request(&cancel_packet);
|
|
906
|
+
|
|
907
|
+
return POOL_END;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/*
|
|
911
|
+
* Check if some error detected. If so, emit
|
|
912
|
+
* log. This is useful when invalid encoding error
|
|
913
|
+
* occurs. In this case, PostgreSQL does not report
|
|
914
|
+
* what statement caused that error and make users
|
|
915
|
+
* confused.
|
|
916
|
+
*/
|
|
917
|
+
per_node_error_log(backend, i, string, "pool_send_and_wait: Error or notice message from backend: ", true);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
return POOL_CONTINUE;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/*
|
|
924
|
+
* Send extended query and wait for response
|
|
925
|
+
* send_type:
|
|
926
|
+
* -1: do not send this node_id
|
|
927
|
+
* 0: send to all nodes
|
|
928
|
+
* >0: send to this node_id
|
|
929
|
+
*/
|
|
930
|
+
POOL_STATUS pool_extended_send_and_wait(POOL_QUERY_CONTEXT *query_context,
|
|
931
|
+
char *kind, int len, char *contents,
|
|
932
|
+
int send_type, int node_id)
|
|
933
|
+
{
|
|
934
|
+
POOL_SESSION_CONTEXT *session_context;
|
|
935
|
+
POOL_CONNECTION *frontend;
|
|
936
|
+
POOL_CONNECTION_POOL *backend;
|
|
937
|
+
bool is_commit;
|
|
938
|
+
bool is_begin_read_write;
|
|
939
|
+
int i;
|
|
940
|
+
int str_len;
|
|
941
|
+
int rewritten_len;
|
|
942
|
+
char *str;
|
|
943
|
+
char *rewritten_begin;
|
|
944
|
+
|
|
945
|
+
session_context = pool_get_session_context();
|
|
946
|
+
frontend = session_context->frontend;
|
|
947
|
+
backend = session_context->backend;
|
|
948
|
+
is_commit = is_commit_or_rollback_query(query_context->parse_tree);
|
|
949
|
+
is_begin_read_write = false;
|
|
950
|
+
str_len = 0;
|
|
951
|
+
rewritten_len = 0;
|
|
952
|
+
str = NULL;
|
|
953
|
+
rewritten_begin = NULL;
|
|
954
|
+
|
|
955
|
+
/*
|
|
956
|
+
* If the query is BEGIN READ WRITE or
|
|
957
|
+
* BEGIN ... SERIALIZABLE in master/slave mode,
|
|
958
|
+
* we send BEGIN to slaves/standbys instead.
|
|
959
|
+
* original_query which is BEGIN READ WRITE is sent to primary.
|
|
960
|
+
* rewritten_query which is BEGIN is sent to standbys.
|
|
961
|
+
*/
|
|
962
|
+
if (pool_need_to_treat_as_if_default_transaction(query_context))
|
|
963
|
+
{
|
|
964
|
+
is_begin_read_write = true;
|
|
965
|
+
|
|
966
|
+
if (*kind == 'P')
|
|
967
|
+
{
|
|
968
|
+
rewritten_begin = remove_read_write(len, contents, &rewritten_len);
|
|
969
|
+
if (rewritten_begin == NULL)
|
|
970
|
+
return POOL_END;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (!rewritten_begin)
|
|
975
|
+
{
|
|
976
|
+
str_len = len;
|
|
977
|
+
str = contents;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/* Send query */
|
|
981
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
982
|
+
{
|
|
983
|
+
if (!VALID_BACKEND(i))
|
|
984
|
+
continue;
|
|
985
|
+
else if (send_type < 0 && i == node_id)
|
|
986
|
+
continue;
|
|
987
|
+
else if (send_type > 0 && i != node_id)
|
|
988
|
+
continue;
|
|
989
|
+
|
|
990
|
+
/*
|
|
991
|
+
* If in reset context, we send COMMIT/ABORT to nodes those
|
|
992
|
+
* are not in I(idle) state. This will ensure that
|
|
993
|
+
* transactions are closed.
|
|
994
|
+
*/
|
|
995
|
+
if (is_commit && session_context->reset_context && TSTATE(backend, i) == 'I')
|
|
996
|
+
{
|
|
997
|
+
pool_unset_node_to_be_sent(query_context, i);
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
if (rewritten_begin)
|
|
1002
|
+
{
|
|
1003
|
+
if (REAL_PRIMARY_NODE_ID == i)
|
|
1004
|
+
{
|
|
1005
|
+
str = contents;
|
|
1006
|
+
str_len = len;
|
|
1007
|
+
}
|
|
1008
|
+
else
|
|
1009
|
+
{
|
|
1010
|
+
str = rewritten_begin;
|
|
1011
|
+
str_len = rewritten_len;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
if (pool_config->log_per_node_statement)
|
|
1016
|
+
{
|
|
1017
|
+
char msgbuf[QUERY_STRING_BUFFER_LEN];
|
|
1018
|
+
char *stmt;
|
|
1019
|
+
|
|
1020
|
+
if (*kind == 'P' || *kind == 'E')
|
|
1021
|
+
{
|
|
1022
|
+
if (query_context->rewritten_query)
|
|
1023
|
+
{
|
|
1024
|
+
if (is_begin_read_write)
|
|
1025
|
+
{
|
|
1026
|
+
if (REAL_PRIMARY_NODE_ID == i)
|
|
1027
|
+
stmt = query_context->original_query;
|
|
1028
|
+
else
|
|
1029
|
+
stmt = query_context->rewritten_query;
|
|
1030
|
+
}
|
|
1031
|
+
else
|
|
1032
|
+
{
|
|
1033
|
+
stmt = query_context->rewritten_query;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
else
|
|
1037
|
+
{
|
|
1038
|
+
stmt = query_context->original_query;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if (*kind == 'P')
|
|
1042
|
+
snprintf(msgbuf, sizeof(msgbuf), "Parse: %s", stmt);
|
|
1043
|
+
else
|
|
1044
|
+
snprintf(msgbuf, sizeof(msgbuf), "Execute: %s", stmt);
|
|
1045
|
+
}
|
|
1046
|
+
else
|
|
1047
|
+
{
|
|
1048
|
+
snprintf(msgbuf, sizeof(msgbuf), "%c message", *kind);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
per_node_statement_log(backend, i, msgbuf);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (send_extended_protocol_message(backend, i, kind, str_len, str) != POOL_CONTINUE)
|
|
1055
|
+
{
|
|
1056
|
+
free(rewritten_begin);
|
|
1057
|
+
return POOL_END;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
if (!is_begin_read_write)
|
|
1062
|
+
{
|
|
1063
|
+
if (query_context->rewritten_query)
|
|
1064
|
+
str = query_context->rewritten_query;
|
|
1065
|
+
else
|
|
1066
|
+
str = query_context->original_query;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/* Wait for response */
|
|
1070
|
+
for (i=0;i<NUM_BACKENDS;i++)
|
|
1071
|
+
{
|
|
1072
|
+
if (!VALID_BACKEND(i))
|
|
1073
|
+
continue;
|
|
1074
|
+
else if (send_type < 0 && i == node_id)
|
|
1075
|
+
continue;
|
|
1076
|
+
else if (send_type > 0 && i != node_id)
|
|
1077
|
+
continue;
|
|
1078
|
+
|
|
1079
|
+
/*
|
|
1080
|
+
* If in master/slave mode, we do not send COMMIT/ABORT to
|
|
1081
|
+
* slaves/standbys if it's in I(idle) state.
|
|
1082
|
+
*/
|
|
1083
|
+
if (is_commit && MASTER_SLAVE && !IS_MASTER_NODE_ID(i) && TSTATE(backend, i) == 'I')
|
|
1084
|
+
{
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
if (is_begin_read_write)
|
|
1089
|
+
{
|
|
1090
|
+
if (REAL_PRIMARY_NODE_ID == i)
|
|
1091
|
+
str = query_context->original_query;
|
|
1092
|
+
else
|
|
1093
|
+
str = query_context->rewritten_query;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
if (wait_for_query_response(frontend, CONNECTION(backend, i), MAJOR(backend)) != POOL_CONTINUE)
|
|
1097
|
+
{
|
|
1098
|
+
/* Cancel current transaction */
|
|
1099
|
+
CancelPacket cancel_packet;
|
|
1100
|
+
|
|
1101
|
+
cancel_packet.protoVersion = htonl(PROTO_CANCEL);
|
|
1102
|
+
cancel_packet.pid = MASTER_CONNECTION(backend)->pid;
|
|
1103
|
+
cancel_packet.key= MASTER_CONNECTION(backend)->key;
|
|
1104
|
+
cancel_request(&cancel_packet);
|
|
1105
|
+
|
|
1106
|
+
free(rewritten_begin);
|
|
1107
|
+
return POOL_END;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/*
|
|
1111
|
+
* Check if some error detected. If so, emit
|
|
1112
|
+
* log. This is useful when invalid encoding error
|
|
1113
|
+
* occurs. In this case, PostgreSQL does not report
|
|
1114
|
+
* what statement caused that error and make users
|
|
1115
|
+
* confused.
|
|
1116
|
+
*/
|
|
1117
|
+
per_node_error_log(backend, i, str, "pool_send_and_wait: Error or notice message from backend: ", true);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
free(rewritten_begin);
|
|
1121
|
+
return POOL_CONTINUE;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/*
|
|
1125
|
+
* From syntactically analysis decide the statement to be sent to the
|
|
1126
|
+
* primary, the standby or either or both in master/slave+HR/SR mode.
|
|
1127
|
+
*/
|
|
1128
|
+
static POOL_DEST send_to_where(Node *node, char *query)
|
|
1129
|
+
{
|
|
1130
|
+
/* From storage/lock.h */
|
|
1131
|
+
#define NoLock 0
|
|
1132
|
+
#define AccessShareLock 1 /* SELECT */
|
|
1133
|
+
#define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */
|
|
1134
|
+
#define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */
|
|
1135
|
+
#define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL),ANALYZE, CREATE
|
|
1136
|
+
* INDEX CONCURRENTLY */
|
|
1137
|
+
#define ShareLock 5 /* CREATE INDEX (WITHOUT CONCURRENTLY) */
|
|
1138
|
+
#define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW
|
|
1139
|
+
* SHARE */
|
|
1140
|
+
#define ExclusiveLock 7 /* blocks ROW SHARE/SELECT...FOR
|
|
1141
|
+
* UPDATE */
|
|
1142
|
+
#define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM
|
|
1143
|
+
* FULL, and unqualified LOCK TABLE */
|
|
1144
|
+
|
|
1145
|
+
/* From 9.0 include/nodes/node.h */
|
|
1146
|
+
static NodeTag nodemap[] = {
|
|
1147
|
+
T_PlannedStmt,
|
|
1148
|
+
T_InsertStmt,
|
|
1149
|
+
T_DeleteStmt,
|
|
1150
|
+
T_UpdateStmt,
|
|
1151
|
+
T_SelectStmt,
|
|
1152
|
+
T_AlterTableStmt,
|
|
1153
|
+
T_AlterTableCmd,
|
|
1154
|
+
T_AlterDomainStmt,
|
|
1155
|
+
T_SetOperationStmt,
|
|
1156
|
+
T_GrantStmt,
|
|
1157
|
+
T_GrantRoleStmt,
|
|
1158
|
+
/*
|
|
1159
|
+
T_AlterDefaultPrivilegesStmt, Our parser does not support yet
|
|
1160
|
+
*/
|
|
1161
|
+
T_ClosePortalStmt,
|
|
1162
|
+
T_ClusterStmt,
|
|
1163
|
+
T_CopyStmt,
|
|
1164
|
+
T_CreateStmt, /* CREATE TABLE */
|
|
1165
|
+
T_DefineStmt, /* CREATE AGGREGATE, OPERATOR, TYPE */
|
|
1166
|
+
T_DropStmt, /* DROP TABLE etc. */
|
|
1167
|
+
T_TruncateStmt,
|
|
1168
|
+
T_CommentStmt,
|
|
1169
|
+
T_FetchStmt,
|
|
1170
|
+
T_IndexStmt, /* CREATE INDEX */
|
|
1171
|
+
T_CreateFunctionStmt,
|
|
1172
|
+
T_AlterFunctionStmt,
|
|
1173
|
+
/*
|
|
1174
|
+
T_DoStmt, Our parser does not support yet
|
|
1175
|
+
*/
|
|
1176
|
+
T_RenameStmt, /* ALTER AGGREGATE etc. */
|
|
1177
|
+
T_RuleStmt, /* CREATE RULE */
|
|
1178
|
+
T_NotifyStmt,
|
|
1179
|
+
T_ListenStmt,
|
|
1180
|
+
T_UnlistenStmt,
|
|
1181
|
+
T_TransactionStmt,
|
|
1182
|
+
T_ViewStmt, /* CREATE VIEW */
|
|
1183
|
+
T_LoadStmt,
|
|
1184
|
+
T_CreateDomainStmt,
|
|
1185
|
+
T_CreatedbStmt,
|
|
1186
|
+
T_DropdbStmt,
|
|
1187
|
+
T_VacuumStmt,
|
|
1188
|
+
T_ExplainStmt,
|
|
1189
|
+
T_CreateSeqStmt,
|
|
1190
|
+
T_AlterSeqStmt,
|
|
1191
|
+
T_VariableSetStmt, /* SET */
|
|
1192
|
+
T_VariableShowStmt,
|
|
1193
|
+
T_DiscardStmt,
|
|
1194
|
+
T_CreateTrigStmt,
|
|
1195
|
+
T_CreatePLangStmt,
|
|
1196
|
+
T_CreateRoleStmt,
|
|
1197
|
+
T_AlterRoleStmt,
|
|
1198
|
+
T_DropRoleStmt,
|
|
1199
|
+
T_LockStmt,
|
|
1200
|
+
T_ConstraintsSetStmt,
|
|
1201
|
+
T_ReindexStmt,
|
|
1202
|
+
T_CheckPointStmt,
|
|
1203
|
+
T_CreateSchemaStmt,
|
|
1204
|
+
T_AlterDatabaseStmt,
|
|
1205
|
+
T_AlterDatabaseSetStmt,
|
|
1206
|
+
T_AlterRoleSetStmt,
|
|
1207
|
+
T_CreateConversionStmt,
|
|
1208
|
+
T_CreateCastStmt,
|
|
1209
|
+
T_CreateOpClassStmt,
|
|
1210
|
+
T_CreateOpFamilyStmt,
|
|
1211
|
+
T_AlterOpFamilyStmt,
|
|
1212
|
+
T_PrepareStmt,
|
|
1213
|
+
T_ExecuteStmt,
|
|
1214
|
+
T_DeallocateStmt, /* DEALLOCATE */
|
|
1215
|
+
T_DeclareCursorStmt, /* DECLARE */
|
|
1216
|
+
T_CreateTableSpaceStmt,
|
|
1217
|
+
T_DropTableSpaceStmt,
|
|
1218
|
+
T_AlterObjectSchemaStmt,
|
|
1219
|
+
T_AlterOwnerStmt,
|
|
1220
|
+
T_DropOwnedStmt,
|
|
1221
|
+
T_ReassignOwnedStmt,
|
|
1222
|
+
T_CompositeTypeStmt, /* CREATE TYPE */
|
|
1223
|
+
T_CreateEnumStmt,
|
|
1224
|
+
T_AlterTSDictionaryStmt,
|
|
1225
|
+
T_AlterTSConfigurationStmt,
|
|
1226
|
+
T_CreateFdwStmt,
|
|
1227
|
+
T_AlterFdwStmt,
|
|
1228
|
+
T_CreateForeignServerStmt,
|
|
1229
|
+
T_AlterForeignServerStmt,
|
|
1230
|
+
T_CreateUserMappingStmt,
|
|
1231
|
+
T_AlterUserMappingStmt,
|
|
1232
|
+
T_DropUserMappingStmt,
|
|
1233
|
+
/*
|
|
1234
|
+
T_AlterTableSpaceOptionsStmt, Our parser does not support yet
|
|
1235
|
+
*/
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
if (bsearch(&nodeTag(node), nodemap, sizeof(nodemap)/sizeof(nodemap[0]),
|
|
1239
|
+
sizeof(NodeTag), compare) != NULL)
|
|
1240
|
+
{
|
|
1241
|
+
/*
|
|
1242
|
+
* SELECT INTO
|
|
1243
|
+
* SELECT FOR SHARE or UPDATE
|
|
1244
|
+
*/
|
|
1245
|
+
if (IsA(node, SelectStmt))
|
|
1246
|
+
{
|
|
1247
|
+
/* SELECT INTO or SELECT FOR SHARE or UPDATE ? */
|
|
1248
|
+
if (pool_has_insertinto_or_locking_clause(node))
|
|
1249
|
+
return POOL_PRIMARY;
|
|
1250
|
+
|
|
1251
|
+
return POOL_EITHER;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/*
|
|
1255
|
+
* COPY FROM
|
|
1256
|
+
*/
|
|
1257
|
+
else if (IsA(node, CopyStmt))
|
|
1258
|
+
{
|
|
1259
|
+
return (((CopyStmt *)node)->is_from)?POOL_PRIMARY:POOL_EITHER;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/*
|
|
1263
|
+
* LOCK
|
|
1264
|
+
*/
|
|
1265
|
+
else if (IsA(node, LockStmt))
|
|
1266
|
+
{
|
|
1267
|
+
return (((LockStmt *)node)->mode >= RowExclusiveLock)?POOL_PRIMARY:POOL_BOTH;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/*
|
|
1271
|
+
* Transaction commands
|
|
1272
|
+
*/
|
|
1273
|
+
else if (IsA(node, TransactionStmt))
|
|
1274
|
+
{
|
|
1275
|
+
/*
|
|
1276
|
+
* Check "BEGIN READ WRITE" "START TRANSACTION READ WRITE"
|
|
1277
|
+
*/
|
|
1278
|
+
if (is_start_transaction_query(node))
|
|
1279
|
+
{
|
|
1280
|
+
/* But actually, we send BEGIN to standby if it's
|
|
1281
|
+
BEGIN READ WRITE or START TRANSACTION READ WRITE */
|
|
1282
|
+
if (is_read_write((TransactionStmt *)node))
|
|
1283
|
+
return POOL_BOTH;
|
|
1284
|
+
/* Other TRANSACTION start commands are sent to both primary
|
|
1285
|
+
and standby */
|
|
1286
|
+
else
|
|
1287
|
+
return POOL_BOTH;
|
|
1288
|
+
}
|
|
1289
|
+
/* SAVEPOINT related commands are sent to both primary and standby */
|
|
1290
|
+
else if (is_savepoint_query(node))
|
|
1291
|
+
return POOL_BOTH;
|
|
1292
|
+
/*
|
|
1293
|
+
* 2PC commands
|
|
1294
|
+
*/
|
|
1295
|
+
else if (is_2pc_transaction_query(node))
|
|
1296
|
+
return POOL_PRIMARY;
|
|
1297
|
+
else
|
|
1298
|
+
/* COMMIT etc. */
|
|
1299
|
+
return POOL_BOTH;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
/*
|
|
1303
|
+
* SET
|
|
1304
|
+
*/
|
|
1305
|
+
else if (IsA(node, VariableSetStmt))
|
|
1306
|
+
{
|
|
1307
|
+
ListCell *list_item;
|
|
1308
|
+
bool ret = POOL_BOTH;
|
|
1309
|
+
|
|
1310
|
+
/*
|
|
1311
|
+
* SET transaction_read_only TO off
|
|
1312
|
+
*/
|
|
1313
|
+
if (((VariableSetStmt *)node)->kind == VAR_SET_VALUE &&
|
|
1314
|
+
!strcmp(((VariableSetStmt *)node)->name, "transaction_read_only"))
|
|
1315
|
+
{
|
|
1316
|
+
List *options = ((VariableSetStmt *)node)->args;
|
|
1317
|
+
foreach(list_item, options)
|
|
1318
|
+
{
|
|
1319
|
+
A_Const *v = (A_Const *)lfirst(list_item);
|
|
1320
|
+
|
|
1321
|
+
switch (v->val.type)
|
|
1322
|
+
{
|
|
1323
|
+
case T_String:
|
|
1324
|
+
if (!strcasecmp(v->val.val.str, "off") ||
|
|
1325
|
+
!strcasecmp(v->val.val.str, "f") ||
|
|
1326
|
+
!strcasecmp(v->val.val.str, "false"))
|
|
1327
|
+
ret = POOL_PRIMARY;
|
|
1328
|
+
break;
|
|
1329
|
+
case T_Integer:
|
|
1330
|
+
if (v->val.val.ival)
|
|
1331
|
+
ret = POOL_PRIMARY;
|
|
1332
|
+
default:
|
|
1333
|
+
break;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
return ret;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/* SET TRANSACTION ISOLATION LEVEL SERIALIZABLE or
|
|
1340
|
+
* SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE or
|
|
1341
|
+
* SET transaction_isolation TO 'serializable'
|
|
1342
|
+
* SET default_transaction_isolation TO 'serializable'
|
|
1343
|
+
*/
|
|
1344
|
+
else if (is_set_transaction_serializable(node))
|
|
1345
|
+
{
|
|
1346
|
+
return POOL_PRIMARY;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/*
|
|
1350
|
+
* Check "SET TRANSACTION READ WRITE" "SET SESSION
|
|
1351
|
+
* CHARACTERISTICS AS TRANSACTION READ WRITE"
|
|
1352
|
+
*/
|
|
1353
|
+
else if (((VariableSetStmt *)node)->kind == VAR_SET_MULTI &&
|
|
1354
|
+
(!strcmp(((VariableSetStmt *)node)->name, "TRANSACTION") ||
|
|
1355
|
+
!strcmp(((VariableSetStmt *)node)->name, "SESSION CHARACTERISTICS")))
|
|
1356
|
+
{
|
|
1357
|
+
List *options = ((VariableSetStmt *)node)->args;
|
|
1358
|
+
foreach(list_item, options)
|
|
1359
|
+
{
|
|
1360
|
+
DefElem *opt = (DefElem *) lfirst(list_item);
|
|
1361
|
+
|
|
1362
|
+
if (!strcmp("transaction_read_only", opt->defname))
|
|
1363
|
+
{
|
|
1364
|
+
bool read_only;
|
|
1365
|
+
|
|
1366
|
+
read_only = ((A_Const *)opt->arg)->val.val.ival;
|
|
1367
|
+
if (!read_only)
|
|
1368
|
+
return POOL_PRIMARY;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
return POOL_BOTH;
|
|
1372
|
+
}
|
|
1373
|
+
else
|
|
1374
|
+
{
|
|
1375
|
+
/*
|
|
1376
|
+
* All other SET command sent to both primary and
|
|
1377
|
+
* standby
|
|
1378
|
+
*/
|
|
1379
|
+
return POOL_BOTH;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/*
|
|
1384
|
+
* DISCARD
|
|
1385
|
+
*/
|
|
1386
|
+
else if (IsA(node, DiscardStmt))
|
|
1387
|
+
{
|
|
1388
|
+
return POOL_BOTH;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
/*
|
|
1392
|
+
* PREPARE
|
|
1393
|
+
*/
|
|
1394
|
+
else if (IsA(node, PrepareStmt))
|
|
1395
|
+
{
|
|
1396
|
+
PrepareStmt *prepare_statement = (PrepareStmt *)node;
|
|
1397
|
+
|
|
1398
|
+
char *string = nodeToString(prepare_statement->query);
|
|
1399
|
+
|
|
1400
|
+
/* Note that this is a recursive call */
|
|
1401
|
+
return send_to_where((Node *)(prepare_statement->query), string);
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
/*
|
|
1405
|
+
* EXECUTE
|
|
1406
|
+
*/
|
|
1407
|
+
else if (IsA(node, ExecuteStmt))
|
|
1408
|
+
{
|
|
1409
|
+
/* This is temporary decision. where_to_send will inherit
|
|
1410
|
+
* same destination AS PREPARE.
|
|
1411
|
+
*/
|
|
1412
|
+
return POOL_PRIMARY;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
/*
|
|
1416
|
+
* DEALLOCATE
|
|
1417
|
+
*/
|
|
1418
|
+
else if (IsA(node, DeallocateStmt))
|
|
1419
|
+
{
|
|
1420
|
+
/* This is temporary decision. where_to_send will inherit
|
|
1421
|
+
* same destination AS PREPARE.
|
|
1422
|
+
*/
|
|
1423
|
+
return POOL_PRIMARY;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
/*
|
|
1427
|
+
* Other statements are sent to primary
|
|
1428
|
+
*/
|
|
1429
|
+
return POOL_PRIMARY;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
/*
|
|
1433
|
+
* All unknown statements are sent to primary
|
|
1434
|
+
*/
|
|
1435
|
+
return POOL_PRIMARY;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
static
|
|
1439
|
+
void where_to_send_deallocate(POOL_QUERY_CONTEXT *query_context, Node *node)
|
|
1440
|
+
{
|
|
1441
|
+
DeallocateStmt *d = (DeallocateStmt *)node;
|
|
1442
|
+
POOL_SENT_MESSAGE *msg;
|
|
1443
|
+
|
|
1444
|
+
/* DEALLOCATE ALL? */
|
|
1445
|
+
if (d->name == NULL)
|
|
1446
|
+
{
|
|
1447
|
+
pool_setall_node_to_be_sent(query_context);
|
|
1448
|
+
}
|
|
1449
|
+
else
|
|
1450
|
+
{
|
|
1451
|
+
msg = pool_get_sent_message('Q', d->name);
|
|
1452
|
+
if (!msg)
|
|
1453
|
+
msg = pool_get_sent_message('P', d->name);
|
|
1454
|
+
if (msg)
|
|
1455
|
+
{
|
|
1456
|
+
/* Inherit same map from PREPARE or PARSE */
|
|
1457
|
+
pool_copy_prep_where(msg->query_context->where_to_send,
|
|
1458
|
+
query_context->where_to_send);
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
/* prepared statement was not found */
|
|
1462
|
+
pool_setall_node_to_be_sent(query_context);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
/*
|
|
1467
|
+
* Returns parse tree for current query.
|
|
1468
|
+
* Precondition: the query is in progress state.
|
|
1469
|
+
*/
|
|
1470
|
+
Node *pool_get_parse_tree(void)
|
|
1471
|
+
{
|
|
1472
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1473
|
+
|
|
1474
|
+
sc = pool_get_session_context();
|
|
1475
|
+
if (!sc)
|
|
1476
|
+
return NULL;
|
|
1477
|
+
|
|
1478
|
+
if (pool_is_query_in_progress() && sc->query_context)
|
|
1479
|
+
{
|
|
1480
|
+
return sc->query_context->parse_tree;
|
|
1481
|
+
}
|
|
1482
|
+
return NULL;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
/*
|
|
1486
|
+
* Returns raw query string for current query.
|
|
1487
|
+
* Precondition: the query is in progress state.
|
|
1488
|
+
*/
|
|
1489
|
+
char *pool_get_query_string(void)
|
|
1490
|
+
{
|
|
1491
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1492
|
+
|
|
1493
|
+
sc = pool_get_session_context();
|
|
1494
|
+
if (!sc)
|
|
1495
|
+
return NULL;
|
|
1496
|
+
|
|
1497
|
+
if (pool_is_query_in_progress() && sc->query_context)
|
|
1498
|
+
{
|
|
1499
|
+
return sc->query_context->original_query;
|
|
1500
|
+
}
|
|
1501
|
+
return NULL;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/*
|
|
1505
|
+
* Return true if the query is:
|
|
1506
|
+
* SET TRANSACTION ISOLATION LEVEL SERIALIZABLE or
|
|
1507
|
+
* SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE or
|
|
1508
|
+
* SET transaction_isolation TO 'serializable'
|
|
1509
|
+
* SET default_transaction_isolation TO 'serializable'
|
|
1510
|
+
*/
|
|
1511
|
+
bool is_set_transaction_serializable(Node *node)
|
|
1512
|
+
{
|
|
1513
|
+
ListCell *list_item;
|
|
1514
|
+
|
|
1515
|
+
if (!IsA(node, VariableSetStmt))
|
|
1516
|
+
return false;
|
|
1517
|
+
|
|
1518
|
+
if (((VariableSetStmt *)node)->kind == VAR_SET_VALUE &&
|
|
1519
|
+
!strcmp(((VariableSetStmt *)node)->name, "transaction_isolation"))
|
|
1520
|
+
{
|
|
1521
|
+
List *options = ((VariableSetStmt *)node)->args;
|
|
1522
|
+
foreach(list_item, options)
|
|
1523
|
+
{
|
|
1524
|
+
A_Const *v = (A_Const *)lfirst(list_item);
|
|
1525
|
+
|
|
1526
|
+
switch (v->val.type)
|
|
1527
|
+
{
|
|
1528
|
+
case T_String:
|
|
1529
|
+
if (!strcasecmp(v->val.val.str, "serializable"))
|
|
1530
|
+
return true;
|
|
1531
|
+
break;
|
|
1532
|
+
default:
|
|
1533
|
+
break;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return false;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
else if (((VariableSetStmt *)node)->kind == VAR_SET_MULTI &&
|
|
1540
|
+
(!strcmp(((VariableSetStmt *)node)->name, "TRANSACTION") ||
|
|
1541
|
+
!strcmp(((VariableSetStmt *)node)->name, "SESSION CHARACTERISTICS")))
|
|
1542
|
+
{
|
|
1543
|
+
List *options = ((VariableSetStmt *)node)->args;
|
|
1544
|
+
foreach(list_item, options)
|
|
1545
|
+
{
|
|
1546
|
+
DefElem *opt = (DefElem *) lfirst(list_item);
|
|
1547
|
+
if (!strcmp("transaction_isolation", opt->defname) ||
|
|
1548
|
+
!strcmp("default_transaction_isolation", opt->defname))
|
|
1549
|
+
{
|
|
1550
|
+
A_Const *v = (A_Const *)opt->arg;
|
|
1551
|
+
|
|
1552
|
+
if (!strcasecmp(v->val.val.str, "serializable"))
|
|
1553
|
+
return true;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return false;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/*
|
|
1561
|
+
* Returns true if SQL is transaction starting command (START
|
|
1562
|
+
* TRANSACTION or BEGIN)
|
|
1563
|
+
*/
|
|
1564
|
+
bool is_start_transaction_query(Node *node)
|
|
1565
|
+
{
|
|
1566
|
+
TransactionStmt *stmt;
|
|
1567
|
+
|
|
1568
|
+
if (node == NULL || !IsA(node, TransactionStmt))
|
|
1569
|
+
return false;
|
|
1570
|
+
|
|
1571
|
+
stmt = (TransactionStmt *)node;
|
|
1572
|
+
return stmt->kind == TRANS_STMT_START || stmt->kind == TRANS_STMT_BEGIN;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
/*
|
|
1576
|
+
* Return true if start transaction query with "READ WRITE" option.
|
|
1577
|
+
*/
|
|
1578
|
+
bool is_read_write(TransactionStmt *node)
|
|
1579
|
+
{
|
|
1580
|
+
ListCell *list_item;
|
|
1581
|
+
|
|
1582
|
+
List *options = node->options;
|
|
1583
|
+
foreach(list_item, options)
|
|
1584
|
+
{
|
|
1585
|
+
DefElem *opt = (DefElem *) lfirst(list_item);
|
|
1586
|
+
|
|
1587
|
+
if (!strcmp("transaction_read_only", opt->defname))
|
|
1588
|
+
{
|
|
1589
|
+
bool read_only;
|
|
1590
|
+
|
|
1591
|
+
read_only = ((A_Const *)opt->arg)->val.val.ival;
|
|
1592
|
+
if (read_only)
|
|
1593
|
+
return false; /* TRANSACTION READ ONLY */
|
|
1594
|
+
else
|
|
1595
|
+
/*
|
|
1596
|
+
* TRANSACTION READ WRITE specified. This sounds a little bit strange,
|
|
1597
|
+
* but actually the parse code works in the way.
|
|
1598
|
+
*/
|
|
1599
|
+
return true;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/*
|
|
1604
|
+
* No TRANSACTION READ ONLY/READ WRITE clause specified.
|
|
1605
|
+
*/
|
|
1606
|
+
return false;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
/*
|
|
1610
|
+
* Return true if start transaction query with "SERIALIZABLE" option.
|
|
1611
|
+
*/
|
|
1612
|
+
bool is_serializable(TransactionStmt *node)
|
|
1613
|
+
{
|
|
1614
|
+
ListCell *list_item;
|
|
1615
|
+
|
|
1616
|
+
List *options = node->options;
|
|
1617
|
+
foreach(list_item, options)
|
|
1618
|
+
{
|
|
1619
|
+
DefElem *opt = (DefElem *) lfirst(list_item);
|
|
1620
|
+
|
|
1621
|
+
if (!strcmp("transaction_isolation", opt->defname) &&
|
|
1622
|
+
IsA(opt->arg, A_Const) &&
|
|
1623
|
+
((A_Const *)opt->arg)->val.type == T_String &&
|
|
1624
|
+
!strcmp("serializable", ((A_Const *)opt->arg)->val.val.str))
|
|
1625
|
+
return true;
|
|
1626
|
+
}
|
|
1627
|
+
return false;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
/*
|
|
1631
|
+
* If the query is BEGIN READ WRITE or
|
|
1632
|
+
* BEGIN ... SERIALIZABLE in master/slave mode,
|
|
1633
|
+
* we send BEGIN to slaves/standbys instead.
|
|
1634
|
+
* original_query which is BEGIN READ WRITE is sent to primary.
|
|
1635
|
+
* rewritten_query which is BEGIN is sent to standbys.
|
|
1636
|
+
*/
|
|
1637
|
+
bool pool_need_to_treat_as_if_default_transaction(POOL_QUERY_CONTEXT *query_context)
|
|
1638
|
+
{
|
|
1639
|
+
return (MASTER_SLAVE &&
|
|
1640
|
+
is_start_transaction_query(query_context->parse_tree) &&
|
|
1641
|
+
(is_read_write((TransactionStmt *)query_context->parse_tree) ||
|
|
1642
|
+
is_serializable((TransactionStmt *)query_context->parse_tree)));
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/*
|
|
1646
|
+
* Return true if the query is SAVEPOINT related query.
|
|
1647
|
+
*/
|
|
1648
|
+
bool is_savepoint_query(Node *node)
|
|
1649
|
+
{
|
|
1650
|
+
if (((TransactionStmt *)node)->kind == TRANS_STMT_SAVEPOINT ||
|
|
1651
|
+
((TransactionStmt *)node)->kind == TRANS_STMT_ROLLBACK_TO ||
|
|
1652
|
+
((TransactionStmt *)node)->kind == TRANS_STMT_RELEASE)
|
|
1653
|
+
return true;
|
|
1654
|
+
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
/*
|
|
1659
|
+
* Return true if the query is 2PC transaction query.
|
|
1660
|
+
*/
|
|
1661
|
+
bool is_2pc_transaction_query(Node *node)
|
|
1662
|
+
{
|
|
1663
|
+
if (((TransactionStmt *)node)->kind == TRANS_STMT_PREPARE ||
|
|
1664
|
+
((TransactionStmt *)node)->kind == TRANS_STMT_COMMIT_PREPARED ||
|
|
1665
|
+
((TransactionStmt *)node)->kind == TRANS_STMT_ROLLBACK_PREPARED)
|
|
1666
|
+
return true;
|
|
1667
|
+
|
|
1668
|
+
return false;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
/*
|
|
1672
|
+
* Set query state, if a current state is before it than the specified state.
|
|
1673
|
+
*/
|
|
1674
|
+
void pool_set_query_state(POOL_QUERY_CONTEXT *query_context, POOL_QUERY_STATE state)
|
|
1675
|
+
{
|
|
1676
|
+
int i;
|
|
1677
|
+
|
|
1678
|
+
if (!query_context)
|
|
1679
|
+
{
|
|
1680
|
+
pool_error("pool_set_query_state: no query context");
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
for (i = 0; i < NUM_BACKENDS; i++)
|
|
1685
|
+
{
|
|
1686
|
+
if (query_context->where_to_send[i] &&
|
|
1687
|
+
statecmp(query_context->query_state[i], state) < 0)
|
|
1688
|
+
query_context->query_state[i] = state;
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
/*
|
|
1693
|
+
* Return -1, 0 or 1 according to s1 is "before, equal or after" s2 in terms of state
|
|
1694
|
+
* transition order.
|
|
1695
|
+
* The State transition order is defined as: UNPARSED < PARSE_COMPLETE < BIND_COMPLETE < EXECUTE_COMPLETE
|
|
1696
|
+
*/
|
|
1697
|
+
int statecmp(POOL_QUERY_STATE s1, POOL_QUERY_STATE s2)
|
|
1698
|
+
{
|
|
1699
|
+
int ret;
|
|
1700
|
+
|
|
1701
|
+
switch (s2) {
|
|
1702
|
+
case POOL_UNPARSED:
|
|
1703
|
+
ret = (s1 == s2) ? 0 : 1;
|
|
1704
|
+
break;
|
|
1705
|
+
case POOL_PARSE_COMPLETE:
|
|
1706
|
+
if (s1 == POOL_UNPARSED)
|
|
1707
|
+
ret = -1;
|
|
1708
|
+
else
|
|
1709
|
+
ret = (s1 == s2) ? 0 : 1;
|
|
1710
|
+
break;
|
|
1711
|
+
case POOL_BIND_COMPLETE:
|
|
1712
|
+
if (s1 == POOL_UNPARSED || s1 == POOL_PARSE_COMPLETE)
|
|
1713
|
+
ret = -1;
|
|
1714
|
+
else
|
|
1715
|
+
ret = (s1 == s2) ? 0 : 1;
|
|
1716
|
+
break;
|
|
1717
|
+
case POOL_EXECUTE_COMPLETE:
|
|
1718
|
+
ret = (s1 == s2) ? 0 : -1;
|
|
1719
|
+
break;
|
|
1720
|
+
default:
|
|
1721
|
+
ret = -2;
|
|
1722
|
+
break;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
return ret;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
/*
|
|
1729
|
+
* Remove READ WRITE option from the packet of START TRANSACTION command.
|
|
1730
|
+
* To free the return value is required.
|
|
1731
|
+
*/
|
|
1732
|
+
static
|
|
1733
|
+
char* remove_read_write(int len, const char* contents, int *rewritten_len)
|
|
1734
|
+
{
|
|
1735
|
+
char *rewritten_query;
|
|
1736
|
+
char *rewritten_contents;
|
|
1737
|
+
const char *name;
|
|
1738
|
+
const char *stmt;
|
|
1739
|
+
|
|
1740
|
+
rewritten_query = "BEGIN";
|
|
1741
|
+
name = contents;
|
|
1742
|
+
stmt = contents + strlen(name) + 1;
|
|
1743
|
+
|
|
1744
|
+
*rewritten_len = len - strlen(stmt) + strlen(rewritten_query);
|
|
1745
|
+
if (len < *rewritten_len)
|
|
1746
|
+
{
|
|
1747
|
+
pool_error("remove_read_write: invalid message length.");
|
|
1748
|
+
return NULL;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
rewritten_contents = malloc(*rewritten_len);
|
|
1752
|
+
if (rewritten_contents == NULL)
|
|
1753
|
+
{
|
|
1754
|
+
pool_error("remove_read_write: malloc failed.");
|
|
1755
|
+
return NULL;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
strcpy(rewritten_contents, name);
|
|
1759
|
+
strcpy(rewritten_contents + strlen(name) + 1, rewritten_query);
|
|
1760
|
+
memcpy(rewritten_contents + strlen(name) + strlen(rewritten_query) + 2,
|
|
1761
|
+
stmt + strlen(stmt) + 1,
|
|
1762
|
+
len - (strlen(name) + strlen(stmt) + 2));
|
|
1763
|
+
|
|
1764
|
+
return rewritten_contents;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/*
|
|
1768
|
+
* Return true if current query is safe to cache.
|
|
1769
|
+
*/
|
|
1770
|
+
bool pool_is_cache_safe(void)
|
|
1771
|
+
{
|
|
1772
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1773
|
+
|
|
1774
|
+
sc = pool_get_session_context();
|
|
1775
|
+
if (!sc)
|
|
1776
|
+
return false;
|
|
1777
|
+
|
|
1778
|
+
if (pool_is_query_in_progress() && sc->query_context)
|
|
1779
|
+
{
|
|
1780
|
+
return sc->query_context->is_cache_safe;
|
|
1781
|
+
}
|
|
1782
|
+
return false;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
/*
|
|
1786
|
+
* Set safe to cache.
|
|
1787
|
+
*/
|
|
1788
|
+
void pool_set_cache_safe(void)
|
|
1789
|
+
{
|
|
1790
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1791
|
+
|
|
1792
|
+
sc = pool_get_session_context();
|
|
1793
|
+
if (!sc)
|
|
1794
|
+
return;
|
|
1795
|
+
|
|
1796
|
+
if (sc->query_context)
|
|
1797
|
+
{
|
|
1798
|
+
sc->query_context->is_cache_safe = true;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
/*
|
|
1803
|
+
* Unset safe to cache.
|
|
1804
|
+
*/
|
|
1805
|
+
void pool_unset_cache_safe(void)
|
|
1806
|
+
{
|
|
1807
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1808
|
+
|
|
1809
|
+
sc = pool_get_session_context();
|
|
1810
|
+
if (!sc)
|
|
1811
|
+
return;
|
|
1812
|
+
|
|
1813
|
+
if (sc->query_context)
|
|
1814
|
+
{
|
|
1815
|
+
sc->query_context->is_cache_safe = false;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
/*
|
|
1820
|
+
* Return true if current temporary query cache is exceeded
|
|
1821
|
+
*/
|
|
1822
|
+
bool pool_is_cache_exceeded(void)
|
|
1823
|
+
{
|
|
1824
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1825
|
+
|
|
1826
|
+
sc = pool_get_session_context();
|
|
1827
|
+
if (!sc)
|
|
1828
|
+
return false;
|
|
1829
|
+
|
|
1830
|
+
if (pool_is_query_in_progress() && sc->query_context)
|
|
1831
|
+
{
|
|
1832
|
+
if (sc->query_context->temp_cache)
|
|
1833
|
+
return sc->query_context->temp_cache->is_exceeded;
|
|
1834
|
+
return true;
|
|
1835
|
+
}
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
/*
|
|
1840
|
+
* Set current temporary query cache is exceeded
|
|
1841
|
+
*/
|
|
1842
|
+
void pool_set_cache_exceeded(void)
|
|
1843
|
+
{
|
|
1844
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1845
|
+
|
|
1846
|
+
sc = pool_get_session_context();
|
|
1847
|
+
if (!sc)
|
|
1848
|
+
return;
|
|
1849
|
+
|
|
1850
|
+
if (sc->query_context && sc->query_context->temp_cache)
|
|
1851
|
+
{
|
|
1852
|
+
sc->query_context->temp_cache->is_exceeded = true;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
/*
|
|
1857
|
+
* Unset current temporary query cache is exceeded
|
|
1858
|
+
*/
|
|
1859
|
+
void pool_unset_cache_exceeded(void)
|
|
1860
|
+
{
|
|
1861
|
+
POOL_SESSION_CONTEXT *sc;
|
|
1862
|
+
|
|
1863
|
+
sc = pool_get_session_context();
|
|
1864
|
+
if (!sc)
|
|
1865
|
+
return;
|
|
1866
|
+
|
|
1867
|
+
if (sc->query_context && sc->query_context->temp_cache)
|
|
1868
|
+
{
|
|
1869
|
+
sc->query_context->temp_cache->is_exceeded = false;
|
|
1870
|
+
}
|
|
1871
|
+
}
|