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.
Files changed (393) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +20 -0
  4. data/LICENSE +202 -0
  5. data/NOTICE +22 -0
  6. data/README.md +217 -0
  7. data/Rakefile +13 -0
  8. data/VERSION +1 -0
  9. data/bin/prestogres +254 -0
  10. data/config/pcp.conf.sample +28 -0
  11. data/config/pgpool.conf +678 -0
  12. data/config/pool_hba.conf +84 -0
  13. data/config/pool_passwd +0 -0
  14. data/config/postgresql.conf +2 -0
  15. data/ext/.gitignore +6 -0
  16. data/ext/depend +26 -0
  17. data/ext/extconf.rb +4 -0
  18. data/ext/prestogres_config.c +12 -0
  19. data/pgpool2/.gitignore +36 -0
  20. data/pgpool2/AUTHORS +4 -0
  21. data/pgpool2/COPYING +12 -0
  22. data/pgpool2/ChangeLog +1 -0
  23. data/pgpool2/INSTALL +1 -0
  24. data/pgpool2/Makefile.am +159 -0
  25. data/pgpool2/Makefile.in +1187 -0
  26. data/pgpool2/NEWS +4960 -0
  27. data/pgpool2/README +1 -0
  28. data/pgpool2/README.euc_jp +1 -0
  29. data/pgpool2/README.online-recovery +62 -0
  30. data/pgpool2/TODO +103 -0
  31. data/pgpool2/ac_func_accept_argtypes.m4 +85 -0
  32. data/pgpool2/aclocal.m4 +1088 -0
  33. data/pgpool2/c-compiler.m4 +134 -0
  34. data/pgpool2/c-library.m4 +325 -0
  35. data/pgpool2/child.c +2097 -0
  36. data/pgpool2/config.guess +1532 -0
  37. data/pgpool2/config.h.in +332 -0
  38. data/pgpool2/config.sub +1640 -0
  39. data/pgpool2/configure +15752 -0
  40. data/pgpool2/configure.in +392 -0
  41. data/pgpool2/depcomp +522 -0
  42. data/pgpool2/doc/basebackup.sh +17 -0
  43. data/pgpool2/doc/pgpool-de.html +4220 -0
  44. data/pgpool2/doc/pgpool-en.html +5738 -0
  45. data/pgpool2/doc/pgpool-fr.html +4118 -0
  46. data/pgpool2/doc/pgpool-ja.css +198 -0
  47. data/pgpool2/doc/pgpool-ja.html +11279 -0
  48. data/pgpool2/doc/pgpool-zh_cn.html +4445 -0
  49. data/pgpool2/doc/pgpool.css +280 -0
  50. data/pgpool2/doc/pgpool_remote_start +13 -0
  51. data/pgpool2/doc/recovery.conf.sample +117 -0
  52. data/pgpool2/doc/tutorial-en.html +707 -0
  53. data/pgpool2/doc/tutorial-ja.html +422 -0
  54. data/pgpool2/doc/tutorial-memqcache-en.html +325 -0
  55. data/pgpool2/doc/tutorial-memqcache-ja.html +370 -0
  56. data/pgpool2/doc/tutorial-memqcache-zh_cn.html +322 -0
  57. data/pgpool2/doc/tutorial-watchdog-en.html +306 -0
  58. data/pgpool2/doc/tutorial-watchdog-ja.html +343 -0
  59. data/pgpool2/doc/tutorial-watchdog-zh_cn.html +301 -0
  60. data/pgpool2/doc/tutorial-zh_cn.html +537 -0
  61. data/pgpool2/doc/watchdog.png +0 -0
  62. data/pgpool2/doc/wd-en.html +236 -0
  63. data/pgpool2/doc/wd-en.jpg +0 -0
  64. data/pgpool2/doc/wd-ja.html +219 -0
  65. data/pgpool2/doc/wd-ja.jpg +0 -0
  66. data/pgpool2/doc/wd-zh_cn.html +201 -0
  67. data/pgpool2/doc/where_to_send_queries.odg +0 -0
  68. data/pgpool2/doc/where_to_send_queries.pdf +0 -0
  69. data/pgpool2/general.m4 +166 -0
  70. data/pgpool2/getopt_long.c +200 -0
  71. data/pgpool2/getopt_long.h +44 -0
  72. data/pgpool2/install-sh +251 -0
  73. data/pgpool2/ltmain.sh +8406 -0
  74. data/pgpool2/m4/libtool.m4 +7360 -0
  75. data/pgpool2/m4/ltoptions.m4 +368 -0
  76. data/pgpool2/m4/ltsugar.m4 +123 -0
  77. data/pgpool2/m4/ltversion.m4 +23 -0
  78. data/pgpool2/m4/lt~obsolete.m4 +92 -0
  79. data/pgpool2/main.c +2971 -0
  80. data/pgpool2/md5.c +444 -0
  81. data/pgpool2/md5.h +28 -0
  82. data/pgpool2/missing +360 -0
  83. data/pgpool2/mkinstalldirs +40 -0
  84. data/pgpool2/parser/Makefile.am +50 -0
  85. data/pgpool2/parser/Makefile.in +559 -0
  86. data/pgpool2/parser/copyfuncs.c +3310 -0
  87. data/pgpool2/parser/gram.c +39100 -0
  88. data/pgpool2/parser/gram.h +940 -0
  89. data/pgpool2/parser/gram.y +13408 -0
  90. data/pgpool2/parser/gramparse.h +74 -0
  91. data/pgpool2/parser/keywords.c +32 -0
  92. data/pgpool2/parser/keywords.h +39 -0
  93. data/pgpool2/parser/kwlist.h +425 -0
  94. data/pgpool2/parser/kwlookup.c +88 -0
  95. data/pgpool2/parser/list.c +1156 -0
  96. data/pgpool2/parser/makefuncs.c +518 -0
  97. data/pgpool2/parser/makefuncs.h +83 -0
  98. data/pgpool2/parser/memnodes.h +79 -0
  99. data/pgpool2/parser/nodes.c +29 -0
  100. data/pgpool2/parser/nodes.h +609 -0
  101. data/pgpool2/parser/outfuncs.c +5790 -0
  102. data/pgpool2/parser/parsenodes.h +2615 -0
  103. data/pgpool2/parser/parser.c +262 -0
  104. data/pgpool2/parser/parser.h +46 -0
  105. data/pgpool2/parser/pg_class.h +158 -0
  106. data/pgpool2/parser/pg_config_manual.h +273 -0
  107. data/pgpool2/parser/pg_list.h +352 -0
  108. data/pgpool2/parser/pg_trigger.h +147 -0
  109. data/pgpool2/parser/pg_wchar.h +492 -0
  110. data/pgpool2/parser/pool_memory.c +342 -0
  111. data/pgpool2/parser/pool_memory.h +77 -0
  112. data/pgpool2/parser/pool_parser.h +222 -0
  113. data/pgpool2/parser/pool_string.c +121 -0
  114. data/pgpool2/parser/pool_string.h +37 -0
  115. data/pgpool2/parser/primnodes.h +1280 -0
  116. data/pgpool2/parser/scan.c +4094 -0
  117. data/pgpool2/parser/scan.l +1451 -0
  118. data/pgpool2/parser/scanner.h +120 -0
  119. data/pgpool2/parser/scansup.c +221 -0
  120. data/pgpool2/parser/scansup.h +28 -0
  121. data/pgpool2/parser/snprintf.c +1102 -0
  122. data/pgpool2/parser/stringinfo.c +294 -0
  123. data/pgpool2/parser/stringinfo.h +178 -0
  124. data/pgpool2/parser/value.c +78 -0
  125. data/pgpool2/parser/value.h +62 -0
  126. data/pgpool2/parser/wchar.c +2048 -0
  127. data/pgpool2/pcp.conf.sample +28 -0
  128. data/pgpool2/pcp/Makefile.am +40 -0
  129. data/pgpool2/pcp/Makefile.in +771 -0
  130. data/pgpool2/pcp/libpcp_ext.h +250 -0
  131. data/pgpool2/pcp/md5.c +444 -0
  132. data/pgpool2/pcp/md5.h +28 -0
  133. data/pgpool2/pcp/pcp.c +1652 -0
  134. data/pgpool2/pcp/pcp.h +61 -0
  135. data/pgpool2/pcp/pcp_attach_node.c +172 -0
  136. data/pgpool2/pcp/pcp_detach_node.c +185 -0
  137. data/pgpool2/pcp/pcp_error.c +87 -0
  138. data/pgpool2/pcp/pcp_node_count.c +160 -0
  139. data/pgpool2/pcp/pcp_node_info.c +198 -0
  140. data/pgpool2/pcp/pcp_pool_status.c +166 -0
  141. data/pgpool2/pcp/pcp_proc_count.c +166 -0
  142. data/pgpool2/pcp/pcp_proc_info.c +261 -0
  143. data/pgpool2/pcp/pcp_promote_node.c +185 -0
  144. data/pgpool2/pcp/pcp_recovery_node.c +172 -0
  145. data/pgpool2/pcp/pcp_stop_pgpool.c +179 -0
  146. data/pgpool2/pcp/pcp_stream.c +385 -0
  147. data/pgpool2/pcp/pcp_stream.h +52 -0
  148. data/pgpool2/pcp/pcp_systemdb_info.c +194 -0
  149. data/pgpool2/pcp/pcp_watchdog_info.c +211 -0
  150. data/pgpool2/pcp_child.c +1493 -0
  151. data/pgpool2/pg_md5.c +305 -0
  152. data/pgpool2/pgpool.8.in +121 -0
  153. data/pgpool2/pgpool.conf +553 -0
  154. data/pgpool2/pgpool.conf.sample +666 -0
  155. data/pgpool2/pgpool.conf.sample-master-slave +665 -0
  156. data/pgpool2/pgpool.conf.sample-replication +664 -0
  157. data/pgpool2/pgpool.conf.sample-stream +664 -0
  158. data/pgpool2/pgpool.spec +264 -0
  159. data/pgpool2/pgpool_adm/TODO +7 -0
  160. data/pgpool2/pgpool_adm/pgpool_adm--1.0.sql +85 -0
  161. data/pgpool2/pgpool_adm/pgpool_adm.c +558 -0
  162. data/pgpool2/pgpool_adm/pgpool_adm.control +5 -0
  163. data/pgpool2/pgpool_adm/pgpool_adm.h +46 -0
  164. data/pgpool2/pgpool_adm/pgpool_adm.sql.in +85 -0
  165. data/pgpool2/pool.h +655 -0
  166. data/pgpool2/pool_auth.c +1390 -0
  167. data/pgpool2/pool_config.c +5007 -0
  168. data/pgpool2/pool_config.h +284 -0
  169. data/pgpool2/pool_config.l +3281 -0
  170. data/pgpool2/pool_config_md5.c +29 -0
  171. data/pgpool2/pool_connection_pool.c +812 -0
  172. data/pgpool2/pool_error.c +242 -0
  173. data/pgpool2/pool_globals.c +27 -0
  174. data/pgpool2/pool_hba.c +1723 -0
  175. data/pgpool2/pool_hba.conf.sample +67 -0
  176. data/pgpool2/pool_ip.c +567 -0
  177. data/pgpool2/pool_ip.h +65 -0
  178. data/pgpool2/pool_ipc.h +38 -0
  179. data/pgpool2/pool_lobj.c +242 -0
  180. data/pgpool2/pool_lobj.h +32 -0
  181. data/pgpool2/pool_memqcache.c +3818 -0
  182. data/pgpool2/pool_memqcache.h +268 -0
  183. data/pgpool2/pool_params.c +163 -0
  184. data/pgpool2/pool_passwd.c +249 -0
  185. data/pgpool2/pool_passwd.h +41 -0
  186. data/pgpool2/pool_path.c +193 -0
  187. data/pgpool2/pool_path.h +81 -0
  188. data/pgpool2/pool_process_context.c +247 -0
  189. data/pgpool2/pool_process_context.h +62 -0
  190. data/pgpool2/pool_process_query.c +5001 -0
  191. data/pgpool2/pool_process_reporting.c +1671 -0
  192. data/pgpool2/pool_process_reporting.h +44 -0
  193. data/pgpool2/pool_proto2.c +671 -0
  194. data/pgpool2/pool_proto_modules.c +3524 -0
  195. data/pgpool2/pool_proto_modules.h +185 -0
  196. data/pgpool2/pool_query_cache.c +1020 -0
  197. data/pgpool2/pool_query_context.c +1871 -0
  198. data/pgpool2/pool_query_context.h +105 -0
  199. data/pgpool2/pool_relcache.c +284 -0
  200. data/pgpool2/pool_relcache.h +78 -0
  201. data/pgpool2/pool_rewrite_outfuncs.c +9060 -0
  202. data/pgpool2/pool_rewrite_query.c +715 -0
  203. data/pgpool2/pool_rewrite_query.h +192 -0
  204. data/pgpool2/pool_select_walker.c +1150 -0
  205. data/pgpool2/pool_select_walker.h +68 -0
  206. data/pgpool2/pool_sema.c +161 -0
  207. data/pgpool2/pool_session_context.c +952 -0
  208. data/pgpool2/pool_session_context.h +203 -0
  209. data/pgpool2/pool_shmem.c +185 -0
  210. data/pgpool2/pool_signal.c +158 -0
  211. data/pgpool2/pool_signal.h +61 -0
  212. data/pgpool2/pool_ssl.c +339 -0
  213. data/pgpool2/pool_stream.c +962 -0
  214. data/pgpool2/pool_stream.h +61 -0
  215. data/pgpool2/pool_system.c +659 -0
  216. data/pgpool2/pool_timestamp.c +1215 -0
  217. data/pgpool2/pool_timestamp.h +38 -0
  218. data/pgpool2/pool_type.h +171 -0
  219. data/pgpool2/pool_worker_child.c +384 -0
  220. data/pgpool2/ps_status.c +404 -0
  221. data/pgpool2/recovery.c +435 -0
  222. data/pgpool2/redhat/pgpool.conf.sample.patch +52 -0
  223. data/pgpool2/redhat/pgpool.init +201 -0
  224. data/pgpool2/redhat/pgpool.sysconfig +7 -0
  225. data/pgpool2/redhat/rpm_installer/basebackup-replication.sh +53 -0
  226. data/pgpool2/redhat/rpm_installer/basebackup-stream.sh +55 -0
  227. data/pgpool2/redhat/rpm_installer/config_for_script +17 -0
  228. data/pgpool2/redhat/rpm_installer/failover.sh +64 -0
  229. data/pgpool2/redhat/rpm_installer/getsources.sh +141 -0
  230. data/pgpool2/redhat/rpm_installer/install.sh +1363 -0
  231. data/pgpool2/redhat/rpm_installer/pgpool_recovery_pitr +47 -0
  232. data/pgpool2/redhat/rpm_installer/pgpool_remote_start +15 -0
  233. data/pgpool2/redhat/rpm_installer/recovery.conf +4 -0
  234. data/pgpool2/redhat/rpm_installer/uninstall.sh +57 -0
  235. data/pgpool2/sample/dist_def_pgbench.sql +73 -0
  236. data/pgpool2/sample/pgpool.pam +3 -0
  237. data/pgpool2/sample/pgpool_recovery +20 -0
  238. data/pgpool2/sample/pgpool_recovery_pitr +19 -0
  239. data/pgpool2/sample/pgpool_remote_start +13 -0
  240. data/pgpool2/sample/replicate_def_pgbench.sql +18 -0
  241. data/pgpool2/sql/insert_lock.sql +15 -0
  242. data/pgpool2/sql/pgpool-recovery/pgpool-recovery.c +280 -0
  243. data/pgpool2/sql/pgpool-recovery/pgpool-recovery.sql.in +19 -0
  244. data/pgpool2/sql/pgpool-recovery/pgpool_recovery--1.0.sql +24 -0
  245. data/pgpool2/sql/pgpool-recovery/pgpool_recovery.control +5 -0
  246. data/pgpool2/sql/pgpool-recovery/uninstall_pgpool-recovery.sql +3 -0
  247. data/pgpool2/sql/pgpool-regclass/pgpool-regclass.c +206 -0
  248. data/pgpool2/sql/pgpool-regclass/pgpool-regclass.sql.in +4 -0
  249. data/pgpool2/sql/pgpool-regclass/pgpool_regclass--1.0.sql +7 -0
  250. data/pgpool2/sql/pgpool-regclass/pgpool_regclass.control +5 -0
  251. data/pgpool2/sql/pgpool-regclass/uninstall_pgpool-regclass.sql +1 -0
  252. data/pgpool2/sql/system_db.sql +38 -0
  253. data/pgpool2/strlcpy.c +85 -0
  254. data/pgpool2/test/C/test_extended.c +98 -0
  255. data/pgpool2/test/jdbc/.cvsignore +2 -0
  256. data/pgpool2/test/jdbc/AutoCommitTest.java +45 -0
  257. data/pgpool2/test/jdbc/BatchTest.java +55 -0
  258. data/pgpool2/test/jdbc/ColumnTest.java +60 -0
  259. data/pgpool2/test/jdbc/CreateTempTableTest.java +48 -0
  260. data/pgpool2/test/jdbc/InsertTest.java +34 -0
  261. data/pgpool2/test/jdbc/LockTest.java +36 -0
  262. data/pgpool2/test/jdbc/PgpoolTest.java +75 -0
  263. data/pgpool2/test/jdbc/README.euc_jp +73 -0
  264. data/pgpool2/test/jdbc/RunTest.java +83 -0
  265. data/pgpool2/test/jdbc/SelectTest.java +37 -0
  266. data/pgpool2/test/jdbc/UpdateTest.java +32 -0
  267. data/pgpool2/test/jdbc/expected/CreateTempTable +1 -0
  268. data/pgpool2/test/jdbc/expected/autocommit +10 -0
  269. data/pgpool2/test/jdbc/expected/batch +1 -0
  270. data/pgpool2/test/jdbc/expected/column +100 -0
  271. data/pgpool2/test/jdbc/expected/insert +1 -0
  272. data/pgpool2/test/jdbc/expected/lock +100 -0
  273. data/pgpool2/test/jdbc/expected/select +2 -0
  274. data/pgpool2/test/jdbc/expected/update +1 -0
  275. data/pgpool2/test/jdbc/pgpool.properties +7 -0
  276. data/pgpool2/test/jdbc/prepare.sql +54 -0
  277. data/pgpool2/test/jdbc/run.sh +6 -0
  278. data/pgpool2/test/parser/.cvsignore +6 -0
  279. data/pgpool2/test/parser/README +32 -0
  280. data/pgpool2/test/parser/expected/copy.out +17 -0
  281. data/pgpool2/test/parser/expected/create.out +64 -0
  282. data/pgpool2/test/parser/expected/cursor.out +37 -0
  283. data/pgpool2/test/parser/expected/delete.out +10 -0
  284. data/pgpool2/test/parser/expected/drop.out +12 -0
  285. data/pgpool2/test/parser/expected/insert.out +13 -0
  286. data/pgpool2/test/parser/expected/misc.out +28 -0
  287. data/pgpool2/test/parser/expected/prepare.out +4 -0
  288. data/pgpool2/test/parser/expected/privileges.out +31 -0
  289. data/pgpool2/test/parser/expected/scanner.out +30 -0
  290. data/pgpool2/test/parser/expected/select.out +89 -0
  291. data/pgpool2/test/parser/expected/transaction.out +38 -0
  292. data/pgpool2/test/parser/expected/update.out +11 -0
  293. data/pgpool2/test/parser/expected/v84.out +37 -0
  294. data/pgpool2/test/parser/expected/v90.out +25 -0
  295. data/pgpool2/test/parser/expected/var.out +22 -0
  296. data/pgpool2/test/parser/input/alter.sql +2 -0
  297. data/pgpool2/test/parser/input/copy.sql +17 -0
  298. data/pgpool2/test/parser/input/create.sql +64 -0
  299. data/pgpool2/test/parser/input/cursor.sql +37 -0
  300. data/pgpool2/test/parser/input/delete.sql +10 -0
  301. data/pgpool2/test/parser/input/drop.sql +12 -0
  302. data/pgpool2/test/parser/input/insert.sql +13 -0
  303. data/pgpool2/test/parser/input/misc.sql +28 -0
  304. data/pgpool2/test/parser/input/prepare.sql +4 -0
  305. data/pgpool2/test/parser/input/privileges.sql +31 -0
  306. data/pgpool2/test/parser/input/scanner.sql +34 -0
  307. data/pgpool2/test/parser/input/select.sql +89 -0
  308. data/pgpool2/test/parser/input/transaction.sql +38 -0
  309. data/pgpool2/test/parser/input/update.sql +11 -0
  310. data/pgpool2/test/parser/input/v84.sql +37 -0
  311. data/pgpool2/test/parser/input/v90.sql +38 -0
  312. data/pgpool2/test/parser/input/var.sql +22 -0
  313. data/pgpool2/test/parser/main.c +96 -0
  314. data/pgpool2/test/parser/parse_schedule +16 -0
  315. data/pgpool2/test/parser/pool.h +13 -0
  316. data/pgpool2/test/parser/run-test +62 -0
  317. data/pgpool2/test/pdo-test/README.euc_jp +58 -0
  318. data/pgpool2/test/pdo-test/SQLlist/test1.sql +3 -0
  319. data/pgpool2/test/pdo-test/SQLlist/test2.sql +3 -0
  320. data/pgpool2/test/pdo-test/collections.inc +11 -0
  321. data/pgpool2/test/pdo-test/def.inc +7 -0
  322. data/pgpool2/test/pdo-test/log.txt +0 -0
  323. data/pgpool2/test/pdo-test/mod/database.inc +36 -0
  324. data/pgpool2/test/pdo-test/mod/def.inc +0 -0
  325. data/pgpool2/test/pdo-test/mod/errorhandler.inc +27 -0
  326. data/pgpool2/test/pdo-test/pdotest.php +11 -0
  327. data/pgpool2/test/pdo-test/regsql.inc +56 -0
  328. data/pgpool2/test/pgpool_setup +898 -0
  329. data/pgpool2/test/regression/README +39 -0
  330. data/pgpool2/test/regression/clean.sh +21 -0
  331. data/pgpool2/test/regression/libs.sh +16 -0
  332. data/pgpool2/test/regression/regress.sh +166 -0
  333. data/pgpool2/test/regression/tests/001.load_balance/test.sh +128 -0
  334. data/pgpool2/test/regression/tests/002.native_replication/PgTester.java +47 -0
  335. data/pgpool2/test/regression/tests/002.native_replication/create.sql +6 -0
  336. data/pgpool2/test/regression/tests/002.native_replication/test.sh +71 -0
  337. data/pgpool2/test/regression/tests/003.failover/expected.r +6 -0
  338. data/pgpool2/test/regression/tests/003.failover/expected.s +6 -0
  339. data/pgpool2/test/regression/tests/003.failover/test.sh +45 -0
  340. data/pgpool2/test/regression/tests/004.watchdog/master.conf +12 -0
  341. data/pgpool2/test/regression/tests/004.watchdog/standby.conf +19 -0
  342. data/pgpool2/test/regression/tests/004.watchdog/test.sh +52 -0
  343. data/pgpool2/test/regression/tests/050.bug58/test.sh +50 -0
  344. data/pgpool2/test/regression/tests/051.bug60/bug.sql +12 -0
  345. data/pgpool2/test/regression/tests/051.bug60/database-clean.sql +6 -0
  346. data/pgpool2/test/regression/tests/051.bug60/database-setup.sql +28 -0
  347. data/pgpool2/test/regression/tests/051.bug60/test.sh +79 -0
  348. data/pgpool2/test/regression/tests/052.do_query/test.sh +44 -0
  349. data/pgpool2/test/regression/tests/053.insert_lock_hangs/test.sh +81 -0
  350. data/pgpool2/test/regression/tests/054.postgres_fdw/test.sh +67 -0
  351. data/pgpool2/test/regression/tests/055.backend_all_down/test.sh +52 -0
  352. data/pgpool2/test/regression/tests/056.bug63/jdbctest2.java +66 -0
  353. data/pgpool2/test/regression/tests/056.bug63/test.sh +47 -0
  354. data/pgpool2/test/regression/tests/057.bug61/test.sh +40 -0
  355. data/pgpool2/test/regression/tests/058.bug68/jdbctest3.java +45 -0
  356. data/pgpool2/test/regression/tests/058.bug68/test.sh +47 -0
  357. data/pgpool2/test/timestamp/expected/insert.out +16 -0
  358. data/pgpool2/test/timestamp/expected/misc.out +3 -0
  359. data/pgpool2/test/timestamp/expected/update.out +6 -0
  360. data/pgpool2/test/timestamp/input/insert.sql +16 -0
  361. data/pgpool2/test/timestamp/input/misc.sql +3 -0
  362. data/pgpool2/test/timestamp/input/update.sql +6 -0
  363. data/pgpool2/test/timestamp/main.c +129 -0
  364. data/pgpool2/test/timestamp/parse_schedule +3 -0
  365. data/pgpool2/test/timestamp/run-test +69 -0
  366. data/pgpool2/version.h +1 -0
  367. data/pgpool2/watchdog/Makefile.am +17 -0
  368. data/pgpool2/watchdog/Makefile.in +505 -0
  369. data/pgpool2/watchdog/test/stab.c +266 -0
  370. data/pgpool2/watchdog/test/test.c +85 -0
  371. data/pgpool2/watchdog/test/wd_child_t.c +87 -0
  372. data/pgpool2/watchdog/test/wd_lifecheck_t.c +87 -0
  373. data/pgpool2/watchdog/test/wd_packet_t.c +87 -0
  374. data/pgpool2/watchdog/test/wd_ping_t.c +20 -0
  375. data/pgpool2/watchdog/watchdog.c +408 -0
  376. data/pgpool2/watchdog/watchdog.h +209 -0
  377. data/pgpool2/watchdog/wd_child.c +444 -0
  378. data/pgpool2/watchdog/wd_ext.h +123 -0
  379. data/pgpool2/watchdog/wd_heartbeat.c +577 -0
  380. data/pgpool2/watchdog/wd_if.c +216 -0
  381. data/pgpool2/watchdog/wd_init.c +126 -0
  382. data/pgpool2/watchdog/wd_interlock.c +347 -0
  383. data/pgpool2/watchdog/wd_lifecheck.c +512 -0
  384. data/pgpool2/watchdog/wd_list.c +429 -0
  385. data/pgpool2/watchdog/wd_packet.c +1159 -0
  386. data/pgpool2/watchdog/wd_ping.c +330 -0
  387. data/pgpool2/ylwrap +223 -0
  388. data/pgsql/presto_client.py +346 -0
  389. data/pgsql/prestogres.py +156 -0
  390. data/pgsql/setup_functions.sql +21 -0
  391. data/pgsql/setup_language.sql +3 -0
  392. data/prestogres.gemspec +23 -0
  393. 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
+ }