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,192 @@
|
|
|
1
|
+
/* -*-pgsql-c-*- */
|
|
2
|
+
/*
|
|
3
|
+
* $Header$
|
|
4
|
+
*
|
|
5
|
+
* pgpool: a language independent connection pool server for PostgreSQL
|
|
6
|
+
* written by Tatsuo Ishii
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2003-2010 PgPool Global Development Group
|
|
9
|
+
*
|
|
10
|
+
* Permission to use, copy, modify, and distribute this software and
|
|
11
|
+
* its documentation for any purpose and without fee is hereby
|
|
12
|
+
* granted, provided that the above copyright notice appear in all
|
|
13
|
+
* copies and that both that copyright notice and this permission
|
|
14
|
+
* notice appear in supporting documentation, and that the name of the
|
|
15
|
+
* author not be used in advertising or publicity pertaining to
|
|
16
|
+
* distribution of the software without specific, written prior
|
|
17
|
+
* permission. The author makes no representations about the
|
|
18
|
+
* suitability of this software for any purpose. It is provided "as
|
|
19
|
+
* is" without express or implied warranty.
|
|
20
|
+
*
|
|
21
|
+
* pool_rewrite_query.h: rewrite_query
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#ifndef POOL_REWRITE_QUERY_H
|
|
26
|
+
#define POOL_REWRITE_QUERY_H
|
|
27
|
+
|
|
28
|
+
#include "parser/nodes.h"
|
|
29
|
+
#include "parser/parser.h"
|
|
30
|
+
#include "parser/pg_list.h"
|
|
31
|
+
#include "parser/parsenodes.h"
|
|
32
|
+
#include "parser/pool_memory.h"
|
|
33
|
+
#include "parser/pool_string.h"
|
|
34
|
+
|
|
35
|
+
/* return code set */
|
|
36
|
+
#define INSERT_SQL_RESTRICTION 1
|
|
37
|
+
#define SELECT_INIT 2
|
|
38
|
+
#define SELECT_BACKEND_CONNECT 3
|
|
39
|
+
#define SELECT_NOT_BACKEND_CONNECT 4
|
|
40
|
+
#define SELECT_PGCATALOG 5
|
|
41
|
+
#define SELECT_CHECK_PGCATALOG_REPLICATION 6
|
|
42
|
+
#define SELECT_DEFAULT 7
|
|
43
|
+
#define SELECT_DEFAULT_INSIDE_DBLINK 8
|
|
44
|
+
#define SELECT_AEXPR 9
|
|
45
|
+
#define SELECT_AEXPR_FALSE 10
|
|
46
|
+
#define SELECT_ONETABLE 11
|
|
47
|
+
#define SELECT_ONETABLE_FALSE 12
|
|
48
|
+
#define SELECT_RELATION_ERROR 13
|
|
49
|
+
#define INSERT_DIST_NO_RULE 14
|
|
50
|
+
#define SEND_PARALLEL_ENGINE 15
|
|
51
|
+
#define SEND_LOADBALANCE_ENGINE 16
|
|
52
|
+
#define SELECT_NOT_REPLICATION 17
|
|
53
|
+
#define SELECT_REWRITE 18
|
|
54
|
+
#define SELECT_ANALYZE 19
|
|
55
|
+
#define SELECT_DEFAULT_PREP 20
|
|
56
|
+
|
|
57
|
+
/* build Sub-Select`s target List */
|
|
58
|
+
typedef struct {
|
|
59
|
+
char **col_list; /* column list */
|
|
60
|
+
char **type_list; /* type list */
|
|
61
|
+
int *return_list; /* order of col_list */
|
|
62
|
+
int col_num; /* column number */
|
|
63
|
+
bool valid; /* return to frontend */
|
|
64
|
+
} SelectDefInfo;
|
|
65
|
+
|
|
66
|
+
/* This struct is used as each table/sub-select of FROM-CLUASE */
|
|
67
|
+
typedef struct {
|
|
68
|
+
DistDefInfo *distinfo; /* distribution table into */
|
|
69
|
+
RepliDefInfo *repliinfo; /* replication table info */
|
|
70
|
+
SelectDefInfo *selectinfo; /* Sub-Select info */
|
|
71
|
+
char *alias; /* alias name */
|
|
72
|
+
char state; /* P = parallel, L = loadbalance S = systemdb(dblink) E = error*/
|
|
73
|
+
int ret_num; /* build column number */
|
|
74
|
+
} RangeInfo;
|
|
75
|
+
|
|
76
|
+
/* build Virtual Table of FROM-Clause */
|
|
77
|
+
typedef struct {
|
|
78
|
+
char **col_list; /* column list */
|
|
79
|
+
char **type_list; /* type list */
|
|
80
|
+
char **table_list; /* table list */
|
|
81
|
+
char *state_list; /* state of each column */
|
|
82
|
+
int *column_no; /* order of column */
|
|
83
|
+
int *valid; /* valid column is true */
|
|
84
|
+
int col_num; /* virtual table column num */
|
|
85
|
+
} VirtualTable;
|
|
86
|
+
|
|
87
|
+
/* this struct is used by JOIN Expr */
|
|
88
|
+
typedef struct {
|
|
89
|
+
char **col_list; /* column list */
|
|
90
|
+
char **type_list; /* type list */
|
|
91
|
+
char **table_list; /* table list */
|
|
92
|
+
char state; /* P = parallel, L = loadbalance S = systemdb(dblink) E = error*/
|
|
93
|
+
int *valid; /* valid column is true */
|
|
94
|
+
int col_num; /* number of column */
|
|
95
|
+
char **using_list; /* if join expr has using-list, column name is listed up */
|
|
96
|
+
int using_length; /* column number of using-list */
|
|
97
|
+
} JoinTable;
|
|
98
|
+
|
|
99
|
+
/* this struct is used in optimization of aggregate opr */
|
|
100
|
+
typedef struct {
|
|
101
|
+
ColumnRef **usec_p; /* targetlist columns */
|
|
102
|
+
FuncCall **tfunc_p; /* targetlist funcs */
|
|
103
|
+
ColumnRef **col_p; /* group by columns */
|
|
104
|
+
FuncCall **hfunc_p; /* having funcs */
|
|
105
|
+
int *umapc; /* order of number */
|
|
106
|
+
int u_num; /* targetlist columns num */
|
|
107
|
+
int t_num; /* targetlist funcs num */
|
|
108
|
+
int c_num; /* group by column num */
|
|
109
|
+
int h_num; /* having funcs num */
|
|
110
|
+
int hc_num; /* having column num */
|
|
111
|
+
int s_num; /* sort funcs num */
|
|
112
|
+
int sc_num; /* sort column num */
|
|
113
|
+
bool opt; /* optimization flag */
|
|
114
|
+
} Aggexpr;
|
|
115
|
+
|
|
116
|
+
/* main struct of analyzing query */
|
|
117
|
+
typedef struct {
|
|
118
|
+
int now_select; /* rank of select */
|
|
119
|
+
int part; /* the position of analyzing select statement */
|
|
120
|
+
int last_select; /* caller select rank */
|
|
121
|
+
int call_part; /* caller's potion */
|
|
122
|
+
int from_num; /* number for from-clause */
|
|
123
|
+
int larg_count; /* left arg count */
|
|
124
|
+
int rarg_count; /* right arg count */
|
|
125
|
+
int ret_count; /* return list count */
|
|
126
|
+
char state; /* final state */
|
|
127
|
+
char *table_name; /* table name or virtual table name */
|
|
128
|
+
char partstate[8]; /* state of analyzing part */
|
|
129
|
+
bool select_union; /* if UNION is used, this flag is true */
|
|
130
|
+
bool select_range; /* RangeSubSelect is used */
|
|
131
|
+
bool aggregate; /* aggregate optimization ? */
|
|
132
|
+
bool retlock; /* this is used */
|
|
133
|
+
Aggexpr *aggexpr; /* Aggexpr in this statement*/
|
|
134
|
+
RangeInfo **range; /* RangeInfo in from clause */
|
|
135
|
+
int rangeinfo_num; /* RangeInfo's number in this select statement*/
|
|
136
|
+
VirtualTable *virtual; /* Virtual Table in this select statement */
|
|
137
|
+
JoinTable *join; /* summary of join table */
|
|
138
|
+
SelectDefInfo *select_ret; /* build return list */
|
|
139
|
+
} AnalyzeSelect;
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* This struct is used as Information that relates
|
|
143
|
+
* to distribution processing of parallel query
|
|
144
|
+
*/
|
|
145
|
+
typedef struct {
|
|
146
|
+
int r_code; /* analyze or rewrite */
|
|
147
|
+
int r_node; /* which node, query is sent */
|
|
148
|
+
int part; /* part of select statement */
|
|
149
|
+
int rewritelock; /* dblink start position and lock rewrite */
|
|
150
|
+
int analyze_num; /* sum of AnalyzeSelect */
|
|
151
|
+
int current_select; /* position of analyze[] */
|
|
152
|
+
int ignore_rewrite; /* dont rewrite */
|
|
153
|
+
int column; /* column number */
|
|
154
|
+
int virtual_num; /* Virtual table column number */
|
|
155
|
+
int ret_num; /* expect return column number */
|
|
156
|
+
bool is_pg_catalog; /* reference of pg_catalog */
|
|
157
|
+
bool is_loadbalance; /* load balance ? */
|
|
158
|
+
bool is_parallel; /* can parallel exec ? */
|
|
159
|
+
bool fromClause; /* having FromClause ? */
|
|
160
|
+
char *table_relname; /* table name */
|
|
161
|
+
char *table_alias; /* table alias name */
|
|
162
|
+
char *schemaname; /* schema */
|
|
163
|
+
char *dbname; /* connect dbname */
|
|
164
|
+
char *rewrite_query; /* execute query */
|
|
165
|
+
char table_state; /* final state */
|
|
166
|
+
POOL_STATUS status; /* return POOL_STATUS */
|
|
167
|
+
NodeTag type; /* Query Type */
|
|
168
|
+
AnalyzeSelect **analyze; /* point to analyzing result */
|
|
169
|
+
} RewriteQuery;
|
|
170
|
+
|
|
171
|
+
/* This info is used in dblink */
|
|
172
|
+
typedef struct {
|
|
173
|
+
char *hostaddr; /* hostname */
|
|
174
|
+
char *dbname; /* data base name */
|
|
175
|
+
char *user; /* access user name */
|
|
176
|
+
int port; /* access port number */
|
|
177
|
+
char *password; /* password of connection */
|
|
178
|
+
} ConInfoTodblink;
|
|
179
|
+
|
|
180
|
+
extern RewriteQuery *rewrite_query_stmt(Node *node, POOL_CONNECTION *frontend,POOL_CONNECTION_POOL *backend,RewriteQuery *message);
|
|
181
|
+
extern void nodeToRewriteString(RewriteQuery *message, ConInfoTodblink *dblink,void *obj);
|
|
182
|
+
char *pool_error_message(char *message);
|
|
183
|
+
extern int IsSelectpgcatalog(Node *node,POOL_CONNECTION_POOL *backend);
|
|
184
|
+
extern RewriteQuery *is_parallel_query(Node *node,POOL_CONNECTION_POOL *backend);
|
|
185
|
+
extern POOL_STATUS pool_parallel_exec(POOL_CONNECTION *frontend,POOL_CONNECTION_POOL *backend, char *string,Node *node,bool send_to_frontend);
|
|
186
|
+
|
|
187
|
+
POOL_STATUS pool_do_parallel_query(POOL_CONNECTION *frontend,
|
|
188
|
+
POOL_CONNECTION_POOL *backend,
|
|
189
|
+
Node *node, bool *parallel, char **string, int *len);
|
|
190
|
+
|
|
191
|
+
#endif /* POOL_REWRITE_QUERY_H */
|
|
192
|
+
|
|
@@ -0,0 +1,1150 @@
|
|
|
1
|
+
/* -*-pgsql-c-*- */
|
|
2
|
+
/*
|
|
3
|
+
* $Header$
|
|
4
|
+
*
|
|
5
|
+
* pgpool: a language independent connection pool server for PostgreSQL
|
|
6
|
+
* written by Tatsuo Ishii
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2003-2013 PgPool Global Development Group
|
|
9
|
+
*
|
|
10
|
+
* Permission to use, copy, modify, and distribute this software and
|
|
11
|
+
* its documentation for any purpose and without fee is hereby
|
|
12
|
+
* granted, provided that the above copyright notice appear in all
|
|
13
|
+
* copies and that both that copyright notice and this permission
|
|
14
|
+
* notice appear in supporting documentation, and that the name of the
|
|
15
|
+
* author not be used in advertising or publicity pertaining to
|
|
16
|
+
* distribution of the software without specific, written prior
|
|
17
|
+
* permission. The author makes no representations about the
|
|
18
|
+
* suitability of this software for any purpose. It is provided "as
|
|
19
|
+
* is" without express or implied warranty.
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
#include <stdlib.h>
|
|
23
|
+
#include <string.h>
|
|
24
|
+
#include <unistd.h>
|
|
25
|
+
|
|
26
|
+
#include "pool.h"
|
|
27
|
+
#include "pool_config.h"
|
|
28
|
+
#include "pool_select_walker.h"
|
|
29
|
+
#include "pool_relcache.h"
|
|
30
|
+
#include "parser/parsenodes.h"
|
|
31
|
+
#include "pool_session_context.h"
|
|
32
|
+
#include "pool_timestamp.h"
|
|
33
|
+
|
|
34
|
+
static bool function_call_walker(Node *node, void *context);
|
|
35
|
+
static bool system_catalog_walker(Node *node, void *context);
|
|
36
|
+
static bool is_system_catalog(char *table_name);
|
|
37
|
+
static bool temp_table_walker(Node *node, void *context);
|
|
38
|
+
static bool relation_walker(Node *node, void *context);
|
|
39
|
+
static bool unlogged_table_walker(Node *node, void *context);
|
|
40
|
+
static bool view_walker(Node *node, void *context);
|
|
41
|
+
static bool is_temp_table(char *table_name);
|
|
42
|
+
static bool insertinto_or_locking_clause_walker(Node *node, void *context);
|
|
43
|
+
static bool is_immutable_function(char *fname);
|
|
44
|
+
static bool select_table_walker(Node *node, void *context);
|
|
45
|
+
static bool non_immutable_function_call_walker(Node *node, void *context);
|
|
46
|
+
static char *strip_quote(char *str);
|
|
47
|
+
static char *make_table_name_from_rangevar(RangeVar *rangevar);
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Return true if this SELECT has function calls *and* supposed to
|
|
51
|
+
* modify database. We check black/white function list to determine
|
|
52
|
+
* whether the function modifies database.
|
|
53
|
+
*/
|
|
54
|
+
bool pool_has_function_call(Node *node)
|
|
55
|
+
{
|
|
56
|
+
SelectContext ctx;
|
|
57
|
+
|
|
58
|
+
if (!IsA(node, SelectStmt))
|
|
59
|
+
return false;
|
|
60
|
+
|
|
61
|
+
ctx.has_function_call = false;
|
|
62
|
+
|
|
63
|
+
raw_expression_tree_walker(node, function_call_walker, &ctx);
|
|
64
|
+
|
|
65
|
+
return ctx.has_function_call;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* Return true if this SELECT has system catalog table.
|
|
70
|
+
*/
|
|
71
|
+
bool pool_has_system_catalog(Node *node)
|
|
72
|
+
{
|
|
73
|
+
|
|
74
|
+
SelectContext ctx;
|
|
75
|
+
|
|
76
|
+
if (!IsA(node, SelectStmt))
|
|
77
|
+
return false;
|
|
78
|
+
|
|
79
|
+
ctx.has_system_catalog = false;
|
|
80
|
+
|
|
81
|
+
raw_expression_tree_walker(node, system_catalog_walker, &ctx);
|
|
82
|
+
|
|
83
|
+
return ctx.has_system_catalog;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* Return true if this SELECT has temporary table.
|
|
88
|
+
*/
|
|
89
|
+
bool pool_has_temp_table(Node *node)
|
|
90
|
+
{
|
|
91
|
+
|
|
92
|
+
SelectContext ctx;
|
|
93
|
+
|
|
94
|
+
if (!IsA(node, SelectStmt))
|
|
95
|
+
return false;
|
|
96
|
+
|
|
97
|
+
ctx.has_temp_table = false;
|
|
98
|
+
|
|
99
|
+
raw_expression_tree_walker(node, temp_table_walker, &ctx);
|
|
100
|
+
|
|
101
|
+
return ctx.has_temp_table;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* Return true if this SELECT has at least one FROM
|
|
106
|
+
*/
|
|
107
|
+
bool pool_has_relation(Node *node)
|
|
108
|
+
{
|
|
109
|
+
|
|
110
|
+
SelectContext ctx;
|
|
111
|
+
|
|
112
|
+
if (!IsA(node, SelectStmt))
|
|
113
|
+
return false;
|
|
114
|
+
|
|
115
|
+
ctx.has_temp_table = false;
|
|
116
|
+
|
|
117
|
+
raw_expression_tree_walker(node, relation_walker, &ctx);
|
|
118
|
+
|
|
119
|
+
return ctx.has_temp_table;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/*
|
|
123
|
+
* Return true if this SELECT has unlogged table.
|
|
124
|
+
*/
|
|
125
|
+
bool pool_has_unlogged_table(Node *node)
|
|
126
|
+
{
|
|
127
|
+
|
|
128
|
+
SelectContext ctx;
|
|
129
|
+
|
|
130
|
+
if (!IsA(node, SelectStmt))
|
|
131
|
+
return false;
|
|
132
|
+
|
|
133
|
+
ctx.has_unlogged_table = false;
|
|
134
|
+
|
|
135
|
+
raw_expression_tree_walker(node, unlogged_table_walker, &ctx);
|
|
136
|
+
|
|
137
|
+
return ctx.has_unlogged_table;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Return true if this SELECT has a view.
|
|
142
|
+
*/
|
|
143
|
+
bool pool_has_view(Node *node)
|
|
144
|
+
{
|
|
145
|
+
|
|
146
|
+
SelectContext ctx;
|
|
147
|
+
|
|
148
|
+
if (!IsA(node, SelectStmt))
|
|
149
|
+
return false;
|
|
150
|
+
|
|
151
|
+
ctx.has_view = false;
|
|
152
|
+
|
|
153
|
+
raw_expression_tree_walker(node, view_walker, &ctx);
|
|
154
|
+
|
|
155
|
+
return ctx.has_view;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
* Return true if this SELECT has INSERT INTO or FOR SHARE or FOR UPDATE.
|
|
160
|
+
*/
|
|
161
|
+
bool pool_has_insertinto_or_locking_clause(Node *node)
|
|
162
|
+
{
|
|
163
|
+
SelectContext ctx;
|
|
164
|
+
|
|
165
|
+
if (!IsA(node, SelectStmt))
|
|
166
|
+
return false;
|
|
167
|
+
|
|
168
|
+
ctx.has_insertinto_or_locking_clause = false;
|
|
169
|
+
|
|
170
|
+
raw_expression_tree_walker(node, insertinto_or_locking_clause_walker, &ctx);
|
|
171
|
+
|
|
172
|
+
pool_debug("pool_has_insertinto_or_locking_clause: returns %d",
|
|
173
|
+
ctx.has_insertinto_or_locking_clause);
|
|
174
|
+
|
|
175
|
+
return ctx.has_insertinto_or_locking_clause;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/*
|
|
179
|
+
* Search function name in whilelist or blacklist regex array
|
|
180
|
+
* Return 1 on success (found in list)
|
|
181
|
+
* Return 0 when not found in list
|
|
182
|
+
* Return -1 if the given search type doesn't exist.
|
|
183
|
+
* Search type supported are: WHITELIST and BLACKLIST
|
|
184
|
+
*/
|
|
185
|
+
int pattern_compare(char *str, const int type, const char *param_name)
|
|
186
|
+
{
|
|
187
|
+
int i = 0;
|
|
188
|
+
|
|
189
|
+
RegPattern *lists_patterns;
|
|
190
|
+
int *pattc;
|
|
191
|
+
|
|
192
|
+
if (strcmp(param_name, "white_function_list") == 0 ||
|
|
193
|
+
strcmp(param_name, "black_function_list") == 0)
|
|
194
|
+
{
|
|
195
|
+
lists_patterns = pool_config->lists_patterns;
|
|
196
|
+
pattc = &pool_config->pattc;
|
|
197
|
+
|
|
198
|
+
} else if (strcmp(param_name, "white_memqcache_table_list") == 0 ||
|
|
199
|
+
strcmp(param_name, "black_memqcache_table_list") == 0)
|
|
200
|
+
{
|
|
201
|
+
lists_patterns = pool_config->lists_memqcache_table_patterns;
|
|
202
|
+
pattc = &pool_config->memqcache_table_pattc;
|
|
203
|
+
|
|
204
|
+
} else {
|
|
205
|
+
pool_error("pattern_compare: unknown paramname %s", param_name);
|
|
206
|
+
return -1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
for (i = 0; i < *pattc; i++) {
|
|
210
|
+
if (lists_patterns[i].type != type)
|
|
211
|
+
continue;
|
|
212
|
+
|
|
213
|
+
if (regexec(&lists_patterns[i].regexv, str, 0, 0, 0) == 0)
|
|
214
|
+
{
|
|
215
|
+
switch(type) {
|
|
216
|
+
/* return 1 if string matches whitelist pattern */
|
|
217
|
+
case WHITELIST:
|
|
218
|
+
pool_debug("pattern_compare: %s (%s) matched: %s",
|
|
219
|
+
param_name, lists_patterns[i].pattern, str);
|
|
220
|
+
return 1;
|
|
221
|
+
/* return 1 if string matches blacklist pattern */
|
|
222
|
+
case BLACKLIST:
|
|
223
|
+
pool_debug("pattern_compare: %s (%s) matched: %s",
|
|
224
|
+
param_name, lists_patterns[i].pattern, str);
|
|
225
|
+
return 1;
|
|
226
|
+
default:
|
|
227
|
+
pool_error("pattern_compare: %s unknown pattern match type: %s", param_name, str);
|
|
228
|
+
return -1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
pool_debug("pattern_compare: %s (%s) not matched: %s",
|
|
232
|
+
param_name, lists_patterns[i].pattern, str);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* return 0 otherwise */
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/*
|
|
240
|
+
* Walker function to find a function call which is supposed to write
|
|
241
|
+
* database.
|
|
242
|
+
*/
|
|
243
|
+
static bool function_call_walker(Node *node, void *context)
|
|
244
|
+
{
|
|
245
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
246
|
+
|
|
247
|
+
if (node == NULL)
|
|
248
|
+
return false;
|
|
249
|
+
|
|
250
|
+
if (IsA(node, FuncCall))
|
|
251
|
+
{
|
|
252
|
+
FuncCall *fcall = (FuncCall *)node;
|
|
253
|
+
char *fname;
|
|
254
|
+
int length = list_length(fcall->funcname);
|
|
255
|
+
|
|
256
|
+
if (length > 0)
|
|
257
|
+
{
|
|
258
|
+
if (length == 1) /* no schema qualification? */
|
|
259
|
+
{
|
|
260
|
+
fname = strVal(linitial(fcall->funcname));
|
|
261
|
+
}
|
|
262
|
+
else
|
|
263
|
+
{
|
|
264
|
+
fname = strVal(lsecond(fcall->funcname)); /* with schema qualification */
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
pool_debug("function_call_walker: function name: %s", fname);
|
|
268
|
+
|
|
269
|
+
/*
|
|
270
|
+
* Check white list if any.
|
|
271
|
+
*/
|
|
272
|
+
if (pool_config->num_white_function_list > 0)
|
|
273
|
+
{
|
|
274
|
+
/* Search function in the white list regex patterns */
|
|
275
|
+
if (pattern_compare(fname, WHITELIST, "white_function_list") == 1) {
|
|
276
|
+
/* If the function is found in the white list, we can ignore it */
|
|
277
|
+
return raw_expression_tree_walker(node, function_call_walker, context);
|
|
278
|
+
}
|
|
279
|
+
/*
|
|
280
|
+
* Since the function was not found in white list, we
|
|
281
|
+
* have found a writing function.
|
|
282
|
+
*/
|
|
283
|
+
ctx->has_function_call = true;
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/*
|
|
288
|
+
* Check black list if any.
|
|
289
|
+
*/
|
|
290
|
+
if (pool_config->num_black_function_list > 0)
|
|
291
|
+
{
|
|
292
|
+
/* Search function in the black list regex patterns */
|
|
293
|
+
if (pattern_compare(fname, BLACKLIST, "black_function_list") == 1) {
|
|
294
|
+
/* Found. */
|
|
295
|
+
ctx->has_function_call = true;
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return raw_expression_tree_walker(node, function_call_walker, context);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/*
|
|
305
|
+
* Walker function to find a system catalog
|
|
306
|
+
*/
|
|
307
|
+
static bool
|
|
308
|
+
system_catalog_walker(Node *node, void *context)
|
|
309
|
+
{
|
|
310
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
311
|
+
|
|
312
|
+
if (node == NULL)
|
|
313
|
+
return false;
|
|
314
|
+
|
|
315
|
+
if (IsA(node, RangeVar))
|
|
316
|
+
{
|
|
317
|
+
RangeVar *rgv = (RangeVar *)node;
|
|
318
|
+
|
|
319
|
+
pool_debug("system_catalog_walker: relname: %s", rgv->relname);
|
|
320
|
+
|
|
321
|
+
if (is_system_catalog(rgv->relname))
|
|
322
|
+
{
|
|
323
|
+
ctx->has_system_catalog = true;
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return raw_expression_tree_walker(node, system_catalog_walker, context);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/*
|
|
331
|
+
* Walker function to find a temp table
|
|
332
|
+
*/
|
|
333
|
+
static bool
|
|
334
|
+
temp_table_walker(Node *node, void *context)
|
|
335
|
+
{
|
|
336
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
337
|
+
|
|
338
|
+
if (node == NULL)
|
|
339
|
+
return false;
|
|
340
|
+
|
|
341
|
+
if (IsA(node, RangeVar))
|
|
342
|
+
{
|
|
343
|
+
RangeVar *rgv = (RangeVar *)node;
|
|
344
|
+
|
|
345
|
+
pool_debug("temp_table_walker: relname: %s", rgv->relname);
|
|
346
|
+
|
|
347
|
+
if (is_temp_table(rgv->relname))
|
|
348
|
+
{
|
|
349
|
+
ctx->has_temp_table = true;
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return raw_expression_tree_walker(node, temp_table_walker, context);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
static bool
|
|
357
|
+
relation_walker(Node *node, void *context)
|
|
358
|
+
{
|
|
359
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
360
|
+
|
|
361
|
+
if (node == NULL)
|
|
362
|
+
return false;
|
|
363
|
+
|
|
364
|
+
if (IsA(node, RangeVar))
|
|
365
|
+
{
|
|
366
|
+
ctx->has_temp_table = true;
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
return raw_expression_tree_walker(node, relation_walker, context);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/*
|
|
373
|
+
* Walker function to find a unlogged table
|
|
374
|
+
*/
|
|
375
|
+
static bool
|
|
376
|
+
unlogged_table_walker(Node *node, void *context)
|
|
377
|
+
{
|
|
378
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
379
|
+
char *relname;
|
|
380
|
+
|
|
381
|
+
if (node == NULL)
|
|
382
|
+
return false;
|
|
383
|
+
|
|
384
|
+
if (IsA(node, RangeVar))
|
|
385
|
+
{
|
|
386
|
+
RangeVar *rgv = (RangeVar *)node;
|
|
387
|
+
relname = make_table_name_from_rangevar(rgv);
|
|
388
|
+
pool_debug("unlogged_table_walker: relname: %s", relname);
|
|
389
|
+
|
|
390
|
+
if (is_unlogged_table(relname))
|
|
391
|
+
{
|
|
392
|
+
ctx->has_unlogged_table = true;
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return raw_expression_tree_walker(node, unlogged_table_walker, context);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/*
|
|
400
|
+
* Walker function to find a view
|
|
401
|
+
*/
|
|
402
|
+
static bool
|
|
403
|
+
view_walker(Node *node, void *context)
|
|
404
|
+
{
|
|
405
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
406
|
+
char *relname;
|
|
407
|
+
|
|
408
|
+
if (node == NULL)
|
|
409
|
+
return false;
|
|
410
|
+
|
|
411
|
+
if (IsA(node, RangeVar))
|
|
412
|
+
{
|
|
413
|
+
RangeVar *rgv = (RangeVar *)node;
|
|
414
|
+
relname = make_table_name_from_rangevar(rgv);
|
|
415
|
+
pool_debug("view_walker: relname: %s", relname);
|
|
416
|
+
|
|
417
|
+
if (is_view(relname))
|
|
418
|
+
{
|
|
419
|
+
ctx->has_view = true;
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return raw_expression_tree_walker(node, view_walker, context);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/*
|
|
427
|
+
* Judge the table used in a query represented by node is a system
|
|
428
|
+
* catalog or not.
|
|
429
|
+
*/
|
|
430
|
+
static bool is_system_catalog(char *table_name)
|
|
431
|
+
{
|
|
432
|
+
/*
|
|
433
|
+
* Query to know if pg_namespace exists. PostgreSQL 7.2 or before doesn't have.
|
|
434
|
+
*/
|
|
435
|
+
#define HASPGNAMESPACEQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.relname = '%s'"
|
|
436
|
+
|
|
437
|
+
/*
|
|
438
|
+
* Query to know if the target table belongs pg_catalog schema.
|
|
439
|
+
*/
|
|
440
|
+
#define ISBELONGTOPGCATALOGQUERY "SELECT count(*) FROM pg_class AS c, pg_namespace AS n WHERE c.relname = '%s' AND c.relnamespace = n.oid AND n.nspname = 'pg_catalog'"
|
|
441
|
+
|
|
442
|
+
#define ISBELONGTOPGCATALOGQUERY2 "SELECT count(*) FROM pg_class AS c, pg_namespace AS n WHERE c.oid = pgpool_regclass('%s') AND c.relnamespace = n.oid AND n.nspname = 'pg_catalog'"
|
|
443
|
+
|
|
444
|
+
int hasreliscatalog;
|
|
445
|
+
bool result;
|
|
446
|
+
static POOL_RELCACHE *hasreliscatalog_cache;
|
|
447
|
+
static POOL_RELCACHE *relcache;
|
|
448
|
+
POOL_CONNECTION_POOL *backend;
|
|
449
|
+
|
|
450
|
+
if (table_name == NULL)
|
|
451
|
+
{
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
backend = pool_get_session_context()->backend;
|
|
456
|
+
|
|
457
|
+
/*
|
|
458
|
+
* Check if pg_namespace exists
|
|
459
|
+
*/
|
|
460
|
+
if (!hasreliscatalog_cache)
|
|
461
|
+
{
|
|
462
|
+
char *query;
|
|
463
|
+
|
|
464
|
+
/* pgpool_regclass has been installed */
|
|
465
|
+
if (pool_has_pgpool_regclass())
|
|
466
|
+
{
|
|
467
|
+
query = ISBELONGTOPGCATALOGQUERY2;
|
|
468
|
+
}
|
|
469
|
+
else
|
|
470
|
+
{
|
|
471
|
+
query = ISBELONGTOPGCATALOGQUERY;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
hasreliscatalog_cache = pool_create_relcache(pool_config->relcache_size, query,
|
|
475
|
+
int_register_func, int_unregister_func,
|
|
476
|
+
false);
|
|
477
|
+
if (hasreliscatalog_cache == NULL)
|
|
478
|
+
{
|
|
479
|
+
pool_error("is_system_catalog: pool_create_relcache error");
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
hasreliscatalog = pool_search_relcache(hasreliscatalog_cache, backend, "pg_namespace")==0?0:1;
|
|
485
|
+
|
|
486
|
+
if (hasreliscatalog)
|
|
487
|
+
{
|
|
488
|
+
/*
|
|
489
|
+
* If relcache does not exist, create it.
|
|
490
|
+
*/
|
|
491
|
+
if (!relcache)
|
|
492
|
+
{
|
|
493
|
+
char *query;
|
|
494
|
+
|
|
495
|
+
/* pgpool_regclass has been installed */
|
|
496
|
+
if (pool_has_pgpool_regclass())
|
|
497
|
+
{
|
|
498
|
+
query = ISBELONGTOPGCATALOGQUERY2;
|
|
499
|
+
}
|
|
500
|
+
else
|
|
501
|
+
{
|
|
502
|
+
query = ISBELONGTOPGCATALOGQUERY;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
relcache = pool_create_relcache(pool_config->relcache_size, query,
|
|
506
|
+
int_register_func, int_unregister_func,
|
|
507
|
+
false);
|
|
508
|
+
if (relcache == NULL)
|
|
509
|
+
{
|
|
510
|
+
pool_error("is_system_catalog: pool_create_relcache error");
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/*
|
|
515
|
+
* Search relcache.
|
|
516
|
+
*/
|
|
517
|
+
result = pool_search_relcache(relcache, backend, table_name)==0?false:true;
|
|
518
|
+
return result;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/*
|
|
522
|
+
* Pre 7.3. Just check whether the table starts with "pg_".
|
|
523
|
+
*/
|
|
524
|
+
return (strcasecmp(table_name, "pg_") == 0);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/*
|
|
528
|
+
* Judge the table used in a query represented by node is a temporary
|
|
529
|
+
* table or not.
|
|
530
|
+
*/
|
|
531
|
+
static POOL_RELCACHE *is_temp_table_relcache;
|
|
532
|
+
|
|
533
|
+
static bool is_temp_table(char *table_name)
|
|
534
|
+
{
|
|
535
|
+
/*
|
|
536
|
+
* Query to know if pg_class has relistemp column or not.
|
|
537
|
+
* PostgreSQL 8.4 and 9.0 have this.
|
|
538
|
+
*/
|
|
539
|
+
#define HASRELITEMPPQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c, pg_attribute AS a WHERE c.relname = 'pg_class' AND a.attrelid = c.oid AND a.attname = 'relistemp'"
|
|
540
|
+
|
|
541
|
+
/*
|
|
542
|
+
* Query to know if the target table is a temporary one. This query
|
|
543
|
+
* is valid in PostgreSQL 7.3 to 8.3 and 9.1 or later. We do not use
|
|
544
|
+
* regclass (or its variant) here, because temporary tables never have
|
|
545
|
+
* schema qualified name.
|
|
546
|
+
*/
|
|
547
|
+
#define ISTEMPQUERY83 "SELECT count(*) FROM pg_class AS c, pg_namespace AS n WHERE c.relname = '%s' AND c.relnamespace = n.oid AND n.nspname ~ '^pg_temp_'"
|
|
548
|
+
|
|
549
|
+
/*
|
|
550
|
+
* Query to know if the target table is a temporary one. This query
|
|
551
|
+
* is valid in PostgreSQL 8.4 and 9.0. We do not use regclass (or its
|
|
552
|
+
* variant) here, because temporary tables never have schema qualified
|
|
553
|
+
* name.
|
|
554
|
+
*/
|
|
555
|
+
#define ISTEMPQUERY84 "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.relname = '%s' AND c.relistemp"
|
|
556
|
+
|
|
557
|
+
int hasrelistemp;
|
|
558
|
+
bool result;
|
|
559
|
+
static POOL_RELCACHE *hasrelistemp_cache;
|
|
560
|
+
char *query;
|
|
561
|
+
POOL_CONNECTION_POOL *backend;
|
|
562
|
+
|
|
563
|
+
if (table_name == NULL)
|
|
564
|
+
{
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
backend = pool_get_session_context()->backend;
|
|
569
|
+
|
|
570
|
+
/*
|
|
571
|
+
* Check backend version
|
|
572
|
+
*/
|
|
573
|
+
if (!hasrelistemp_cache)
|
|
574
|
+
{
|
|
575
|
+
hasrelistemp_cache = pool_create_relcache(pool_config->relcache_size, HASRELITEMPPQUERY,
|
|
576
|
+
int_register_func, int_unregister_func,
|
|
577
|
+
false);
|
|
578
|
+
if (hasrelistemp_cache == NULL)
|
|
579
|
+
{
|
|
580
|
+
pool_error("is_temp_table: pool_create_relcache error");
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
hasrelistemp = pool_search_relcache(hasrelistemp_cache, backend, "pg_class")==0?0:1;
|
|
586
|
+
if (hasrelistemp)
|
|
587
|
+
query = ISTEMPQUERY84;
|
|
588
|
+
else
|
|
589
|
+
query = ISTEMPQUERY83;
|
|
590
|
+
|
|
591
|
+
/*
|
|
592
|
+
* If relcache does not exist, create it.
|
|
593
|
+
*/
|
|
594
|
+
if (!is_temp_table_relcache)
|
|
595
|
+
{
|
|
596
|
+
is_temp_table_relcache = pool_create_relcache(pool_config->relcache_size, query,
|
|
597
|
+
int_register_func, int_unregister_func,
|
|
598
|
+
true);
|
|
599
|
+
if (is_temp_table_relcache == NULL)
|
|
600
|
+
{
|
|
601
|
+
pool_error("is_temp_table: pool_create_relcache error");
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/*
|
|
607
|
+
* Search relcache.
|
|
608
|
+
*/
|
|
609
|
+
result = pool_search_relcache(is_temp_table_relcache, backend, table_name)==0?false:true;
|
|
610
|
+
return result;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/*
|
|
614
|
+
* Discard relcache used by is_temp_table_relcache().
|
|
615
|
+
*/
|
|
616
|
+
void discard_temp_table_relcache(void)
|
|
617
|
+
{
|
|
618
|
+
if (is_temp_table_relcache)
|
|
619
|
+
{
|
|
620
|
+
pool_discard_relcache(is_temp_table_relcache);
|
|
621
|
+
is_temp_table_relcache = NULL;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/*
|
|
626
|
+
* Judge the table used in a query represented by node is a unlogged
|
|
627
|
+
* table or not.
|
|
628
|
+
*/
|
|
629
|
+
bool is_unlogged_table(char *table_name)
|
|
630
|
+
{
|
|
631
|
+
/*
|
|
632
|
+
* Query to know if pg_class has relpersistence column or not.
|
|
633
|
+
* PostgreSQL 9.1 or later has this.
|
|
634
|
+
*/
|
|
635
|
+
#define HASRELPERSISTENCEQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c, pg_catalog.pg_attribute AS a WHERE c.relname = 'pg_class' AND a.attrelid = c.oid AND a.attname = 'relpersistence'"
|
|
636
|
+
|
|
637
|
+
/*
|
|
638
|
+
* Query to know if the target table is a unlogged one. This query
|
|
639
|
+
* is valid in PostgreSQL 9.1 or later.
|
|
640
|
+
*/
|
|
641
|
+
#define ISUNLOGGEDQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.relname = '%s' AND c.relpersistence = 'u'"
|
|
642
|
+
|
|
643
|
+
#define ISUNLOGGEDQUERY2 "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.oid = pgpool_regclass('%s') AND c.relpersistence = 'u'"
|
|
644
|
+
|
|
645
|
+
int hasrelpersistence;
|
|
646
|
+
static POOL_RELCACHE *hasrelpersistence_cache;
|
|
647
|
+
static POOL_RELCACHE *relcache;
|
|
648
|
+
POOL_CONNECTION_POOL *backend;
|
|
649
|
+
|
|
650
|
+
if (table_name == NULL)
|
|
651
|
+
{
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
backend = pool_get_session_context()->backend;
|
|
656
|
+
|
|
657
|
+
/*
|
|
658
|
+
* Check backend version
|
|
659
|
+
*/
|
|
660
|
+
if (!hasrelpersistence_cache)
|
|
661
|
+
{
|
|
662
|
+
hasrelpersistence_cache = pool_create_relcache(pool_config->relcache_size, HASRELPERSISTENCEQUERY,
|
|
663
|
+
int_register_func, int_unregister_func,
|
|
664
|
+
false);
|
|
665
|
+
if (hasrelpersistence_cache == NULL)
|
|
666
|
+
{
|
|
667
|
+
pool_error("is_unlogged_table: pool_create_relcache error");
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
hasrelpersistence = pool_search_relcache(hasrelpersistence_cache, backend, "pg_class")==0?0:1;
|
|
673
|
+
if (hasrelpersistence)
|
|
674
|
+
{
|
|
675
|
+
bool result;
|
|
676
|
+
char *query;
|
|
677
|
+
|
|
678
|
+
/* pgpool_regclass has been installed */
|
|
679
|
+
if (pool_has_pgpool_regclass())
|
|
680
|
+
{
|
|
681
|
+
query = ISUNLOGGEDQUERY2;
|
|
682
|
+
}
|
|
683
|
+
else
|
|
684
|
+
{
|
|
685
|
+
query = ISUNLOGGEDQUERY;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/*
|
|
689
|
+
* If relcache does not exist, create it.
|
|
690
|
+
*/
|
|
691
|
+
if (!relcache)
|
|
692
|
+
{
|
|
693
|
+
relcache = pool_create_relcache(pool_config->relcache_size, query,
|
|
694
|
+
int_register_func, int_unregister_func,
|
|
695
|
+
true);
|
|
696
|
+
if (relcache == NULL)
|
|
697
|
+
{
|
|
698
|
+
pool_error("is_unlogged_table: pool_create_relcache error");
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/*
|
|
704
|
+
* Search relcache.
|
|
705
|
+
*/
|
|
706
|
+
result = pool_search_relcache(relcache, backend, table_name)==0?false:true;
|
|
707
|
+
return result;
|
|
708
|
+
}
|
|
709
|
+
else
|
|
710
|
+
{
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/*
|
|
716
|
+
* Judge the table used in a query is a view or not.
|
|
717
|
+
*/
|
|
718
|
+
bool is_view(char *table_name)
|
|
719
|
+
{
|
|
720
|
+
/*
|
|
721
|
+
* Query to know if the target table is a view.
|
|
722
|
+
*/
|
|
723
|
+
#define ISVIEWQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.relname = '%s' AND c.relkind = 'v'"
|
|
724
|
+
|
|
725
|
+
#define ISVIEWQUERY2 "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.oid = pgpool_regclass('%s') AND c.relkind = 'v'"
|
|
726
|
+
|
|
727
|
+
static POOL_RELCACHE *relcache;
|
|
728
|
+
POOL_CONNECTION_POOL *backend;
|
|
729
|
+
bool result;
|
|
730
|
+
char *query;
|
|
731
|
+
|
|
732
|
+
if (table_name == NULL)
|
|
733
|
+
{
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
backend = pool_get_session_context()->backend;
|
|
738
|
+
|
|
739
|
+
/* pgpool_regclass has been installed */
|
|
740
|
+
if (pool_has_pgpool_regclass())
|
|
741
|
+
{
|
|
742
|
+
query = ISVIEWQUERY2;
|
|
743
|
+
}
|
|
744
|
+
else
|
|
745
|
+
{
|
|
746
|
+
query = ISVIEWQUERY;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (!relcache)
|
|
750
|
+
{
|
|
751
|
+
relcache = pool_create_relcache(pool_config->relcache_size, query,
|
|
752
|
+
int_register_func, int_unregister_func,
|
|
753
|
+
false);
|
|
754
|
+
if (relcache == NULL)
|
|
755
|
+
{
|
|
756
|
+
pool_error("is_view: pool_create_relcache error");
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/*
|
|
763
|
+
* Search relcache.
|
|
764
|
+
*/
|
|
765
|
+
result = pool_search_relcache(relcache, backend, table_name)==0?false:true;
|
|
766
|
+
return result;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/*
|
|
770
|
+
* Judge if we have pgpool_regclass or not.
|
|
771
|
+
*/
|
|
772
|
+
bool pool_has_pgpool_regclass(void)
|
|
773
|
+
{
|
|
774
|
+
/*
|
|
775
|
+
* Query to know if pgpool_regclass exists.
|
|
776
|
+
*/
|
|
777
|
+
#define HASPGPOOL_REGCLASSQUERY "SELECT count(*) from (SELECT has_function_privilege('%s', 'pgpool_regclass(cstring)', 'execute') WHERE EXISTS(SELECT * FROM pg_catalog.pg_proc AS p WHERE p.proname = 'pgpool_regclass')) AS s"
|
|
778
|
+
|
|
779
|
+
bool result;
|
|
780
|
+
static POOL_RELCACHE *relcache;
|
|
781
|
+
POOL_CONNECTION_POOL *backend;
|
|
782
|
+
char *user;
|
|
783
|
+
|
|
784
|
+
backend = pool_get_session_context()->backend;
|
|
785
|
+
user = MASTER_CONNECTION(backend)->sp->user;
|
|
786
|
+
|
|
787
|
+
if (!relcache)
|
|
788
|
+
{
|
|
789
|
+
relcache = pool_create_relcache(pool_config->relcache_size, HASPGPOOL_REGCLASSQUERY,
|
|
790
|
+
int_register_func, int_unregister_func,
|
|
791
|
+
false);
|
|
792
|
+
if (relcache == NULL)
|
|
793
|
+
{
|
|
794
|
+
pool_error("has_pgpool_regclass: pool_create_relcache error");
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
result = pool_search_relcache(relcache, backend, user)==0?0:1;
|
|
800
|
+
return result;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/*
|
|
804
|
+
* Walker function to find intoClause or lockingClause.
|
|
805
|
+
*/
|
|
806
|
+
static bool insertinto_or_locking_clause_walker(Node *node, void *context)
|
|
807
|
+
{
|
|
808
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
809
|
+
|
|
810
|
+
if (node == NULL)
|
|
811
|
+
return false;
|
|
812
|
+
|
|
813
|
+
if (IsA(node, IntoClause) || IsA(node, LockingClause))
|
|
814
|
+
{
|
|
815
|
+
ctx->has_insertinto_or_locking_clause = true;
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
return raw_expression_tree_walker(node, insertinto_or_locking_clause_walker, ctx);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/*
|
|
822
|
+
* Return true if this SELECT has non immutable function calls.
|
|
823
|
+
*/
|
|
824
|
+
bool pool_has_non_immutable_function_call(Node *node)
|
|
825
|
+
{
|
|
826
|
+
SelectContext ctx;
|
|
827
|
+
|
|
828
|
+
if (!IsA(node, SelectStmt))
|
|
829
|
+
return false;
|
|
830
|
+
|
|
831
|
+
ctx.has_non_immutable_function_call = false;
|
|
832
|
+
|
|
833
|
+
raw_expression_tree_walker(node, non_immutable_function_call_walker, &ctx);
|
|
834
|
+
|
|
835
|
+
pool_debug("pool_has_non_immutable_function_call: %d", ctx.has_non_immutable_function_call);
|
|
836
|
+
return ctx.has_non_immutable_function_call;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/*
|
|
840
|
+
* Walker function to find non immutable function call.
|
|
841
|
+
*/
|
|
842
|
+
static bool non_immutable_function_call_walker(Node *node, void *context)
|
|
843
|
+
{
|
|
844
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
845
|
+
|
|
846
|
+
if (node == NULL)
|
|
847
|
+
return false;
|
|
848
|
+
|
|
849
|
+
if (IsA(node, FuncCall))
|
|
850
|
+
{
|
|
851
|
+
FuncCall *fcall = (FuncCall *)node;
|
|
852
|
+
char *fname;
|
|
853
|
+
int length = list_length(fcall->funcname);
|
|
854
|
+
|
|
855
|
+
if (length > 0)
|
|
856
|
+
{
|
|
857
|
+
if (length == 1) /* no schema qualification? */
|
|
858
|
+
{
|
|
859
|
+
fname = strVal(linitial(fcall->funcname));
|
|
860
|
+
}
|
|
861
|
+
else
|
|
862
|
+
{
|
|
863
|
+
fname = strVal(lsecond(fcall->funcname)); /* with schema qualification */
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
pool_debug("non_immutable_function_call_walker: function name: %s", fname);
|
|
867
|
+
|
|
868
|
+
/* Check system catalog if the function is immutable */
|
|
869
|
+
if (is_immutable_function(fname) == false)
|
|
870
|
+
{
|
|
871
|
+
/* Non immutable function call found */
|
|
872
|
+
ctx->has_non_immutable_function_call = true;
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
else if (IsA(node, TypeCast))
|
|
878
|
+
{
|
|
879
|
+
/* CURRENT_DATE, CURRENT_TIME, LOCALTIMESTAMP, LOCALTIME etc.*/
|
|
880
|
+
TypeCast *tc = (TypeCast *) node;
|
|
881
|
+
|
|
882
|
+
if ((isSystemType((Node *) tc->typeName, "date") ||
|
|
883
|
+
isSystemType((Node *) tc->typeName, "timestamp") ||
|
|
884
|
+
isSystemType((Node *) tc->typeName, "timestamptz") ||
|
|
885
|
+
isSystemType((Node *) tc->typeName, "time") ||
|
|
886
|
+
isSystemType((Node *) tc->typeName, "timetz")))
|
|
887
|
+
{
|
|
888
|
+
ctx->has_non_immutable_function_call = true;
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
return raw_expression_tree_walker(node, non_immutable_function_call_walker, context);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/*
|
|
897
|
+
* Check if the function is stable.
|
|
898
|
+
*/
|
|
899
|
+
static bool is_immutable_function(char *fname)
|
|
900
|
+
{
|
|
901
|
+
/*
|
|
902
|
+
* Query to know if the function is IMMUTABLE
|
|
903
|
+
*/
|
|
904
|
+
#define IS_STABLE_FUNCTION_QUERY "SELECT count(*) FROM pg_catalog.pg_proc AS p WHERE p.proname = '%s' AND p.provolatile = 'i'"
|
|
905
|
+
bool result;
|
|
906
|
+
static POOL_RELCACHE *relcache;
|
|
907
|
+
POOL_CONNECTION_POOL *backend;
|
|
908
|
+
|
|
909
|
+
backend = pool_get_session_context()->backend;
|
|
910
|
+
|
|
911
|
+
if (!relcache)
|
|
912
|
+
{
|
|
913
|
+
relcache = pool_create_relcache(pool_config->relcache_size, IS_STABLE_FUNCTION_QUERY,
|
|
914
|
+
int_register_func, int_unregister_func,
|
|
915
|
+
false);
|
|
916
|
+
if (relcache == NULL)
|
|
917
|
+
{
|
|
918
|
+
pool_error("is_immutable_function: pool_create_relcache error");
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
pool_debug("is_immutable_function: relcache created");
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
result = pool_search_relcache(relcache, backend, fname)==0?0:1;
|
|
925
|
+
pool_debug("is_immutable_function: search result:%d", result);
|
|
926
|
+
return result;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/*
|
|
930
|
+
* Convert table_name(possibly including schema name) to oid
|
|
931
|
+
*/
|
|
932
|
+
int pool_table_name_to_oid(char *table_name)
|
|
933
|
+
{
|
|
934
|
+
/*
|
|
935
|
+
* Query to convert table name to oid
|
|
936
|
+
*/
|
|
937
|
+
#define TABLE_TO_OID_QUERY "SELECT pgpool_regclass('%s')"
|
|
938
|
+
#define TABLE_TO_OID_QUERY2 "SELECT oid FROM pg_class WHERE relname = '%s'"
|
|
939
|
+
|
|
940
|
+
int oid = 0;
|
|
941
|
+
static POOL_RELCACHE *relcache;
|
|
942
|
+
POOL_CONNECTION_POOL *backend;
|
|
943
|
+
char *query;
|
|
944
|
+
|
|
945
|
+
if (table_name == NULL)
|
|
946
|
+
{
|
|
947
|
+
return oid;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
backend = pool_get_session_context()->backend;
|
|
951
|
+
|
|
952
|
+
if (pool_has_pgpool_regclass())
|
|
953
|
+
{
|
|
954
|
+
query = TABLE_TO_OID_QUERY;
|
|
955
|
+
}
|
|
956
|
+
else
|
|
957
|
+
{
|
|
958
|
+
query = TABLE_TO_OID_QUERY2;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/*
|
|
962
|
+
* If relcache does not exist, create it.
|
|
963
|
+
*/
|
|
964
|
+
if (!relcache)
|
|
965
|
+
{
|
|
966
|
+
relcache = pool_create_relcache(pool_config->relcache_size, query,
|
|
967
|
+
int_register_func, int_unregister_func,
|
|
968
|
+
true);
|
|
969
|
+
if (relcache == NULL)
|
|
970
|
+
{
|
|
971
|
+
pool_error("table_name_to_oid: pool_create_relcache error");
|
|
972
|
+
return oid;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/* Se do not cache if pgpool_regclass() returns 0, which indicates
|
|
976
|
+
* there's no such a table. In this case we do not want to cache the
|
|
977
|
+
* state because the table might be created later in this session.
|
|
978
|
+
*/
|
|
979
|
+
relcache->no_cache_if_zero = true;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/*
|
|
983
|
+
* Search relcache.
|
|
984
|
+
*/
|
|
985
|
+
oid = (int)(intptr_t)pool_search_relcache(relcache, backend, table_name);
|
|
986
|
+
return oid;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/*
|
|
990
|
+
* Extract table oids from SELECT statement. Returns number of oids.
|
|
991
|
+
* Oids are returned as an int array. The contents of oid array are
|
|
992
|
+
* discarded by next call to this function.
|
|
993
|
+
*/
|
|
994
|
+
int pool_extract_table_oids_from_select_stmt(Node *node, SelectContext *ctx)
|
|
995
|
+
{
|
|
996
|
+
if (!IsA(node, SelectStmt))
|
|
997
|
+
return 0;
|
|
998
|
+
|
|
999
|
+
ctx->num_oids = 0;
|
|
1000
|
+
raw_expression_tree_walker(node, select_table_walker, ctx);
|
|
1001
|
+
|
|
1002
|
+
return ctx->num_oids;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/*
|
|
1006
|
+
* Walker function to extract table oids from SELECT statement.
|
|
1007
|
+
*/
|
|
1008
|
+
static bool
|
|
1009
|
+
select_table_walker(Node *node, void *context)
|
|
1010
|
+
{
|
|
1011
|
+
SelectContext *ctx = (SelectContext *) context;
|
|
1012
|
+
int num_oids;
|
|
1013
|
+
|
|
1014
|
+
if (node == NULL)
|
|
1015
|
+
return false;
|
|
1016
|
+
|
|
1017
|
+
if (IsA(node, RangeVar))
|
|
1018
|
+
{
|
|
1019
|
+
RangeVar *rgv = (RangeVar *)node;
|
|
1020
|
+
char *table;
|
|
1021
|
+
int oid;
|
|
1022
|
+
char *s;
|
|
1023
|
+
|
|
1024
|
+
table = make_table_name_from_rangevar(rgv);
|
|
1025
|
+
oid = pool_table_name_to_oid(table);
|
|
1026
|
+
|
|
1027
|
+
if (oid)
|
|
1028
|
+
{
|
|
1029
|
+
if (POOL_MAX_SELECT_OIDS <= ctx->num_oids)
|
|
1030
|
+
{
|
|
1031
|
+
pool_debug("select_table_walker: number of oids exceeds");
|
|
1032
|
+
return false;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
num_oids = ctx->num_oids++;
|
|
1036
|
+
|
|
1037
|
+
ctx->table_oids[num_oids] = oid;
|
|
1038
|
+
s = strip_quote(table);
|
|
1039
|
+
strlcpy(ctx->table_names[num_oids], s, POOL_NAMEDATALEN);
|
|
1040
|
+
free(s);
|
|
1041
|
+
|
|
1042
|
+
pool_debug("select_table_walker: ctx->table_names[%d] = %s",
|
|
1043
|
+
num_oids, ctx->table_names[num_oids]);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
return raw_expression_tree_walker(node, select_table_walker, context);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
static char *strip_quote(char *str)
|
|
1051
|
+
{
|
|
1052
|
+
char *after;
|
|
1053
|
+
int i = 0;
|
|
1054
|
+
|
|
1055
|
+
after = malloc(sizeof(char) * strlen(str) + 1);
|
|
1056
|
+
|
|
1057
|
+
do {
|
|
1058
|
+
if (*str != '"')
|
|
1059
|
+
{
|
|
1060
|
+
after[i] = *str;
|
|
1061
|
+
i++;
|
|
1062
|
+
}
|
|
1063
|
+
str++;
|
|
1064
|
+
} while (*str != '\0');
|
|
1065
|
+
|
|
1066
|
+
after[i] = '\0';
|
|
1067
|
+
|
|
1068
|
+
return after;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
/*
|
|
1072
|
+
* makeRangeVarFromNameList
|
|
1073
|
+
* Utility routine to convert a qualified-name list into RangeVar form.
|
|
1074
|
+
*
|
|
1075
|
+
* Copied from backend/catalog/namespace.c
|
|
1076
|
+
*/
|
|
1077
|
+
RangeVar *
|
|
1078
|
+
makeRangeVarFromNameList(List *names)
|
|
1079
|
+
{
|
|
1080
|
+
RangeVar *rel = makeRangeVar(NULL, NULL, -1);
|
|
1081
|
+
|
|
1082
|
+
switch (list_length(names))
|
|
1083
|
+
{
|
|
1084
|
+
case 1:
|
|
1085
|
+
rel->relname = strVal(linitial(names));
|
|
1086
|
+
break;
|
|
1087
|
+
case 2:
|
|
1088
|
+
rel->schemaname = strVal(linitial(names));
|
|
1089
|
+
rel->relname = strVal(lsecond(names));
|
|
1090
|
+
break;
|
|
1091
|
+
case 3:
|
|
1092
|
+
rel->catalogname = strVal(linitial(names));
|
|
1093
|
+
rel->schemaname = strVal(lsecond(names));
|
|
1094
|
+
rel->relname = strVal(lthird(names));
|
|
1095
|
+
break;
|
|
1096
|
+
default:
|
|
1097
|
+
pool_error("improper relation name (too many dotted names)");
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
return rel;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/*
|
|
1105
|
+
* Extract table name from RageVar. Make schema qualification name if
|
|
1106
|
+
* necessary. The returned table name is in static area. So next
|
|
1107
|
+
* call to this function will break previous result.
|
|
1108
|
+
*/
|
|
1109
|
+
static char *make_table_name_from_rangevar(RangeVar *rangevar)
|
|
1110
|
+
{
|
|
1111
|
+
/*
|
|
1112
|
+
* Table name. Max size is calculated as follows:
|
|
1113
|
+
* schema name(POOL_NAMEDATALEN byte)
|
|
1114
|
+
* + single quote(1 byte)
|
|
1115
|
+
* + table name (POOL_NAMEDATALEN byte)
|
|
1116
|
+
* + NULL(1 byte)
|
|
1117
|
+
*/
|
|
1118
|
+
static char tablename[POOL_NAMEDATALEN*2+1+1];
|
|
1119
|
+
|
|
1120
|
+
if (rangevar == NULL)
|
|
1121
|
+
{
|
|
1122
|
+
pool_error("make_table_name_from_rangevar: argument is NULL");
|
|
1123
|
+
return "";
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (!IsA(rangevar, RangeVar))
|
|
1127
|
+
{
|
|
1128
|
+
pool_error("make_table_name_from_rangevar: argument is not a RangeVar (%d)",
|
|
1129
|
+
((Node *)rangevar)->type);
|
|
1130
|
+
return "";
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
*tablename = '\0';
|
|
1134
|
+
|
|
1135
|
+
if (rangevar->schemaname)
|
|
1136
|
+
{
|
|
1137
|
+
strncpy(tablename, rangevar->schemaname, POOL_NAMEDATALEN);
|
|
1138
|
+
strcat(tablename, ".");
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
if (!rangevar->relname)
|
|
1142
|
+
{
|
|
1143
|
+
pool_error("make_table_name_from_rangevar: RangeVar->relname is NULL");
|
|
1144
|
+
return "";
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
strncat(tablename, rangevar->relname, POOL_NAMEDATALEN);
|
|
1148
|
+
pool_debug("make_table_name_from_rangevar: tablename:%s", tablename);
|
|
1149
|
+
return tablename;
|
|
1150
|
+
}
|