prestogres 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }