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,3524 @@
1
+ /* -*-pgsql-c-*- */
2
+ /*
3
+ * $Header$
4
+ *
5
+ * pgpool: a language independent connection pool server for PostgreSQL
6
+ * written by Tatsuo Ishii
7
+ *
8
+ * Copyright (c) 2003-2013 PgPool Global Development Group
9
+ *
10
+ * Permission to use, copy, modify, and distribute this software and
11
+ * its documentation for any purpose and without fee is hereby
12
+ * granted, provided that the above copyright notice appear in all
13
+ * copies and that both that copyright notice and this permission
14
+ * notice appear in supporting documentation, and that the name of the
15
+ * author not be used in advertising or publicity pertaining to
16
+ * distribution of the software without specific, written prior
17
+ * permission. The author makes no representations about the
18
+ * suitability of this software for any purpose. It is provided "as
19
+ * is" without express or implied warranty.
20
+ *
21
+ *---------------------------------------------------------------------
22
+ * pool_proto_modules.c: modules corresponding to message protocols.
23
+ * used by pool_process_query()
24
+ *---------------------------------------------------------------------
25
+ */
26
+ #include "config.h"
27
+ #include <errno.h>
28
+
29
+ #ifdef HAVE_SYS_TYPES_H
30
+ #include <sys/types.h>
31
+ #endif
32
+ #ifdef HAVE_SYS_TIME_H
33
+ #include <sys/time.h>
34
+ #endif
35
+ #ifdef HAVE_SYS_SELECT_H
36
+ #include <sys/select.h>
37
+ #endif
38
+
39
+
40
+ #include <stdlib.h>
41
+ #include <unistd.h>
42
+ #include <string.h>
43
+ #include <netinet/in.h>
44
+ #include <ctype.h>
45
+
46
+ #include "pool.h"
47
+ #include "pool_signal.h"
48
+ #include "pool_timestamp.h"
49
+ #include "pool_proto_modules.h"
50
+ #include "pool_rewrite_query.h"
51
+ #include "pool_relcache.h"
52
+ #include "pool_stream.h"
53
+ #include "pool_config.h"
54
+ #include "parser/pool_string.h"
55
+ #include "pool_session_context.h"
56
+ #include "pool_query_context.h"
57
+ #include "pool_lobj.h"
58
+ #include "pool_select_walker.h"
59
+ #include "pool_memqcache.h"
60
+
61
+ char *copy_table = NULL; /* copy table name */
62
+ char *copy_schema = NULL; /* copy table name */
63
+ char copy_delimiter; /* copy delimiter char */
64
+ char *copy_null = NULL; /* copy null string */
65
+
66
+ /*
67
+ * Non 0 if allow to close internal transaction. This variable was
68
+ * introduced on 2008/4/3 not to close an internal transaction when
69
+ * Sync message is received after receiving Parse message. This hack
70
+ * is for PHP-PDO.
71
+ */
72
+ static int allow_close_transaction = 1;
73
+
74
+ int is_select_pgcatalog = 0;
75
+ int is_select_for_update = 0; /* 1 if SELECT INTO or SELECT FOR UPDATE */
76
+ bool is_parallel_table = false;
77
+
78
+ /*
79
+ * last query string sent to simpleQuery()
80
+ */
81
+ char query_string_buffer[QUERY_STRING_BUFFER_LEN];
82
+
83
+ /*
84
+ * query string produced by nodeToString() in simpleQuery().
85
+ * this variable only useful when enable_query_cache is true.
86
+ */
87
+ char *parsed_query = NULL;
88
+
89
+ static int check_errors(POOL_CONNECTION_POOL *backend, int backend_id);
90
+ static void generate_error_message(char *prefix, int specific_error, char *query);
91
+ static POOL_STATUS parse_before_bind(POOL_CONNECTION *frontend,
92
+ POOL_CONNECTION_POOL *backend,
93
+ POOL_SENT_MESSAGE *message);
94
+ static int* find_victim_nodes(int *ntuples, int nmembers, int master_node, int *number_of_nodes);
95
+ static int extract_ntuples(char *message);
96
+ static POOL_STATUS close_standby_transactions(POOL_CONNECTION *frontend,
97
+ POOL_CONNECTION_POOL *backend);
98
+
99
+ /*
100
+ * Process Query('Q') message
101
+ * Query messages include an SQL string.
102
+ */
103
+ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend,
104
+ POOL_CONNECTION_POOL *backend, int len, char *contents)
105
+ {
106
+ static char *sq_config = "pool_status";
107
+ static char *sq_pools = "pool_pools";
108
+ static char *sq_processes = "pool_processes";
109
+ static char *sq_nodes = "pool_nodes";
110
+ static char *sq_version = "pool_version";
111
+ static char *sq_cache = "pool_cache";
112
+ int commit;
113
+ List *parse_tree_list;
114
+ Node *node = NULL;
115
+ POOL_STATUS status;
116
+ char *string;
117
+ int lock_kind;
118
+ bool is_likely_select = false;
119
+ int specific_error = 0;
120
+
121
+ POOL_SESSION_CONTEXT *session_context;
122
+ POOL_QUERY_CONTEXT *query_context;
123
+ POOL_MEMORY_POOL *old_context;
124
+
125
+ /* Get session context */
126
+ session_context = pool_get_session_context();
127
+ if (!session_context)
128
+ {
129
+ pool_error("SimpleQuery: cannot get session context");
130
+ return POOL_END;
131
+ }
132
+
133
+ /* save last query string for logging purpose */
134
+ strlcpy(query_string_buffer, contents, sizeof(query_string_buffer));
135
+
136
+ /* show ps status */
137
+ query_ps_status(contents, backend);
138
+
139
+ /* log query to log file if necessary */
140
+ if (pool_config->log_statement)
141
+ {
142
+ pool_log("statement: %s", contents);
143
+ }
144
+ else
145
+ {
146
+ pool_debug("statement2: %s", contents);
147
+ }
148
+
149
+ /*
150
+ * Fetch memory cache if possible
151
+ */
152
+ is_likely_select = pool_is_likely_select(contents);
153
+
154
+ /*
155
+ * If memory query cache enabled and the query seems to be a
156
+ * SELECT use query cache if possible. However if we are in an
157
+ * explicit transaction and we had writing query before, we should
158
+ * not use query cache. This means that even the writing query is
159
+ * not anything related to the table which is used the SELECT, we
160
+ * do not use cache. Of course we could analyze the SELECT to see
161
+ * if it uses the table modified in the transaction, but it will
162
+ * need parsing query and accessing to system catalog, which will
163
+ * add significant overhead. Moreover if we are in aborted
164
+ * transaction, commands should be ignored, so we should not use
165
+ * query cache.
166
+ */
167
+ if (pool_config->memory_cache_enabled && is_likely_select &&
168
+ !pool_is_writing_transaction() &&
169
+ TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID) != 'E')
170
+ {
171
+ bool foundp;
172
+
173
+ /* If the query is SELECT from table to cache, try to fetch cached result. */
174
+ status = pool_fetch_from_memory_cache(frontend, backend, contents, &foundp);
175
+
176
+ if (status != POOL_CONTINUE)
177
+ return status;
178
+
179
+ if (foundp)
180
+ {
181
+ pool_ps_idle_display(backend);
182
+ pool_set_skip_reading_from_backends();
183
+ pool_stats_count_up_num_cache_hits();
184
+ return POOL_CONTINUE;
185
+ }
186
+ }
187
+
188
+ /* Create query context */
189
+ query_context = pool_init_query_context();
190
+ if (!query_context)
191
+ {
192
+ pool_error("SimpleQuery: pool_init_query_context failed");
193
+ return POOL_END;
194
+ }
195
+
196
+ /* switch memory context */
197
+ if (pool_memory == NULL)
198
+ pool_memory = pool_memory_create(PARSER_BLOCK_SIZE);
199
+ old_context = pool_memory_context_switch_to(query_context->memory_context);
200
+
201
+ /* parse SQL string */
202
+ parse_tree_list = raw_parser(contents);
203
+
204
+ if (parse_tree_list == NIL)
205
+ {
206
+ /* is the query empty? */
207
+ if (*contents == '\0' || *contents == ';')
208
+ {
209
+ /*
210
+ * JBoss sends empty queries for checking connections.
211
+ * We replace the empty query with SELECT command not
212
+ * to affect load balance.
213
+ * [Pgpool-general] Confused about JDBC and load balancing
214
+ */
215
+ parse_tree_list = raw_parser(POOL_DUMMY_READ_QUERY);
216
+ }
217
+ else
218
+ {
219
+ /*
220
+ * Unable to parse the query. Probably syntax error or the
221
+ * query is too new and our parser cannot understand. Treat as
222
+ * if it were an DELETE command. Note that the DELETE command
223
+ * does not execute, instead the original query will be sent
224
+ * to backends, which may or may not cause an actual syntax errors.
225
+ * The command will be sent to all backends in replication mode
226
+ * or master/primary in master/slave mode.
227
+ */
228
+ if (!strcmp(remote_host, "[local]"))
229
+ {
230
+ pool_log("SimpleQuery: Unable to parse the query: \"%s\" from local client", contents);
231
+ }
232
+ else
233
+ {
234
+ pool_log("SimpleQuery: Unable to parse the query: \"%s\" from client %s(%s)", contents, remote_host, remote_port);
235
+ }
236
+ parse_tree_list = raw_parser(POOL_DUMMY_WRITE_QUERY);
237
+ query_context->is_parse_error = true;
238
+ }
239
+ }
240
+
241
+ if (parse_tree_list != NIL)
242
+ {
243
+ /*
244
+ * XXX: Currently we only process the first element of the parse tree.
245
+ * rest of multiple statements are silently discarded.
246
+ */
247
+ node = (Node *) lfirst(list_head(parse_tree_list));
248
+
249
+ if (pool_config->enable_query_cache &&
250
+ SYSDB_STATUS == CON_UP &&
251
+ IsA(node, SelectStmt) &&
252
+ !(is_select_pgcatalog = IsSelectpgcatalog(node, backend)))
253
+ {
254
+ /*
255
+ * POOL_CONTINUE of here represent cache found, and messages were
256
+ * sent to frontend already.
257
+ */
258
+ if (pool_execute_query_cache_lookup(frontend, backend, node) == POOL_CONTINUE)
259
+ {
260
+ pool_query_context_destroy(query_context);
261
+ pool_set_skip_reading_from_backends();
262
+ pool_memory_context_switch_to(old_context);
263
+ return POOL_CONTINUE;
264
+ }
265
+ }
266
+
267
+ /*
268
+ * Start query context
269
+ */
270
+ pool_start_query(query_context, contents, len, node);
271
+
272
+ /*
273
+ * If the query is DROP DATABASE, after executing it, cache files directory must be discarded.
274
+ * So we have to get the DB's oid before it will be DROPped.
275
+ */
276
+ if (pool_config->memory_cache_enabled && is_drop_database(node))
277
+ {
278
+ DropdbStmt *stmt = (DropdbStmt *)node;
279
+ query_context->dboid = pool_get_database_oid_from_dbname(stmt->dbname);
280
+ if (query_context->dboid != 0)
281
+ {
282
+ pool_debug("DB's oid to discard its cache directory: dboid = %d", query_context->dboid);
283
+ }
284
+ }
285
+
286
+ /*
287
+ * Check if multi statement query
288
+ */
289
+ if (parse_tree_list && list_length(parse_tree_list) > 1)
290
+ {
291
+ query_context->is_multi_statement = true;
292
+ }
293
+ else
294
+ {
295
+ query_context->is_multi_statement = false;
296
+ }
297
+
298
+ if (PARALLEL_MODE)
299
+ {
300
+ bool parallel = true;
301
+
302
+ is_parallel_table = is_partition_table(backend,node);
303
+ status = pool_do_parallel_query(frontend, backend, node, &parallel, &contents, &len);
304
+ if (parallel)
305
+ {
306
+ pool_query_context_destroy(query_context);
307
+ pool_memory_context_switch_to(old_context);
308
+ return status;
309
+ }
310
+ }
311
+
312
+ /* check COPY FROM STDIN
313
+ * if true, set copy_* variable
314
+ */
315
+ check_copy_from_stdin(node);
316
+
317
+ /* status reporting? */
318
+ if (IsA(node, VariableShowStmt))
319
+ {
320
+ bool is_valid_show_command = false;
321
+ VariableShowStmt *vnode = (VariableShowStmt *)node;
322
+
323
+ if (!strcmp(sq_config, vnode->name))
324
+ {
325
+ is_valid_show_command = true;
326
+ pool_debug("config reporting");
327
+ config_reporting(frontend, backend);
328
+ }
329
+ else if (!strcmp(sq_pools, vnode->name))
330
+ {
331
+ is_valid_show_command = true;
332
+ pool_debug("pools reporting");
333
+ pools_reporting(frontend, backend);
334
+ }
335
+ else if (!strcmp(sq_processes, vnode->name))
336
+ {
337
+ is_valid_show_command = true;
338
+ pool_debug("processes reporting");
339
+ processes_reporting(frontend, backend);
340
+ }
341
+ else if (!strcmp(sq_nodes, vnode->name))
342
+ {
343
+ is_valid_show_command = true;
344
+ pool_debug("nodes reporting");
345
+ nodes_reporting(frontend, backend);
346
+ }
347
+ else if (!strcmp(sq_version, vnode->name))
348
+ {
349
+ is_valid_show_command = true;
350
+ pool_debug("version reporting");
351
+ version_reporting(frontend, backend);
352
+ }
353
+ else if (!strcmp(sq_cache, vnode->name))
354
+ {
355
+ is_valid_show_command = true;
356
+ pool_debug("cache reporting");
357
+ cache_reporting(frontend, backend);
358
+ }
359
+
360
+ if (is_valid_show_command)
361
+ {
362
+ pool_ps_idle_display(backend);
363
+ pool_query_context_destroy(query_context);
364
+ pool_set_skip_reading_from_backends();
365
+ pool_memory_context_switch_to(old_context);
366
+ return POOL_CONTINUE;
367
+ }
368
+ }
369
+
370
+ /*
371
+ * If the table is to be cached, set is_cache_safe TRUE and register table oids.
372
+ */
373
+ if (pool_config->memory_cache_enabled && query_context->is_multi_statement == false)
374
+ {
375
+ bool is_select_query = false;
376
+ int num_oids;
377
+ int *oids;
378
+ int i;
379
+
380
+ /* Check if the query is actually SELECT */
381
+ if (is_likely_select && IsA(node, SelectStmt))
382
+ {
383
+ is_select_query = true;
384
+ }
385
+
386
+ /* Switch the flag of is_cache_safe in session_context */
387
+ if (is_select_query && !query_context->is_parse_error &&
388
+ pool_is_allow_to_cache(query_context->parse_tree,
389
+ query_context->original_query))
390
+ {
391
+ pool_set_cache_safe();
392
+ }
393
+ else
394
+ {
395
+ pool_unset_cache_safe();
396
+ }
397
+
398
+ /* If table is to be cached and the query is DML, save the table oid */
399
+ if (!is_select_query && !query_context->is_parse_error)
400
+ {
401
+ num_oids = pool_extract_table_oids(node, &oids);
402
+
403
+ if (num_oids > 0)
404
+ {
405
+ /* Save to oid buffer */
406
+ for (i=0;i<num_oids;i++)
407
+ {
408
+ pool_add_dml_table_oid(oids[i]);
409
+ }
410
+ }
411
+ }
412
+ }
413
+
414
+ /*
415
+ * Decide where to send query
416
+ */
417
+ pool_where_to_send(query_context, query_context->original_query,
418
+ query_context->parse_tree);
419
+
420
+ /*
421
+ * if this is DROP DATABASE command, send USR1 signal to parent and
422
+ * ask it to close all idle connections.
423
+ * XXX This is overkill. It would be better to close the idle
424
+ * connection for the database which DROP DATABASE command tries
425
+ * to drop. This is impossible at this point, since we have no way
426
+ * to pass such info to other processes.
427
+ */
428
+ if (is_drop_database(node))
429
+ {
430
+ int stime = 5; /* XXX give arbitrary time to allow closing idle connections */
431
+
432
+ pool_debug("Query: sending SIGUSR1 signal to parent");
433
+
434
+ Req_info->kind = CLOSE_IDLE_REQUEST;
435
+ kill(getppid(), SIGUSR1); /* send USR1 signal to parent */
436
+
437
+ /* we need to loop over here since we will get USR1 signal while sleeping */
438
+ while (stime > 0)
439
+ {
440
+ stime = sleep(stime);
441
+ }
442
+ }
443
+
444
+ /*
445
+ * determine if we need to lock the table
446
+ * to keep SERIAL data consistency among servers
447
+ * conditions:
448
+ * - replication is enabled
449
+ * - protocol is V3
450
+ * - statement is INSERT
451
+ * - either "INSERT LOCK" comment exists or insert_lock directive specified
452
+ */
453
+ if (!RAW_MODE)
454
+ {
455
+ /*
456
+ * If there's only one node to send the command, there's no
457
+ * point to start a transaction.
458
+ */
459
+ if (pool_multi_node_to_be_sent(query_context))
460
+ {
461
+ /* start a transaction if needed */
462
+ if (start_internal_transaction(frontend, backend, (Node *)node) != POOL_CONTINUE)
463
+ return POOL_END;
464
+
465
+ /* check if need lock */
466
+ lock_kind = need_insert_lock(backend, contents, node);
467
+ if (lock_kind)
468
+ {
469
+ /* if so, issue lock command */
470
+ status = insert_lock(frontend, backend, contents, (InsertStmt *)node, lock_kind);
471
+ if (status != POOL_CONTINUE)
472
+ {
473
+ pool_query_context_destroy(query_context);
474
+ return status;
475
+ }
476
+ }
477
+ }
478
+ }
479
+ else if (REPLICATION && contents == NULL && start_internal_transaction(frontend, backend, node))
480
+ {
481
+ pool_query_context_destroy(query_context);
482
+ return POOL_ERROR;
483
+ }
484
+ }
485
+
486
+ if (MAJOR(backend) == PROTO_MAJOR_V2 && is_start_transaction_query(node))
487
+ {
488
+ int i;
489
+
490
+ for (i=0;i<NUM_BACKENDS;i++)
491
+ {
492
+ if(VALID_BACKEND(i))
493
+ TSTATE(backend, i) = 'T';
494
+ }
495
+ }
496
+
497
+ if (node)
498
+ {
499
+ POOL_SENT_MESSAGE *msg = NULL;
500
+
501
+ if (IsA(node, PrepareStmt))
502
+ {
503
+ msg = pool_create_sent_message('Q', len, contents, 0,
504
+ ((PrepareStmt *)node)->name,
505
+ query_context);
506
+ if (!msg)
507
+ {
508
+ pool_error("SimpleQuery: cannot create query message: %s", strerror(errno));
509
+ return POOL_END;
510
+ }
511
+ session_context->uncompleted_message = msg;
512
+ }
513
+ }
514
+
515
+ string = query_context->original_query;
516
+
517
+ if (!RAW_MODE)
518
+ {
519
+ /* check if query is "COMMIT" or "ROLLBACK" */
520
+ commit = is_commit_or_rollback_query(node);
521
+
522
+ /*
523
+ * Query is not commit/rollback
524
+ */
525
+ if (!commit)
526
+ {
527
+ char *rewrite_query;
528
+
529
+ if (node)
530
+ {
531
+ POOL_SENT_MESSAGE *msg = NULL;
532
+
533
+ if (IsA(node, PrepareStmt))
534
+ {
535
+ msg = session_context->uncompleted_message;
536
+ }
537
+ else if (IsA(node, ExecuteStmt))
538
+ {
539
+ msg = pool_get_sent_message('Q', ((ExecuteStmt *)node)->name);
540
+ if (!msg)
541
+ msg = pool_get_sent_message('P', ((ExecuteStmt *)node)->name);
542
+ }
543
+
544
+ /* rewrite `now()' to timestamp literal */
545
+ rewrite_query = rewrite_timestamp(backend, query_context->parse_tree, false, msg);
546
+
547
+ /*
548
+ * If the query is BEGIN READ WRITE or
549
+ * BEGIN ... SERIALIZABLE in master/slave mode,
550
+ * we send BEGIN to slaves/standbys instead.
551
+ * original_query which is BEGIN READ WRITE is sent to primary.
552
+ * rewritten_query which is BEGIN is sent to standbys.
553
+ */
554
+ if (pool_need_to_treat_as_if_default_transaction(query_context))
555
+ {
556
+ rewrite_query = pstrdup("BEGIN");
557
+ }
558
+
559
+ if (rewrite_query != NULL)
560
+ {
561
+ query_context->rewritten_query = rewrite_query;
562
+ query_context->rewritten_length = strlen(rewrite_query) + 1;
563
+ }
564
+ }
565
+
566
+ /*
567
+ * Optimization effort: If there's only one session, we do
568
+ * not need to wait for the master node's response, and
569
+ * could execute the query concurrently.
570
+ */
571
+ if (pool_config->num_init_children == 1)
572
+ {
573
+ /* Send query to all DB nodes at once */
574
+ status = pool_send_and_wait(query_context, 0, 0);
575
+ /* free_parser(); */
576
+ return status;
577
+ }
578
+
579
+ /* Send the query to master node */
580
+ if (pool_send_and_wait(query_context, 1, MASTER_NODE_ID) != POOL_CONTINUE)
581
+ {
582
+ pool_query_context_destroy(query_context);
583
+ return POOL_END;
584
+ }
585
+
586
+ /* Check specific errors */
587
+ specific_error = check_errors(backend, MASTER_NODE_ID);
588
+ if (specific_error)
589
+ {
590
+ /* log error message */
591
+ generate_error_message("SimpleQuery: ", specific_error, contents);
592
+ }
593
+ }
594
+
595
+ if (specific_error)
596
+ {
597
+ char msg[1024] = POOL_ERROR_QUERY; /* large enough */
598
+ int len = strlen(msg);
599
+
600
+ memset(msg + len, 0, sizeof(int));
601
+
602
+ /* send query to other nodes */
603
+ query_context->rewritten_query = msg;
604
+ query_context->rewritten_length = len;
605
+ if (pool_send_and_wait(query_context, -1, MASTER_NODE_ID) != POOL_CONTINUE)
606
+ return POOL_END;
607
+ }
608
+ else
609
+ {
610
+ /*
611
+ * Send the query to other than master node.
612
+ */
613
+ if (pool_send_and_wait(query_context, -1, MASTER_NODE_ID) != POOL_CONTINUE)
614
+ {
615
+ pool_query_context_destroy(query_context);
616
+ return POOL_END;
617
+ }
618
+ }
619
+
620
+ /* Send "COMMIT" or "ROLLBACK" to only master node if query is "COMMIT" or "ROLLBACK" */
621
+ if (commit)
622
+ {
623
+ if (pool_send_and_wait(query_context, 1, MASTER_NODE_ID) != POOL_CONTINUE)
624
+ {
625
+ pool_query_context_destroy(query_context);
626
+ return POOL_END;
627
+ }
628
+ }
629
+ /* free_parser(); */
630
+ }
631
+ else
632
+ {
633
+ if (pool_send_and_wait(query_context, 1, MASTER_NODE_ID) != POOL_CONTINUE)
634
+ {
635
+ pool_query_context_destroy(query_context);
636
+ return POOL_END;
637
+ }
638
+ /* free_parser(); */
639
+ }
640
+
641
+ /* switch memory context */
642
+ pool_memory_context_switch_to(old_context);
643
+
644
+ return POOL_CONTINUE;
645
+ }
646
+
647
+ /*
648
+ * process EXECUTE (V3 only)
649
+ */
650
+ POOL_STATUS Execute(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
651
+ int len, char *contents)
652
+ {
653
+ int commit = 0;
654
+ char *query = NULL;
655
+ Node *node;
656
+ int specific_error = 0;
657
+ POOL_SESSION_CONTEXT *session_context;
658
+ POOL_QUERY_CONTEXT *query_context;
659
+ POOL_SENT_MESSAGE *bind_msg;
660
+
661
+ /* Get session context */
662
+ session_context = pool_get_session_context();
663
+ if (!session_context)
664
+ {
665
+ pool_error("Execute: cannot get session context");
666
+ return POOL_END;
667
+ }
668
+
669
+ pool_debug("Execute: portal name <%s>", contents);
670
+
671
+ bind_msg = pool_get_sent_message('B', contents);
672
+ if (!bind_msg)
673
+ {
674
+ pool_error("Execute: cannot get bind message");
675
+ return POOL_END;
676
+ }
677
+ if(!bind_msg->query_context)
678
+ {
679
+ pool_error("Execute: cannot get query context");
680
+ return POOL_END;
681
+ }
682
+ if (!bind_msg->query_context->original_query)
683
+ {
684
+ pool_error("Execute: cannot get original query");
685
+ return POOL_END;
686
+ }
687
+ if (!bind_msg->query_context->parse_tree)
688
+ {
689
+ pool_error("Execute: cannot get parse tree");
690
+ return POOL_END;
691
+ }
692
+
693
+ query_context = bind_msg->query_context;
694
+ node = bind_msg->query_context->parse_tree;
695
+ query = bind_msg->query_context->original_query;
696
+
697
+ strlcpy(query_string_buffer, query, sizeof(query_string_buffer));
698
+
699
+ pool_debug("Execute: query string = <%s>", query);
700
+
701
+ /*
702
+ * Fetch memory cache if possible
703
+ */
704
+ if (pool_config->memory_cache_enabled && pool_is_likely_select(query))
705
+ {
706
+ bool foundp;
707
+ POOL_STATUS status;
708
+ char *search_query = NULL;
709
+ int len;
710
+ char *tmp;
711
+ #define STR_ALLOC_SIZE 1024
712
+
713
+ len = strlen(query)+1;
714
+ search_query = (char *)malloc(len);
715
+ if (search_query == NULL)
716
+ {
717
+ pool_error("Execute: malloc failed");
718
+ return POOL_END;
719
+ }
720
+ strcpy(search_query, query);
721
+
722
+ /*
723
+ * Add bind message's info to query to search.
724
+ */
725
+ if (query_context->is_cache_safe && bind_msg->param_offset && bind_msg->contents)
726
+ {
727
+ /* Extract binary contents from bind message */
728
+ char *query_in_bind_msg = bind_msg->contents + bind_msg->param_offset;
729
+ char hex_str[4]; /* 02X chars + white space + null end */
730
+ int i;
731
+ int alloc_len;
732
+
733
+ alloc_len = (len/STR_ALLOC_SIZE+1)*STR_ALLOC_SIZE;
734
+ search_query = realloc(search_query, alloc_len);
735
+ if (search_query == NULL)
736
+ {
737
+ pool_error("Execute: realloc failed");
738
+ return POOL_END;
739
+ }
740
+
741
+ for (i = 0; i < bind_msg->len - bind_msg->param_offset; i++)
742
+ {
743
+ int hexlen;
744
+
745
+ snprintf(hex_str, sizeof(hex_str), (i == 0) ? " %02X" : "%02X", 0xff & query_in_bind_msg[i]);
746
+ hexlen = strlen(hex_str);
747
+
748
+ if ((len+hexlen) >= alloc_len)
749
+ {
750
+ alloc_len += STR_ALLOC_SIZE;
751
+ search_query = realloc(search_query, alloc_len);
752
+ if (search_query == NULL)
753
+ {
754
+ pool_error("Execute: realloc failed");
755
+ return POOL_END;
756
+ }
757
+ }
758
+ strcat(search_query, hex_str);
759
+ len += hexlen;
760
+ }
761
+
762
+ query_context->query_w_hex = search_query;
763
+
764
+ /*
765
+ * When a transaction is committed, query_context->temp_cache->query is used
766
+ * to create md5 hash to search for query cache.
767
+ * So overwrite the query text in temp cache to the one with the hex of bind message.
768
+ * If not, md5 hash will be created by the query text without bind message, and
769
+ * it will happen to find cache never or to get a wrong result.
770
+ *
771
+ * However, It is possible that temp_cache does not exist.
772
+ * Consider following scenario:
773
+ * - In the previous execute cache is overflowed, and
774
+ * temp_cache discarded.
775
+ * - In the subsequent bind/execute uses the same portal
776
+ */
777
+ if (query_context->temp_cache)
778
+ {
779
+ tmp = (char *)malloc(sizeof(char) * strlen(search_query) + 1);
780
+ if (tmp == NULL)
781
+ {
782
+ pool_error("Execute: malloc failed");
783
+ return POOL_END;
784
+ }
785
+ free(query_context->temp_cache->query);
786
+ query_context->temp_cache->query = tmp;
787
+ strcpy(query_context->temp_cache->query, search_query);
788
+ }
789
+ }
790
+
791
+ /* If the query is SELECT from table to cache, try to fetch cached result. */
792
+ status = pool_fetch_from_memory_cache(frontend, backend, search_query, &foundp);
793
+
794
+ if (status != POOL_CONTINUE)
795
+ return status;
796
+
797
+ if (foundp)
798
+ {
799
+ pool_ps_idle_display(backend);
800
+ pool_set_skip_reading_from_backends();
801
+ pool_stats_count_up_num_cache_hits();
802
+ pool_unset_query_in_progress();
803
+ return POOL_CONTINUE;
804
+ }
805
+ }
806
+
807
+ session_context->query_context = query_context;
808
+ /*
809
+ * Calling pool_where_to_send here is dangerous because the node
810
+ * parse/bind has been sent could be change by
811
+ * pool_where_to_send() and it leads to "portal not found"
812
+ * etc. errors.
813
+ */
814
+
815
+ /* check if query is "COMMIT" or "ROLLBACK" */
816
+ commit = is_commit_or_rollback_query(node);
817
+
818
+ if (REPLICATION || PARALLEL_MODE)
819
+ {
820
+ /*
821
+ * Query is not commit/rollback
822
+ */
823
+ if (!commit)
824
+ {
825
+ /* Send the query to master node */
826
+ if (pool_extended_send_and_wait(query_context, "E", len, contents, 1, MASTER_NODE_ID) != POOL_CONTINUE)
827
+ {
828
+ return POOL_END;
829
+ }
830
+
831
+ /* Check specific errors */
832
+ specific_error = check_errors(backend, MASTER_NODE_ID);
833
+ if (specific_error)
834
+ {
835
+ /* log error message */
836
+ generate_error_message("Execute: ", specific_error, contents);
837
+ }
838
+ }
839
+
840
+ if (specific_error)
841
+ {
842
+ char msg[1024] = "pgpool_error_portal"; /* large enough */
843
+ int len = strlen(msg);
844
+
845
+ memset(msg + len, 0, sizeof(int));
846
+
847
+ /* send query to other nodes */
848
+ if (pool_extended_send_and_wait(query_context, "E", len, msg, -1, MASTER_NODE_ID) != POOL_CONTINUE)
849
+ return POOL_END;
850
+ }
851
+ else
852
+ {
853
+ if (pool_extended_send_and_wait(query_context, "E", len, contents, -1, MASTER_NODE_ID) != POOL_CONTINUE)
854
+ return POOL_END;
855
+ }
856
+
857
+ /* send "COMMIT" or "ROLLBACK" to only master node if query is "COMMIT" or "ROLLBACK" */
858
+ if (commit)
859
+ {
860
+ if (pool_extended_send_and_wait(query_context, "E", len, contents, 1, MASTER_NODE_ID) != POOL_CONTINUE)
861
+ {
862
+ return POOL_END;
863
+ }
864
+ }
865
+ }
866
+ else
867
+ {
868
+ if (pool_extended_send_and_wait(query_context, "E", len, contents, 1, MASTER_NODE_ID) != POOL_CONTINUE)
869
+ {
870
+ return POOL_END;
871
+ }
872
+ if (pool_extended_send_and_wait(query_context, "E", len, contents, -1, MASTER_NODE_ID) != POOL_CONTINUE)
873
+ {
874
+ return POOL_END;
875
+ }
876
+ }
877
+
878
+ return POOL_CONTINUE;
879
+ }
880
+
881
+ /*
882
+ * process Parse (V3 only)
883
+ */
884
+ POOL_STATUS Parse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
885
+ int len, char *contents)
886
+ {
887
+ int deadlock_detected = 0;
888
+ int insert_stmt_with_lock = 0;
889
+ char *name;
890
+ char *stmt;
891
+ List *parse_tree_list;
892
+ Node *node = NULL;
893
+ POOL_SENT_MESSAGE *msg;
894
+ POOL_STATUS status;
895
+ POOL_MEMORY_POOL *old_context;
896
+ POOL_SESSION_CONTEXT *session_context;
897
+ POOL_QUERY_CONTEXT *query_context;
898
+
899
+ /* Get session context */
900
+ session_context = pool_get_session_context();
901
+ if (!session_context)
902
+ {
903
+ pool_error("Parse: cannot get session context");
904
+ return POOL_END;
905
+ }
906
+
907
+ /* Create query context */
908
+ query_context = pool_init_query_context();
909
+
910
+ pool_debug("Parse: statement name <%s>", contents);
911
+
912
+ name = contents;
913
+ stmt = contents + strlen(contents) + 1;
914
+
915
+ /* switch memory context */
916
+ if (pool_memory == NULL)
917
+ pool_memory = pool_memory_create(PARSER_BLOCK_SIZE);
918
+ old_context = pool_memory_context_switch_to(query_context->memory_context);
919
+
920
+ /* parse SQL string */
921
+ parse_tree_list = raw_parser(stmt);
922
+
923
+ if (parse_tree_list == NIL)
924
+ {
925
+ /* is the query empty? */
926
+ if (*stmt == '\0' || *stmt == ';')
927
+ {
928
+ /*
929
+ * JBoss sends empty queries for checking connections.
930
+ * We replace the empty query with SELECT command not
931
+ * to affect load balance.
932
+ * [Pgpool-general] Confused about JDBC and load balancing
933
+ */
934
+ parse_tree_list = raw_parser(POOL_DUMMY_READ_QUERY);
935
+ }
936
+ else
937
+ {
938
+ /*
939
+ * Unable to parse the query. Probably syntax error or the
940
+ * query is too new and our parser cannot understand. Treat as
941
+ * if it were an DELETE command. Note that the DELETE command
942
+ * does not execute, instead the original query will be sent
943
+ * to backends, which may or may not cause an actual syntax errors.
944
+ * The command will be sent to all backends in replication mode
945
+ * or master/primary in master/slave mode.
946
+ */
947
+ if (!strcmp(remote_host, "[local]"))
948
+ {
949
+ pool_log("Parse: Unable to parse the query: \"%s\" from local client", stmt);
950
+ }
951
+ else
952
+ {
953
+ pool_log("Parse: Unable to parse the query: \"%s\" from client %s(%s)", stmt, remote_host, remote_port);
954
+ }
955
+ parse_tree_list = raw_parser(POOL_DUMMY_WRITE_QUERY);
956
+ query_context->is_parse_error = true;
957
+ }
958
+ }
959
+
960
+ if (parse_tree_list != NIL)
961
+ {
962
+ /* Save last query string for logging purpose */
963
+ snprintf(query_string_buffer, sizeof(query_string_buffer), "Parse: %s", stmt);
964
+
965
+ node = (Node *) lfirst(list_head(parse_tree_list));
966
+
967
+ insert_stmt_with_lock = need_insert_lock(backend, stmt, node);
968
+
969
+ /*
970
+ * Start query context
971
+ */
972
+ pool_start_query(query_context, pstrdup(stmt), strlen(stmt) + 1, node);
973
+
974
+ msg = pool_create_sent_message('P', len, contents, 0, name, query_context);
975
+ if (!msg)
976
+ {
977
+ pool_error("Parse: cannot create parse message: %s", strerror(errno));
978
+ return POOL_END;
979
+ }
980
+
981
+ session_context->uncompleted_message = msg;
982
+
983
+ /*
984
+ * If the table is to be cached, set is_cache_safe TRUE and register table oids.
985
+ */
986
+ if (pool_config->memory_cache_enabled)
987
+ {
988
+ bool is_likely_select = false;
989
+ bool is_select_query = false;
990
+ int num_oids;
991
+ int *oids;
992
+ int i;
993
+
994
+ /* Check if the query is actually SELECT */
995
+ is_likely_select = pool_is_likely_select(query_context->original_query);
996
+ if (is_likely_select && IsA(node, SelectStmt))
997
+ {
998
+ is_select_query = true;
999
+ }
1000
+
1001
+ /* Switch the flag of is_cache_safe in session_context */
1002
+ if (is_select_query && !query_context->is_parse_error &&
1003
+ pool_is_allow_to_cache(query_context->parse_tree,
1004
+ query_context->original_query))
1005
+ {
1006
+ pool_set_cache_safe();
1007
+ }
1008
+ else
1009
+ {
1010
+ pool_unset_cache_safe();
1011
+ }
1012
+
1013
+ /* If table is to be cached and the query is DML, save the table oid */
1014
+ if (!is_select_query && !query_context->is_parse_error)
1015
+ {
1016
+ num_oids = pool_extract_table_oids(node, &oids);
1017
+
1018
+ if (num_oids > 0)
1019
+ {
1020
+ /* Save to oid buffer */
1021
+ for (i=0;i<num_oids;i++)
1022
+ {
1023
+ pool_add_dml_table_oid(oids[i]);
1024
+ }
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ /*
1030
+ * Decide where to send query
1031
+ */
1032
+ pool_where_to_send(query_context, query_context->original_query,
1033
+ query_context->parse_tree);
1034
+ {
1035
+ int alloc_len = len - strlen(stmt) + strlen(query_context->original_query);
1036
+ contents = palloc(alloc_len);
1037
+ strcpy(contents, name);
1038
+ strcpy(contents + strlen(name) + 1, query_context->original_query);
1039
+ memcpy(contents + strlen(name) + 1 + strlen(query_context->original_query) + 1,
1040
+ stmt + strlen(stmt) + 1,
1041
+ len - (strlen(name) + 1 + strlen(stmt) + 1));
1042
+ len = alloc_len;
1043
+ }
1044
+
1045
+ if (REPLICATION)
1046
+ {
1047
+ char *rewrite_query;
1048
+ bool rewrite_to_params = true;
1049
+
1050
+ /*
1051
+ * rewrite `now()'.
1052
+ * if stmt is unnamed, we rewrite `now()' to timestamp constant.
1053
+ * else we rewrite `now()' to params and expand that at Bind
1054
+ * message.
1055
+ */
1056
+ if (*name == '\0')
1057
+ rewrite_to_params = false;
1058
+ msg->num_tsparams = 0;
1059
+ rewrite_query = rewrite_timestamp(backend, node, rewrite_to_params, msg);
1060
+ if (rewrite_query != NULL)
1061
+ {
1062
+ int alloc_len = len - strlen(stmt) + strlen(rewrite_query);
1063
+ contents = pool_memory_realloc(session_context->memory_context,
1064
+ msg->contents, alloc_len);
1065
+ strcpy(contents, name);
1066
+ strcpy(contents + strlen(name) + 1, rewrite_query);
1067
+ memcpy(contents + strlen(name) + strlen(rewrite_query) + 2,
1068
+ stmt + strlen(stmt) + 1,
1069
+ len - (strlen(name) + strlen(stmt) + 2));
1070
+
1071
+ len = alloc_len;
1072
+ name = contents;
1073
+ stmt = contents + strlen(name) + 1;
1074
+ pool_debug("Parse: rewrite query %s %s len=%d", name, stmt, len);
1075
+
1076
+ msg->len = len;
1077
+ msg->contents = contents;
1078
+
1079
+ query_context->rewritten_query = rewrite_query;
1080
+ }
1081
+ }
1082
+
1083
+ /*
1084
+ * If the query is BEGIN READ WRITE in master/slave mode,
1085
+ * we send BEGIN instead of it to slaves/standbys.
1086
+ * original_query which is BEGIN READ WRITE is sent to primary.
1087
+ * rewritten_query which is BEGIN is sent to standbys.
1088
+ */
1089
+ if (is_start_transaction_query(query_context->parse_tree) &&
1090
+ is_read_write((TransactionStmt *)query_context->parse_tree) &&
1091
+ MASTER_SLAVE)
1092
+ {
1093
+ query_context->rewritten_query = pstrdup("BEGIN");
1094
+ }
1095
+ }
1096
+
1097
+ pool_memory_context_switch_to(old_context);
1098
+
1099
+ /*
1100
+ * If in replication mode, send "SYNC" message if not in a transaction.
1101
+ */
1102
+ if (REPLICATION)
1103
+ {
1104
+ char kind;
1105
+
1106
+ if (TSTATE(backend, MASTER_NODE_ID) != 'T')
1107
+ {
1108
+ int i;
1109
+
1110
+ /* synchronize transaction state */
1111
+ for (i = 0; i < NUM_BACKENDS; i++)
1112
+ {
1113
+ if (!VALID_BACKEND(i))
1114
+ continue;
1115
+
1116
+ /* send sync message */
1117
+ send_extended_protocol_message(backend, i, "S", 0, "");
1118
+ }
1119
+
1120
+ kind = pool_read_kind(backend);
1121
+ if (kind != 'Z')
1122
+ {
1123
+ pool_query_context_destroy(query_context);
1124
+ return POOL_END;
1125
+ }
1126
+
1127
+ /*
1128
+ * SYNC message returns "Ready for Query" message.
1129
+ */
1130
+ if (ReadyForQuery(frontend, backend, 0, false) != POOL_CONTINUE)
1131
+ {
1132
+ pool_query_context_destroy(query_context);
1133
+ return POOL_END;
1134
+ }
1135
+
1136
+ /*
1137
+ * set in_progress flag, because ReadyForQuery unset it.
1138
+ * in_progress flag influences VALID_BACKEND.
1139
+ */
1140
+ if (!pool_is_query_in_progress())
1141
+ pool_set_query_in_progress();
1142
+ }
1143
+
1144
+ if (is_strict_query(query_context->parse_tree))
1145
+ {
1146
+ start_internal_transaction(frontend, backend, query_context->parse_tree);
1147
+ allow_close_transaction = 1;
1148
+ }
1149
+
1150
+ if (insert_stmt_with_lock)
1151
+ {
1152
+ /* start a transaction if needed and lock the table */
1153
+ status = insert_lock(frontend, backend, stmt, (InsertStmt *)query_context->parse_tree, insert_stmt_with_lock);
1154
+ if (status != POOL_CONTINUE)
1155
+ {
1156
+ pool_query_context_destroy(query_context);
1157
+ return status;
1158
+ }
1159
+ }
1160
+ }
1161
+
1162
+ /*
1163
+ * Cannot call free_parser() here. Since "string" might be allocated in parser context.
1164
+ * free_parser();
1165
+ */
1166
+
1167
+ if (REPLICATION || PARALLEL_MODE || MASTER_SLAVE)
1168
+ {
1169
+ /*
1170
+ * We must synchronize because Parse message acquires table
1171
+ * locks.
1172
+ */
1173
+ pool_debug("Parse: waiting for master completing the query");
1174
+ if (pool_extended_send_and_wait(query_context, "P", len, contents, 1, MASTER_NODE_ID) != POOL_CONTINUE)
1175
+ {
1176
+ pool_query_context_destroy(query_context);
1177
+ return POOL_END;
1178
+ }
1179
+
1180
+ /*
1181
+ * We must check deadlock error because a aborted transaction
1182
+ * by detecting deadlock isn't same on all nodes.
1183
+ * If a transaction is aborted on master node, pgpool send a
1184
+ * error query to another nodes.
1185
+ */
1186
+ deadlock_detected = detect_deadlock_error(MASTER(backend), MAJOR(backend));
1187
+ if (deadlock_detected < 0)
1188
+ {
1189
+ pool_query_context_destroy(query_context);
1190
+ return POOL_END;
1191
+ }
1192
+ else
1193
+ {
1194
+ /*
1195
+ * Check if other than deadlock error detected. If so, emit
1196
+ * log. This is useful when invalid encoding error occurs. In
1197
+ * this case, PostgreSQL does not report what statement caused
1198
+ * that error and make users confused.
1199
+ */
1200
+ per_node_error_log(backend, MASTER_NODE_ID, stmt, "Parse: Error or notice message from backend: ", true);
1201
+ }
1202
+
1203
+ if (deadlock_detected)
1204
+ {
1205
+ POOL_QUERY_CONTEXT *error_qc;
1206
+
1207
+ error_qc = pool_init_query_context();
1208
+ pool_start_query(error_qc, POOL_ERROR_QUERY, strlen(POOL_ERROR_QUERY) + 1, node);
1209
+ pool_copy_prep_where(query_context->where_to_send, error_qc->where_to_send);
1210
+
1211
+ pool_log("Parse: received deadlock error message from master node");
1212
+
1213
+ if (pool_send_and_wait(error_qc, -1, MASTER_NODE_ID) != POOL_CONTINUE)
1214
+ {
1215
+ pool_query_context_destroy(query_context);
1216
+ return POOL_END;
1217
+ }
1218
+
1219
+ pool_query_context_destroy(error_qc);
1220
+ pool_set_query_in_progress();
1221
+ session_context->query_context = query_context;
1222
+ }
1223
+ else
1224
+ {
1225
+ if (pool_extended_send_and_wait(query_context, "P", len, contents, -1, MASTER_NODE_ID) != POOL_CONTINUE)
1226
+ {
1227
+ pool_query_context_destroy(query_context);
1228
+ return POOL_END;
1229
+ }
1230
+ }
1231
+ }
1232
+ else
1233
+ {
1234
+ if (pool_extended_send_and_wait(query_context, "P", len, contents, 1, MASTER_NODE_ID) != POOL_CONTINUE)
1235
+ {
1236
+ pool_query_context_destroy(query_context);
1237
+ return POOL_END;
1238
+ }
1239
+ }
1240
+
1241
+ /*
1242
+ * Ok. we are safe to call free_parser();
1243
+ */
1244
+ /* free_parser(); */
1245
+
1246
+ return POOL_CONTINUE;
1247
+
1248
+ }
1249
+
1250
+ POOL_STATUS Bind(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
1251
+ int len, char *contents)
1252
+ {
1253
+ char *pstmt_name;
1254
+ char *portal_name;
1255
+ char *rewrite_msg;
1256
+ POOL_SENT_MESSAGE *parse_msg;
1257
+ POOL_SENT_MESSAGE *bind_msg;
1258
+ POOL_SESSION_CONTEXT *session_context;
1259
+ POOL_QUERY_CONTEXT *query_context;
1260
+ int insert_stmt_with_lock = 0;
1261
+
1262
+ /* Get session context */
1263
+ session_context = pool_get_session_context();
1264
+ if (!session_context)
1265
+ {
1266
+ pool_error("Bind: cannot get session context");
1267
+ return POOL_END;
1268
+ }
1269
+
1270
+ /*
1271
+ * Rewrite message
1272
+ */
1273
+ portal_name = contents;
1274
+ pstmt_name = contents + strlen(portal_name) + 1;
1275
+
1276
+ parse_msg = pool_get_sent_message('Q', pstmt_name);
1277
+ if (!parse_msg)
1278
+ parse_msg = pool_get_sent_message('P', pstmt_name);
1279
+ if (!parse_msg)
1280
+ {
1281
+ pool_error("Bind: cannot get parse message \"%s\"", pstmt_name);
1282
+ return POOL_END;
1283
+ }
1284
+
1285
+ bind_msg = pool_create_sent_message('B', len, contents,
1286
+ parse_msg->num_tsparams, portal_name,
1287
+ parse_msg->query_context);
1288
+ if (!bind_msg)
1289
+ {
1290
+ pool_error("Bind: cannot create bind message: %s", strerror(errno));
1291
+ return POOL_END;
1292
+ }
1293
+
1294
+ query_context = parse_msg->query_context;
1295
+ if (!query_context)
1296
+ {
1297
+ pool_error("Bind: cannot get query context");
1298
+ return POOL_END;
1299
+ }
1300
+
1301
+ /*
1302
+ * If the query can be cached, save its offset of query text in bind message's content.
1303
+ */
1304
+ if (query_context->is_cache_safe)
1305
+ {
1306
+ bind_msg->param_offset = sizeof(char) * (strlen(portal_name) + strlen(pstmt_name) + 2);
1307
+ }
1308
+
1309
+ session_context->uncompleted_message = bind_msg;
1310
+
1311
+ /* rewrite bind message */
1312
+ if (REPLICATION && bind_msg->num_tsparams > 0)
1313
+ {
1314
+ rewrite_msg = bind_rewrite_timestamp(backend, bind_msg, contents, &len);
1315
+ if (rewrite_msg != NULL)
1316
+ contents = rewrite_msg;
1317
+ }
1318
+
1319
+ session_context->query_context = query_context;
1320
+
1321
+ if (pool_config->load_balance_mode && pool_is_writing_transaction())
1322
+ {
1323
+ pool_where_to_send(query_context, query_context->original_query,
1324
+ query_context->parse_tree);
1325
+
1326
+ if (parse_before_bind(frontend, backend, parse_msg) != POOL_CONTINUE)
1327
+ return POOL_END;
1328
+ }
1329
+
1330
+ /*
1331
+ * Start a transaction if necessary
1332
+ */
1333
+ pool_debug("Bind: checking strict query");
1334
+ if (is_strict_query(query_context->parse_tree))
1335
+ {
1336
+ pool_debug("Bind: strict query");
1337
+ start_internal_transaction(frontend, backend, query_context->parse_tree);
1338
+ allow_close_transaction = 1;
1339
+ }
1340
+
1341
+ pool_debug("Bind: checking insert lock");
1342
+ insert_stmt_with_lock = need_insert_lock(backend, query_context->original_query, query_context->parse_tree);
1343
+ if (insert_stmt_with_lock)
1344
+ {
1345
+ pool_debug("Bind: issuing insert lock");
1346
+ /* issue a LOCK command to keep consistency */
1347
+ if (insert_lock(frontend, backend, query_context->original_query, (InsertStmt *)query_context->parse_tree, insert_stmt_with_lock) != POOL_CONTINUE)
1348
+ {
1349
+ pool_query_context_destroy(query_context);
1350
+ return POOL_END;
1351
+ }
1352
+ }
1353
+
1354
+ pool_debug("Bind: waiting for master completing the query");
1355
+ if (pool_extended_send_and_wait(query_context, "B", len, contents, 1, MASTER_NODE_ID)
1356
+ != POOL_CONTINUE)
1357
+ {
1358
+ return POOL_END;
1359
+ }
1360
+
1361
+ if (pool_extended_send_and_wait(query_context, "B", len, contents, -1, MASTER_NODE_ID)
1362
+ != POOL_CONTINUE)
1363
+ {
1364
+ return POOL_END;
1365
+ }
1366
+
1367
+ return POOL_CONTINUE;
1368
+ }
1369
+
1370
+ POOL_STATUS Describe(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
1371
+ int len, char *contents)
1372
+ {
1373
+ POOL_SENT_MESSAGE *msg;
1374
+ POOL_SESSION_CONTEXT *session_context;
1375
+ POOL_QUERY_CONTEXT *query_context;
1376
+
1377
+ /* Get session context */
1378
+ session_context = pool_get_session_context();
1379
+ if (!session_context)
1380
+ {
1381
+ pool_error("Describe: cannot get session context");
1382
+ return POOL_END;
1383
+ }
1384
+
1385
+ /* Prepared Statement */
1386
+ if (*contents == 'S')
1387
+ {
1388
+ msg = pool_get_sent_message('Q', contents+1);
1389
+ if (!msg)
1390
+ msg = pool_get_sent_message('P', contents+1);
1391
+ if (!msg)
1392
+ {
1393
+ pool_error("Describe: cannot get parse message");
1394
+ return POOL_END;
1395
+ }
1396
+ }
1397
+ /* Portal */
1398
+ else
1399
+ {
1400
+ msg = pool_get_sent_message('B', contents+1);
1401
+ if (!msg)
1402
+ {
1403
+ pool_error("Describe: cannot get bind message");
1404
+ return POOL_END;
1405
+ }
1406
+ }
1407
+
1408
+ query_context = msg->query_context;
1409
+
1410
+ if (query_context == NULL)
1411
+ {
1412
+ pool_error("Describe: cannot get query context");
1413
+ return POOL_END;
1414
+ }
1415
+
1416
+ session_context->query_context = query_context;
1417
+
1418
+ /*
1419
+ * Calling pool_where_to_send here is dangerous because the node
1420
+ * parse/bind has been sent could be change by
1421
+ * pool_where_to_send() and it leads to "portal not found"
1422
+ * etc. errors.
1423
+ */
1424
+ pool_debug("Describe: waiting for master completing the query");
1425
+ if (pool_extended_send_and_wait(query_context, "D", len, contents, 1, MASTER_NODE_ID)
1426
+ != POOL_CONTINUE)
1427
+ return POOL_END;
1428
+
1429
+ if (pool_extended_send_and_wait(query_context, "D", len, contents, -1, MASTER_NODE_ID)
1430
+ != POOL_CONTINUE)
1431
+ return POOL_END;
1432
+
1433
+ return POOL_CONTINUE;
1434
+ }
1435
+
1436
+
1437
+ POOL_STATUS Close(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
1438
+ int len, char *contents)
1439
+ {
1440
+ POOL_SENT_MESSAGE *msg;
1441
+ POOL_SESSION_CONTEXT *session_context;
1442
+ POOL_QUERY_CONTEXT *query_context;
1443
+
1444
+ /* Get session context */
1445
+ session_context = pool_get_session_context();
1446
+ if (!session_context)
1447
+ {
1448
+ pool_error("Close: cannot get session context");
1449
+ return POOL_END;
1450
+ }
1451
+
1452
+ /* Prepared Statement */
1453
+ if (*contents == 'S')
1454
+ {
1455
+ msg = pool_get_sent_message('Q', contents+1);
1456
+ if (!msg)
1457
+ msg = pool_get_sent_message('P', contents+1);
1458
+ if (!msg)
1459
+ {
1460
+ pool_error("Close: cannot get parse message");
1461
+ return POOL_END;
1462
+ }
1463
+ }
1464
+ /* Portal */
1465
+ else if (*contents == 'P')
1466
+ {
1467
+ msg = pool_get_sent_message('B', contents+1);
1468
+ if (!msg)
1469
+ {
1470
+ pool_error("Close: cannot get bind message");
1471
+ return POOL_END;
1472
+ }
1473
+ }
1474
+ else
1475
+ {
1476
+ pool_error("Close: invalid message");
1477
+ return POOL_END;
1478
+ }
1479
+
1480
+ session_context->uncompleted_message = msg;
1481
+ query_context = msg->query_context;
1482
+
1483
+ if (!query_context)
1484
+ {
1485
+ pool_error("Close: cannot get query context");
1486
+ return POOL_END;
1487
+ }
1488
+
1489
+ session_context->query_context = query_context;
1490
+ /* pool_where_to_send(query_context, query_context->original_query, query_context->parse_tree); */
1491
+
1492
+ pool_debug("Close: waiting for master completing the query");
1493
+ if (pool_extended_send_and_wait(query_context, "C", len, contents, 1, MASTER_NODE_ID)
1494
+ != POOL_CONTINUE)
1495
+ return POOL_END;
1496
+
1497
+ if (pool_extended_send_and_wait(query_context, "C", len, contents, -1, MASTER_NODE_ID)
1498
+ != POOL_CONTINUE)
1499
+ return POOL_END;
1500
+
1501
+ return POOL_CONTINUE;
1502
+ }
1503
+
1504
+
1505
+ POOL_STATUS FunctionCall3(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
1506
+ int len, char *contents)
1507
+ {
1508
+ /*
1509
+ * If Function call message for lo_creat, rewrite it
1510
+ */
1511
+ char *rewrite_lo;
1512
+ int rewrite_len;
1513
+
1514
+ rewrite_lo = pool_rewrite_lo_creat('F', contents, len, frontend,
1515
+ backend, &rewrite_len);
1516
+
1517
+ if (rewrite_lo != NULL)
1518
+ {
1519
+ contents = rewrite_lo;
1520
+ len = rewrite_len;
1521
+ }
1522
+ return SimpleForwardToBackend('F', frontend, backend, len, contents);
1523
+ }
1524
+
1525
+ /*
1526
+ * Process ReadyForQuery('Z') message.
1527
+ * If send_ready is true, send 'Z' message to frontend.
1528
+ * If cache_commit is true, commit or discard query cache according to
1529
+ * transaction state.
1530
+ *
1531
+ * - if the error status "mismatch_ntuples" is set, send an error query
1532
+ * to all DB nodes to abort transaction or do failover.
1533
+ * - internal transaction is closed
1534
+ */
1535
+ POOL_STATUS ReadyForQuery(POOL_CONNECTION *frontend,
1536
+ POOL_CONNECTION_POOL *backend, bool send_ready, bool cache_commit)
1537
+ {
1538
+ int i;
1539
+ int len;
1540
+ signed char kind;
1541
+ signed char state;
1542
+ POOL_SESSION_CONTEXT *session_context;
1543
+ Node *node = NULL;
1544
+ char *query = NULL;
1545
+
1546
+ /* Get session context */
1547
+ session_context = pool_get_session_context();
1548
+ if (!session_context)
1549
+ {
1550
+ pool_error("ReadyForQuery: cannot get session context");
1551
+ return POOL_END;
1552
+ }
1553
+
1554
+ /*
1555
+ * If the numbers of update tuples are differ and
1556
+ * failover_if_affected_tuples_mismatch is false, we abort
1557
+ * transactions by using do_error_command. If
1558
+ * failover_if_affected_tuples_mismatch is true, trigger failover.
1559
+ * This only works with PROTO_MAJOR_V3.
1560
+ */
1561
+ if (session_context->mismatch_ntuples && MAJOR(backend) == PROTO_MAJOR_V3)
1562
+ {
1563
+ int i;
1564
+ char kind;
1565
+
1566
+ /*
1567
+ * If failover_if_affected_tuples_mismatch, is true, then
1568
+ * decide victim nodes by using find_victim_nodes and
1569
+ * degenerate them.
1570
+ */
1571
+ if (pool_config->failover_if_affected_tuples_mismatch)
1572
+ {
1573
+ int *victim_nodes;
1574
+ int number_of_nodes;
1575
+ char msgbuf[128];
1576
+
1577
+ victim_nodes = find_victim_nodes(session_context->ntuples, NUM_BACKENDS,
1578
+ MASTER_NODE_ID, &number_of_nodes);
1579
+ if (victim_nodes)
1580
+ {
1581
+ int i;
1582
+ String *msg;
1583
+ POOL_MEMORY_POOL *old_context;
1584
+
1585
+ if (session_context->query_context)
1586
+ old_context = pool_memory_context_switch_to(session_context->query_context->memory_context);
1587
+ else
1588
+ old_context = pool_memory_context_switch_to(session_context->memory_context);
1589
+
1590
+ msg = init_string("ReadyForQuery: Degenerate backends:");
1591
+
1592
+ for (i=0;i<number_of_nodes;i++)
1593
+ {
1594
+ snprintf(msgbuf, sizeof(msgbuf), " %d", victim_nodes[i]);
1595
+ string_append_char(msg, msgbuf);
1596
+ }
1597
+ pool_log("%s", msg->data);
1598
+ free_string(msg);
1599
+
1600
+ msg = init_string("ReadyForQuery: Number of affected tuples are:");
1601
+
1602
+ for (i=0;i<NUM_BACKENDS;i++)
1603
+ {
1604
+ snprintf(msgbuf, sizeof(msgbuf), " %d", session_context->ntuples[i]);
1605
+ string_append_char(msg, msgbuf);
1606
+ }
1607
+ pool_log("%s", msg->data);
1608
+ free_string(msg);
1609
+
1610
+ pool_memory_context_switch_to(old_context);
1611
+
1612
+ degenerate_backend_set(victim_nodes, number_of_nodes);
1613
+ child_exit(1);
1614
+ }
1615
+ else
1616
+ {
1617
+ pool_error("ReadyForQuery: find_victim_nodes returned no victim node");
1618
+ }
1619
+ }
1620
+
1621
+ /*
1622
+ * XXX: discard rest of ReadyForQuery packet
1623
+ */
1624
+ if (pool_read_message_length(backend) < 0)
1625
+ return POOL_END;
1626
+
1627
+ state = pool_read_kind(backend);
1628
+ if (state < 0)
1629
+ return POOL_END;
1630
+
1631
+ for (i = 0; i < NUM_BACKENDS; i++)
1632
+ {
1633
+ if (VALID_BACKEND(i))
1634
+ {
1635
+ /* abort transaction on all nodes. */
1636
+ do_error_command(CONNECTION(backend, i), PROTO_MAJOR_V3);
1637
+ }
1638
+ }
1639
+
1640
+ /* loop through until we get ReadyForQuery */
1641
+ for(;;)
1642
+ {
1643
+ kind = pool_read_kind(backend);
1644
+ if (kind < 0)
1645
+ return POOL_END;
1646
+
1647
+ if (kind == 'Z')
1648
+ break;
1649
+
1650
+ /* put the message back to read buffer */
1651
+ for (i=0;i<NUM_BACKENDS;i++)
1652
+ {
1653
+ if (VALID_BACKEND(i))
1654
+ {
1655
+ pool_unread(CONNECTION(backend,i), &kind, 1);
1656
+ }
1657
+ }
1658
+
1659
+ /* discard rest of the packet */
1660
+ if (pool_discard_packet(backend) != POOL_CONTINUE)
1661
+ {
1662
+ pool_error("ReadyForQuery: pool_discard_packet failed");
1663
+ return POOL_END;
1664
+ }
1665
+ }
1666
+ session_context->mismatch_ntuples = false;
1667
+ }
1668
+
1669
+ /*
1670
+ * if a transaction is started for insert lock, we need to close
1671
+ * the transaction.
1672
+ */
1673
+ /* if (pool_is_query_in_progress() && allow_close_transaction) */
1674
+ if (allow_close_transaction)
1675
+ {
1676
+ if (end_internal_transaction(frontend, backend) != POOL_CONTINUE)
1677
+ return POOL_END;
1678
+ }
1679
+
1680
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
1681
+ {
1682
+ if ((len = pool_read_message_length(backend)) < 0)
1683
+ return POOL_END;
1684
+
1685
+ /*
1686
+ * Set transaction state for each node
1687
+ */
1688
+ state = TSTATE(backend,
1689
+ MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID);
1690
+
1691
+ for (i=0;i<NUM_BACKENDS;i++)
1692
+ {
1693
+ if (!VALID_BACKEND(i))
1694
+ continue;
1695
+
1696
+ if (pool_read(CONNECTION(backend, i), &kind, sizeof(kind)))
1697
+ return POOL_END;
1698
+
1699
+ TSTATE(backend, i) = kind;
1700
+
1701
+ pool_debug("ReadyForQuery: transaction state:%c", state);
1702
+
1703
+ /*
1704
+ * The transaction state to be returned to frontend is
1705
+ * master's.
1706
+ */
1707
+ if (i == (MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID))
1708
+ {
1709
+ state = kind;
1710
+ }
1711
+ }
1712
+ }
1713
+
1714
+ if (send_ready)
1715
+ {
1716
+ pool_write(frontend, "Z", 1);
1717
+
1718
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
1719
+ {
1720
+ len = htonl(len);
1721
+ pool_write(frontend, &len, sizeof(len));
1722
+ pool_write(frontend, &state, 1);
1723
+ }
1724
+ pool_flush(frontend);
1725
+ }
1726
+
1727
+ if (pool_is_query_in_progress())
1728
+ {
1729
+ node = pool_get_parse_tree();
1730
+
1731
+ if (pool_is_command_success())
1732
+ {
1733
+ query = pool_get_query_string();
1734
+
1735
+ if (node)
1736
+ {
1737
+ /*
1738
+ * If the query was BEGIN/START TRANSACTION, clear the
1739
+ * history that we had a writing command in the transaction
1740
+ * and forget the transaction isolation level.
1741
+ *
1742
+ * XXX If BEGIN is received while we are already in an
1743
+ * explicit transaction, the command *successes*
1744
+ * (just with a NOTICE message). In this case we lose
1745
+ * "writing_transaction" etc. info.
1746
+ */
1747
+ if (is_start_transaction_query(node))
1748
+ {
1749
+ pool_unset_writing_transaction();
1750
+ pool_unset_failed_transaction();
1751
+ pool_unset_transaction_isolation();
1752
+ }
1753
+
1754
+ /*
1755
+ * If the query was COMMIT/ABORT, clear the history
1756
+ * that we had a writing command in the transaction
1757
+ * and forget the transaction isolation level. This
1758
+ * is necessary if succeeding transaction is not an
1759
+ * explicit one.
1760
+ */
1761
+ else if (is_commit_or_rollback_query(node))
1762
+ {
1763
+ pool_unset_writing_transaction();
1764
+ pool_unset_failed_transaction();
1765
+ pool_unset_transaction_isolation();
1766
+ }
1767
+
1768
+ /*
1769
+ * SET TRANSACTION ISOLATION LEVEL SERIALIZABLE or SET
1770
+ * SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
1771
+ * SERIALIZABLE, remember it.
1772
+ */
1773
+ else if (is_set_transaction_serializable(node))
1774
+ {
1775
+ pool_set_transaction_isolation(POOL_SERIALIZABLE);
1776
+ }
1777
+
1778
+ /*
1779
+ * If 2PC commands has been executed, automatically close
1780
+ * transactions on standbys if there is any open
1781
+ * transaction since 2PC commands close transaction on
1782
+ * primary.
1783
+ */
1784
+ else if (is_2pc_transaction_query(node))
1785
+ {
1786
+ if (close_standby_transactions(frontend, backend) != POOL_CONTINUE)
1787
+ return POOL_END;
1788
+ }
1789
+
1790
+ else if (!is_select_query(node, query))
1791
+ {
1792
+ /*
1793
+ * If the query was not READ SELECT, and we are in an
1794
+ * explicit transaction, remember that we had a write
1795
+ * query in this transaction.
1796
+ */
1797
+ if (TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID) == 'T')
1798
+ {
1799
+ pool_set_writing_transaction();
1800
+ }
1801
+
1802
+ /*
1803
+ * If the query was CREATE TEMP TABLE, discard
1804
+ * temp table relcache because we might have had
1805
+ * persistent table relation cache which has table
1806
+ * name as the temp table.
1807
+ */
1808
+ if (IsA(node, CreateStmt))
1809
+ {
1810
+ CreateStmt *create_table_stmt = (CreateStmt *)node;
1811
+ if (create_table_stmt->relation->relpersistence)
1812
+ discard_temp_table_relcache();
1813
+ }
1814
+ }
1815
+ }
1816
+
1817
+ /* Memory cache enabled? */
1818
+ if (cache_commit && pool_config->memory_cache_enabled)
1819
+ {
1820
+ /* If we are doing extended query and the state is after EXECUTE,
1821
+ * then we can commit cache.
1822
+ * We check latter condition by looking at query_context->query_w_hex.
1823
+ * This check is necessary for certain frame work such as PHP PDO.
1824
+ * It sends Sync message right after PARSE and it produces
1825
+ * "Ready for query" message from backend.
1826
+ */
1827
+ if (pool_is_doing_extended_query_message())
1828
+ {
1829
+ if (session_context->query_context->query_state[MASTER_NODE_ID] == POOL_EXECUTE_COMPLETE)
1830
+ {
1831
+ pool_handle_query_cache(backend, session_context->query_context->query_w_hex, node, state);
1832
+ free(session_context->query_context->query_w_hex);
1833
+ session_context->query_context->query_w_hex = NULL;
1834
+ }
1835
+ }
1836
+ else
1837
+ {
1838
+ if (MAJOR(backend) != PROTO_MAJOR_V3)
1839
+ {
1840
+ state = 'I'; /* XXX I don't think query cache works with PROTO2 protocol */
1841
+ }
1842
+ pool_handle_query_cache(backend, query, node, state);
1843
+ }
1844
+ }
1845
+ }
1846
+ /*
1847
+ * If PREPARE or extended query protocol commands caused error,
1848
+ * remove the temporary saved message.
1849
+ * (except when ReadyForQuery() is called during Parse() of extended queries)
1850
+ */
1851
+ else
1852
+ {
1853
+ if ((pool_is_doing_extended_query_message() &&
1854
+ session_context->query_context->query_state[MASTER_NODE_ID] != POOL_UNPARSED &&
1855
+ session_context->uncompleted_message) ||
1856
+ (!pool_is_doing_extended_query_message() && session_context->uncompleted_message))
1857
+ {
1858
+ pool_add_sent_message(session_context->uncompleted_message);
1859
+ pool_remove_sent_message(session_context->uncompleted_message->kind,
1860
+ session_context->uncompleted_message->name);
1861
+ session_context->uncompleted_message = NULL;
1862
+ }
1863
+ }
1864
+
1865
+ pool_unset_query_in_progress();
1866
+ }
1867
+
1868
+ if (!pool_is_doing_extended_query_message())
1869
+ {
1870
+ if (!(node && IsA(node, PrepareStmt)))
1871
+ pool_query_context_destroy(pool_get_session_context()->query_context);
1872
+ }
1873
+
1874
+ /*
1875
+ * Show ps idle status
1876
+ */
1877
+ pool_ps_idle_display(backend);
1878
+
1879
+ return POOL_CONTINUE;
1880
+ }
1881
+
1882
+ /*
1883
+ * Close running transactions on standbys.
1884
+ */
1885
+ static POOL_STATUS close_standby_transactions(POOL_CONNECTION *frontend,
1886
+ POOL_CONNECTION_POOL *backend)
1887
+ {
1888
+ int i;
1889
+
1890
+ for (i=0;i<NUM_BACKENDS;i++)
1891
+ {
1892
+ if (CONNECTION_SLOT(backend, i) &&
1893
+ TSTATE(backend, i) == 'T' &&
1894
+ BACKEND_INFO(i).backend_status == CON_UP &&
1895
+ (MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID) != i)
1896
+ {
1897
+ per_node_statement_log(backend, i, "COMMIT");
1898
+ if (do_command(frontend, CONNECTION(backend, i), "COMMIT", MAJOR(backend),
1899
+ MASTER_CONNECTION(backend)->pid,
1900
+ MASTER_CONNECTION(backend)->key, 0) != POOL_CONTINUE)
1901
+ {
1902
+ return POOL_END;
1903
+ }
1904
+ }
1905
+ }
1906
+ return POOL_CONTINUE;
1907
+ }
1908
+
1909
+ POOL_STATUS ParseComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
1910
+ {
1911
+ POOL_SESSION_CONTEXT *session_context;
1912
+
1913
+ /* Get session context */
1914
+ session_context = pool_get_session_context();
1915
+ if (!session_context)
1916
+ {
1917
+ pool_error("ParseComplete: cannot get session context");
1918
+ return POOL_END;
1919
+ }
1920
+
1921
+ if (session_context->uncompleted_message)
1922
+ {
1923
+ POOL_QUERY_CONTEXT *qc;
1924
+
1925
+ pool_add_sent_message(session_context->uncompleted_message);
1926
+
1927
+ qc = session_context->uncompleted_message->query_context;
1928
+ if (qc)
1929
+ pool_set_query_state(qc, POOL_PARSE_COMPLETE);
1930
+
1931
+ session_context->uncompleted_message = NULL;
1932
+ }
1933
+
1934
+ return SimpleForwardToFrontend('1', frontend, backend);
1935
+ }
1936
+
1937
+ POOL_STATUS BindComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
1938
+ {
1939
+ POOL_SESSION_CONTEXT *session_context;
1940
+
1941
+ /* Get session context */
1942
+ session_context = pool_get_session_context();
1943
+ if (!session_context)
1944
+ {
1945
+ pool_error("BindComplete: cannot get session context");
1946
+ return POOL_END;
1947
+ }
1948
+
1949
+ if (session_context->uncompleted_message)
1950
+ {
1951
+ POOL_QUERY_CONTEXT *qc;
1952
+
1953
+ pool_add_sent_message(session_context->uncompleted_message);
1954
+
1955
+ qc = session_context->uncompleted_message->query_context;
1956
+ if (qc)
1957
+ pool_set_query_state(qc, POOL_BIND_COMPLETE);
1958
+
1959
+ session_context->uncompleted_message = NULL;
1960
+ }
1961
+
1962
+ return SimpleForwardToFrontend('2', frontend, backend);
1963
+ }
1964
+
1965
+ POOL_STATUS CloseComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
1966
+ {
1967
+ POOL_SESSION_CONTEXT *session_context;
1968
+ POOL_STATUS status;
1969
+
1970
+ /* Get session context */
1971
+ session_context = pool_get_session_context();
1972
+ if (!session_context)
1973
+ {
1974
+ pool_error("CloseComplete: cannot get session context");
1975
+ return POOL_END;
1976
+ }
1977
+
1978
+ /* Send CloseComplete(3) to frontend before removing the target message */
1979
+ status = SimpleForwardToFrontend('3', frontend, backend);
1980
+
1981
+ /* Remove the target message */
1982
+ if (session_context->uncompleted_message)
1983
+ {
1984
+ pool_remove_sent_message(session_context->uncompleted_message->kind,
1985
+ session_context->uncompleted_message->name);
1986
+ session_context->uncompleted_message = NULL;
1987
+ }
1988
+ else
1989
+ {
1990
+ pool_error("CloseComplete: uncompleted message not found");
1991
+ return POOL_END;
1992
+ }
1993
+
1994
+ return status;
1995
+ }
1996
+
1997
+ POOL_STATUS CommandComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
1998
+ {
1999
+ int i;
2000
+ int len, len1, sendlen;
2001
+ int status;
2002
+ int rows;
2003
+ char *p, *p1, *p2;
2004
+ bool update_or_delete = false;
2005
+ POOL_SESSION_CONTEXT *session_context;
2006
+
2007
+ /* Get session context */
2008
+ session_context = pool_get_session_context();
2009
+ if (!session_context)
2010
+ {
2011
+ pool_error("CommandComplete: cannot get session context");
2012
+ return POOL_END;
2013
+ }
2014
+
2015
+ if (session_context->query_context != NULL)
2016
+ {
2017
+ Node *node = session_context->query_context->parse_tree;
2018
+
2019
+ if (IsA(node, PrepareStmt))
2020
+ {
2021
+ if (session_context->uncompleted_message)
2022
+ {
2023
+ pool_add_sent_message(session_context->uncompleted_message);
2024
+ session_context->uncompleted_message = NULL;
2025
+ }
2026
+ }
2027
+ else if (IsA(node, DeallocateStmt))
2028
+ {
2029
+ char *name;
2030
+
2031
+ name = ((DeallocateStmt *)node)->name;
2032
+ if (name == NULL)
2033
+ {
2034
+ pool_remove_sent_messages('Q');
2035
+ pool_remove_sent_messages('P');
2036
+ }
2037
+ else
2038
+ {
2039
+ pool_remove_sent_message('Q', name);
2040
+ pool_remove_sent_message('P', name);
2041
+ }
2042
+ }
2043
+ else if (IsA(node, DiscardStmt))
2044
+ {
2045
+ DiscardStmt *stmt = (DiscardStmt *)node;
2046
+
2047
+ if (stmt->target == DISCARD_PLANS)
2048
+ {
2049
+ pool_remove_sent_messages('Q');
2050
+ pool_remove_sent_messages('P');
2051
+ }
2052
+ else if (stmt->target == DISCARD_ALL)
2053
+ {
2054
+ pool_clear_sent_message_list();
2055
+ }
2056
+ }
2057
+ /*
2058
+ * JDBC driver sends "BEGIN" query internally if
2059
+ * setAutoCommit(false). But it does not send Sync message
2060
+ * after "BEGIN" query. In extended query protocol,
2061
+ * PostgreSQL returns ReadyForQuery when a client sends Sync
2062
+ * message. Problem is, pgpool can't know the transaction
2063
+ * state without receiving ReadyForQuery. So we remember that
2064
+ * we need to send Sync message internally afterward, whenever
2065
+ * we receive BEGIN in extended protocol.
2066
+ */
2067
+ else if (IsA(node, TransactionStmt))
2068
+ {
2069
+ TransactionStmt *stmt = (TransactionStmt *) node;
2070
+
2071
+ if (stmt->kind == TRANS_STMT_BEGIN || stmt->kind == TRANS_STMT_START)
2072
+ {
2073
+ int i;
2074
+
2075
+ for (i = 0; i < NUM_BACKENDS; i++)
2076
+ {
2077
+ if (!VALID_BACKEND(i))
2078
+ continue;
2079
+
2080
+ TSTATE(backend, i) = 'T';
2081
+ }
2082
+ pool_unset_writing_transaction();
2083
+ pool_unset_failed_transaction();
2084
+ pool_unset_transaction_isolation();
2085
+ }
2086
+ }
2087
+
2088
+ }
2089
+
2090
+ status = pool_read(MASTER(backend), &len, sizeof(len));
2091
+ if (status < 0)
2092
+ {
2093
+ pool_error("CommandComplete: error while reading message length");
2094
+ return POOL_END;
2095
+ }
2096
+
2097
+ len = ntohl(len);
2098
+ len -= 4;
2099
+ len1 = len;
2100
+
2101
+ p = pool_read2(MASTER(backend), len);
2102
+ if (p == NULL)
2103
+ return POOL_END;
2104
+ p1 = malloc(len);
2105
+ if (p1 == NULL)
2106
+ {
2107
+ pool_error("CommandComplete: malloc failed");
2108
+ return POOL_ERROR;
2109
+ }
2110
+ memcpy(p1, p, len);
2111
+
2112
+ rows = extract_ntuples(p);
2113
+
2114
+ /*
2115
+ * Save number of affected tuples of master node.
2116
+ */
2117
+ session_context->ntuples[MASTER_NODE_ID] = rows;
2118
+
2119
+ if (strstr(p, "UPDATE") || strstr(p, "DELETE"))
2120
+ update_or_delete = true;
2121
+
2122
+ for (i=0;i<NUM_BACKENDS;i++)
2123
+ {
2124
+ if (!IS_MASTER_NODE_ID(i))
2125
+ {
2126
+ if (!VALID_BACKEND(i))
2127
+ {
2128
+ session_context->ntuples[i] = -1;
2129
+ continue;
2130
+ }
2131
+
2132
+ status = pool_read(CONNECTION(backend, i), &len, sizeof(len));
2133
+ if (status < 0)
2134
+ {
2135
+ pool_error("CommandComplete: error while reading message length");
2136
+ return POOL_END;
2137
+ }
2138
+
2139
+ len = ntohl(len);
2140
+ len -= 4;
2141
+
2142
+ p = pool_read2(CONNECTION(backend, i), len);
2143
+ if (p == NULL)
2144
+ return POOL_END;
2145
+
2146
+ if (len != len1)
2147
+ {
2148
+ pool_debug("CommandComplete: length does not match between backends master(%d) %d th backend(%d)",
2149
+ len, i, len1);
2150
+ }
2151
+
2152
+ int n = extract_ntuples(p);
2153
+
2154
+ /*
2155
+ * Save number of affected tuples.
2156
+ */
2157
+ session_context->ntuples[i] = n;
2158
+
2159
+ /*
2160
+ * if we are in the parallel mode, we have to sum up the number
2161
+ * of affected rows
2162
+ */
2163
+ if (PARALLEL_MODE && is_parallel_table && update_or_delete)
2164
+ {
2165
+ rows += n;
2166
+ }
2167
+ else
2168
+ {
2169
+ if (rows != n)
2170
+ {
2171
+ /*
2172
+ * Remember that we have different number of UPDATE/DELETE
2173
+ * affected tuples in backends.
2174
+ */
2175
+ session_context->mismatch_ntuples = true;
2176
+ }
2177
+ }
2178
+ }
2179
+ }
2180
+
2181
+ if (session_context->mismatch_ntuples)
2182
+ {
2183
+ char msgbuf[128];
2184
+ POOL_MEMORY_POOL *old_context;
2185
+
2186
+ if (session_context->query_context)
2187
+ old_context = pool_memory_context_switch_to(session_context->query_context->memory_context);
2188
+ else
2189
+ old_context = pool_memory_context_switch_to(session_context->memory_context);
2190
+
2191
+ String *msg = init_string("pgpool detected difference of the number of inserted, updated or deleted tuples. Possible last query was: \"");
2192
+ string_append_char(msg, query_string_buffer);
2193
+ string_append_char(msg, "\"");
2194
+ pool_send_error_message(frontend, MAJOR(backend),
2195
+ "XX001", msg->data, "",
2196
+ "check data consistency between master and other db node", __FILE__, __LINE__);
2197
+ pool_error("%s", msg->data);
2198
+ free_string(msg);
2199
+
2200
+ msg = init_string("CommandComplete: Number of affected tuples are:");
2201
+
2202
+ for (i=0;i<NUM_BACKENDS;i++)
2203
+ {
2204
+ snprintf(msgbuf, sizeof(msgbuf), " %d", session_context->ntuples[i]);
2205
+ string_append_char(msg, msgbuf);
2206
+ }
2207
+ pool_log("%s", msg->data);
2208
+ free_string(msg);
2209
+
2210
+ pool_memory_context_switch_to(old_context);
2211
+ }
2212
+ else
2213
+ {
2214
+ if (PARALLEL_MODE && is_parallel_table && update_or_delete)
2215
+ {
2216
+ char tmp[32];
2217
+
2218
+ strncpy(tmp, p1, 7);
2219
+ sprintf(tmp+7, "%d", rows);
2220
+
2221
+ p2 = strdup(tmp);
2222
+ if (p2 == NULL)
2223
+ {
2224
+ pool_error("CommandComplete: malloc failed");
2225
+ free(p1);
2226
+ return POOL_ERROR;
2227
+ }
2228
+
2229
+ free(p1);
2230
+ p1 = p2;
2231
+ len1 = strlen(p2) + 1;
2232
+ }
2233
+
2234
+ pool_write(frontend, "C", 1);
2235
+ sendlen = htonl(len1+4);
2236
+ pool_write(frontend, &sendlen, sizeof(sendlen));
2237
+ pool_write_and_flush(frontend, p1, len1);
2238
+ }
2239
+
2240
+ /* save the received result for each kind */
2241
+ if (pool_config->enable_query_cache && SYSDB_STATUS == CON_UP)
2242
+ {
2243
+ query_cache_register('C', frontend, backend->info->database, p1, len1);
2244
+ }
2245
+
2246
+ /* Save the received result to buffer for each kind */
2247
+ if (pool_config->memory_cache_enabled)
2248
+ {
2249
+ if (pool_is_cache_safe() && !pool_is_cache_exceeded())
2250
+ {
2251
+ memqcache_register('C', frontend, p1, len1);
2252
+ }
2253
+ }
2254
+
2255
+ free(p1);
2256
+
2257
+ if (pool_is_doing_extended_query_message())
2258
+ {
2259
+ pool_set_query_state(session_context->query_context, POOL_EXECUTE_COMPLETE);
2260
+ }
2261
+
2262
+ return POOL_CONTINUE;
2263
+ }
2264
+
2265
+ POOL_STATUS ErrorResponse3(POOL_CONNECTION *frontend,
2266
+ POOL_CONNECTION_POOL *backend)
2267
+ {
2268
+ POOL_STATUS ret;
2269
+
2270
+ ret = SimpleForwardToFrontend('E', frontend, backend);
2271
+ if (ret != POOL_CONTINUE)
2272
+ return ret;
2273
+
2274
+ ret = raise_intentional_error_if_need(backend);
2275
+ if (ret != POOL_CONTINUE)
2276
+ return ret;
2277
+
2278
+ #ifdef NOT_USED
2279
+ for (i = 0;i < NUM_BACKENDS; i++)
2280
+ {
2281
+ if (VALID_BACKEND(i))
2282
+ {
2283
+ POOL_CONNECTION *cp = CONNECTION(backend, i);
2284
+
2285
+ /* We need to send "sync" message to backend in extend mode
2286
+ * so that it accepts next command.
2287
+ * Note that this may be overkill since client may send
2288
+ * it by itself. Moreover we do not need it in non-extend mode.
2289
+ * At this point we regard it is not harmful since error response
2290
+ * will not be sent too frequently.
2291
+ */
2292
+ pool_write(cp, "S", 1);
2293
+ res1 = htonl(4);
2294
+ if (pool_write_and_flush(cp, &res1, sizeof(res1)) < 0)
2295
+ {
2296
+ return POOL_END;
2297
+ }
2298
+ }
2299
+ }
2300
+
2301
+ while ((ret = read_kind_from_backend(frontend, backend, &kind1)) == POOL_CONTINUE)
2302
+ {
2303
+ if (kind1 == 'Z') /* ReadyForQuery? */
2304
+ break;
2305
+
2306
+ ret = SimpleForwardToFrontend(kind1, frontend, backend);
2307
+ if (ret != POOL_CONTINUE)
2308
+ return ret;
2309
+ pool_flush(frontend);
2310
+ }
2311
+
2312
+ if (ret != POOL_CONTINUE)
2313
+ return ret;
2314
+
2315
+ for (i = 0; i < NUM_BACKENDS; i++)
2316
+ {
2317
+ if (VALID_BACKEND(i))
2318
+ {
2319
+ status = pool_read(CONNECTION(backend, i), &res1, sizeof(res1));
2320
+ if (status < 0)
2321
+ {
2322
+ pool_error("SimpleForwardToFrontend: error while reading message length");
2323
+ return POOL_END;
2324
+ }
2325
+ res1 = ntohl(res1) - sizeof(res1);
2326
+ p1 = pool_read2(CONNECTION(backend, i), res1);
2327
+ if (p1 == NULL)
2328
+ return POOL_END;
2329
+ }
2330
+ }
2331
+ #endif
2332
+
2333
+ return POOL_CONTINUE;
2334
+ }
2335
+
2336
+ POOL_STATUS FunctionCall(POOL_CONNECTION *frontend,
2337
+ POOL_CONNECTION_POOL *backend)
2338
+ {
2339
+ char dummy[2];
2340
+ int oid;
2341
+ int argn;
2342
+ int i;
2343
+
2344
+ for (i=0;i<NUM_BACKENDS;i++)
2345
+ {
2346
+ if (VALID_BACKEND(i))
2347
+ {
2348
+ pool_write(CONNECTION(backend, i), "F", 1);
2349
+ }
2350
+ }
2351
+
2352
+ /* dummy */
2353
+ if (pool_read(frontend, dummy, sizeof(dummy)) < 0)
2354
+ return POOL_ERROR;
2355
+
2356
+ for (i=0;i<NUM_BACKENDS;i++)
2357
+ {
2358
+ if (VALID_BACKEND(i))
2359
+ {
2360
+ pool_write(CONNECTION(backend, i), dummy, sizeof(dummy));
2361
+ }
2362
+ }
2363
+
2364
+ /* function object id */
2365
+ if (pool_read(frontend, &oid, sizeof(oid)) < 0)
2366
+ return POOL_ERROR;
2367
+
2368
+ for (i=0;i<NUM_BACKENDS;i++)
2369
+ {
2370
+ if (VALID_BACKEND(i))
2371
+ {
2372
+ pool_write(CONNECTION(backend, i), &oid, sizeof(oid));
2373
+ }
2374
+ }
2375
+
2376
+ /* number of arguments */
2377
+ if (pool_read(frontend, &argn, sizeof(argn)) < 0)
2378
+ return POOL_ERROR;
2379
+
2380
+ for (i=0;i<NUM_BACKENDS;i++)
2381
+ {
2382
+ if (VALID_BACKEND(i))
2383
+ {
2384
+ pool_write(CONNECTION(backend, i), &argn, sizeof(argn));
2385
+ }
2386
+ }
2387
+
2388
+ argn = ntohl(argn);
2389
+
2390
+ for (i=0;i<argn;i++)
2391
+ {
2392
+ int len;
2393
+ char *arg;
2394
+
2395
+ /* length of each argument in bytes */
2396
+ if (pool_read(frontend, &len, sizeof(len)) < 0)
2397
+ return POOL_ERROR;
2398
+
2399
+ for (i=0;i<NUM_BACKENDS;i++)
2400
+ {
2401
+ if (VALID_BACKEND(i))
2402
+ {
2403
+ pool_write(CONNECTION(backend, i), &len, sizeof(len));
2404
+ }
2405
+ }
2406
+
2407
+ len = ntohl(len);
2408
+
2409
+ /* argument value itself */
2410
+ if ((arg = pool_read2(frontend, len)) == NULL)
2411
+ return POOL_ERROR;
2412
+
2413
+ for (i=0;i<NUM_BACKENDS;i++)
2414
+ {
2415
+ if (VALID_BACKEND(i))
2416
+ {
2417
+ pool_write(CONNECTION(backend, i), arg, len);
2418
+ }
2419
+ }
2420
+ }
2421
+
2422
+ for (i=0;i<NUM_BACKENDS;i++)
2423
+ {
2424
+ if (VALID_BACKEND(i))
2425
+ {
2426
+ if (pool_flush(CONNECTION(backend, i)))
2427
+ return POOL_ERROR;
2428
+ }
2429
+ }
2430
+ return POOL_CONTINUE;
2431
+ }
2432
+
2433
+ POOL_STATUS ProcessFrontendResponse(POOL_CONNECTION *frontend,
2434
+ POOL_CONNECTION_POOL *backend)
2435
+ {
2436
+ char fkind;
2437
+ char *bufp = NULL;
2438
+ char *contents;
2439
+ POOL_STATUS status;
2440
+ int len;
2441
+ POOL_SESSION_CONTEXT *session_context;
2442
+
2443
+ /* Get session context */
2444
+ session_context = pool_get_session_context();
2445
+ if (!session_context)
2446
+ {
2447
+ pool_error("Parse: cannot get session context");
2448
+ return POOL_END;
2449
+ }
2450
+
2451
+ if (pool_read_buffer_is_empty(frontend) && frontend->no_forward != 0)
2452
+ return POOL_CONTINUE;
2453
+
2454
+ if (pool_read(frontend, &fkind, 1) < 0)
2455
+ {
2456
+ pool_log("ProcessFrontendResponse: failed to read kind from frontend. frontend abnormally exited");
2457
+ return POOL_END;
2458
+ }
2459
+
2460
+ pool_debug("ProcessFrontendResponse: kind from frontend %c(%02x)", fkind, fkind);
2461
+
2462
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2463
+ {
2464
+ if (pool_read(frontend, &len, sizeof(len)) < 0)
2465
+ return POOL_END;
2466
+ len = ntohl(len) - 4;
2467
+ if (len > 0)
2468
+ bufp = pool_read2(frontend, len);
2469
+ }
2470
+ else
2471
+ {
2472
+ if (fkind != 'F')
2473
+ bufp = pool_read_string(frontend, &len, 0);
2474
+ }
2475
+
2476
+ if (len > 0 && bufp == NULL)
2477
+ return POOL_END;
2478
+
2479
+ if (fkind != 'S' && pool_is_ignore_till_sync())
2480
+ {
2481
+ /*
2482
+ * Flag setting for calling ProcessBackendResponse()
2483
+ * in pool_process_query().
2484
+ */
2485
+ if (!pool_is_query_in_progress())
2486
+ pool_set_query_in_progress();
2487
+ return POOL_CONTINUE;
2488
+ }
2489
+
2490
+ pool_unset_doing_extended_query_message();
2491
+
2492
+ /*
2493
+ * Allocate buffer and copy the packet contents. Because inside
2494
+ * these protocol modules, pool_read2 maybe called and modify its
2495
+ * buffer contents.
2496
+ */
2497
+ contents = malloc(len);
2498
+ if (contents == NULL)
2499
+ {
2500
+ pool_error("ProcessFrontendResponse: cannot allocate memory. request size:%d", len);
2501
+ return POOL_ERROR;
2502
+ }
2503
+ memcpy(contents, bufp, len);
2504
+
2505
+ switch (fkind)
2506
+ {
2507
+ POOL_QUERY_CONTEXT *query_context;
2508
+ char *query;
2509
+ Node *node;
2510
+ List *parse_tree_list;
2511
+ POOL_MEMORY_POOL *old_context;
2512
+
2513
+ case 'X': /* Terminate */
2514
+ free(contents);
2515
+ return POOL_END;
2516
+
2517
+ case 'Q': /* Query */
2518
+ allow_close_transaction = 1;
2519
+ status = SimpleQuery(frontend, backend, len, contents);
2520
+ break;
2521
+
2522
+ case 'E': /* Execute */
2523
+ allow_close_transaction = 1;
2524
+ pool_set_doing_extended_query_message();
2525
+ if (!pool_is_query_in_progress() && !pool_is_ignore_till_sync())
2526
+ pool_set_query_in_progress();
2527
+ status = Execute(frontend, backend, len, contents);
2528
+ break;
2529
+
2530
+ case 'P': /* Parse */
2531
+ allow_close_transaction = 0;
2532
+ pool_set_doing_extended_query_message();
2533
+ if (!pool_is_query_in_progress() && !pool_is_ignore_till_sync())
2534
+ pool_set_query_in_progress();
2535
+ status = Parse(frontend, backend, len, contents);
2536
+ break;
2537
+
2538
+ case 'B': /* Bind */
2539
+ pool_set_doing_extended_query_message();
2540
+ if (!pool_is_query_in_progress() && !pool_is_ignore_till_sync())
2541
+ pool_set_query_in_progress();
2542
+ status = Bind(frontend, backend, len, contents);
2543
+ break;
2544
+
2545
+ case 'C': /* Close */
2546
+ if (!pool_is_query_in_progress() && !pool_is_ignore_till_sync())
2547
+ pool_set_query_in_progress();
2548
+ status = Close(frontend, backend, len, contents);
2549
+ break;
2550
+
2551
+ case 'D': /* Describe */
2552
+ pool_set_doing_extended_query_message();
2553
+ if (!pool_is_query_in_progress() && !pool_is_ignore_till_sync())
2554
+ pool_set_query_in_progress();
2555
+ status = Describe(frontend, backend, len, contents);
2556
+ break;
2557
+
2558
+ case 'S': /* Sync */
2559
+ pool_set_doing_extended_query_message();
2560
+ if (pool_is_ignore_till_sync())
2561
+ pool_unset_ignore_till_sync();
2562
+ if (!pool_is_query_in_progress())
2563
+ pool_set_query_in_progress();
2564
+ status = SimpleForwardToBackend(fkind, frontend, backend, len, contents);
2565
+ break;
2566
+
2567
+ case 'F': /* FunctionCall */
2568
+ /*
2569
+ * Create dummy query context as if it were an INSERT.
2570
+ */
2571
+ query_context = pool_init_query_context();
2572
+ if (!query_context)
2573
+ {
2574
+ pool_error("ProcessFrontendResponse: pool_init_query_context failed");
2575
+ free(contents);
2576
+ return POOL_END;
2577
+ }
2578
+ old_context = pool_memory_context_switch_to(query_context->memory_context);
2579
+ query = "INSERT INTO foo VALUES(1)";
2580
+ parse_tree_list = raw_parser(query);
2581
+ node = (Node *) lfirst(list_head(parse_tree_list));
2582
+ pool_start_query(query_context, query, strlen(query) + 1, node);
2583
+ pool_where_to_send(query_context, query_context->original_query,
2584
+ query_context->parse_tree);
2585
+
2586
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2587
+ status = FunctionCall3(frontend, backend, len, contents);
2588
+ else
2589
+ status = FunctionCall(frontend, backend);
2590
+
2591
+ pool_memory_context_switch_to(old_context);
2592
+ break;
2593
+
2594
+ case 'c': /* CopyDone */
2595
+ case 'd': /* CopyData */
2596
+ case 'f': /* CopyFail */
2597
+ case 'H': /* Flush */
2598
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2599
+ {
2600
+ status = SimpleForwardToBackend(fkind, frontend, backend, len, contents);
2601
+ break;
2602
+ }
2603
+
2604
+ default:
2605
+ pool_error("ProcessFrontendResponse: unknown message type %c(%02x)", fkind, fkind);
2606
+ status = POOL_ERROR;
2607
+ }
2608
+ free(contents);
2609
+
2610
+ if (status != POOL_CONTINUE)
2611
+ status = POOL_ERROR;
2612
+ return status;
2613
+ }
2614
+
2615
+ POOL_STATUS ProcessBackendResponse(POOL_CONNECTION *frontend,
2616
+ POOL_CONNECTION_POOL *backend,
2617
+ int *state, short *num_fields)
2618
+ {
2619
+ int status;
2620
+ char kind;
2621
+ POOL_SESSION_CONTEXT *session_context;
2622
+
2623
+ /* Get session context */
2624
+ session_context = pool_get_session_context();
2625
+ if (!session_context)
2626
+ {
2627
+ pool_error("ProcessBackendResponse: cannot get session context");
2628
+ return POOL_END;
2629
+ }
2630
+
2631
+ if (pool_is_ignore_till_sync())
2632
+ {
2633
+ if (pool_is_query_in_progress())
2634
+ pool_unset_query_in_progress();
2635
+ return POOL_CONTINUE;
2636
+ }
2637
+
2638
+ if (pool_is_skip_reading_from_backends())
2639
+ {
2640
+ pool_unset_skip_reading_from_backends();
2641
+ return POOL_CONTINUE;
2642
+ }
2643
+
2644
+ status = read_kind_from_backend(frontend, backend, &kind);
2645
+ if (status != POOL_CONTINUE)
2646
+ return status;
2647
+
2648
+ /*
2649
+ * Sanity check
2650
+ */
2651
+ if (kind == 0)
2652
+ {
2653
+ pool_error("ProcessBackendResponse: kind is 0!");
2654
+ return POOL_ERROR;
2655
+ }
2656
+
2657
+ pool_debug("ProcessBackendResponse: kind from backend: %c", kind);
2658
+
2659
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2660
+ {
2661
+ switch (kind)
2662
+ {
2663
+ case 'G': /* CopyInResponse */
2664
+ status = CopyInResponse(frontend, backend);
2665
+ break;
2666
+
2667
+ case 'S': /* ParameterStatus */
2668
+ status = ParameterStatus(frontend, backend);
2669
+ break;
2670
+
2671
+ case 'Z': /* ReadyForQuery */
2672
+ status = ReadyForQuery(frontend, backend, true, true);
2673
+ pool_debug("ProcessBackendResponse: Ready For Query");
2674
+ break;
2675
+
2676
+ case '1': /* ParseComplete */
2677
+ status = ParseComplete(frontend, backend);
2678
+ pool_set_command_success();
2679
+ pool_unset_query_in_progress();
2680
+ break;
2681
+
2682
+ case '2': /* BindComplete */
2683
+ status = BindComplete(frontend, backend);
2684
+ pool_set_command_success();
2685
+ pool_unset_query_in_progress();
2686
+ break;
2687
+
2688
+ case '3': /* CloseComplete */
2689
+ status = CloseComplete(frontend, backend);
2690
+ pool_set_command_success();
2691
+ pool_unset_query_in_progress();
2692
+ break;
2693
+
2694
+ case 'E': /* ErrorResponse */
2695
+ status = ErrorResponse3(frontend, backend);
2696
+ pool_unset_command_success();
2697
+ if (TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID :
2698
+ REAL_MASTER_NODE_ID) != 'I')
2699
+ pool_set_failed_transaction();
2700
+ if (pool_is_doing_extended_query_message())
2701
+ {
2702
+ pool_set_ignore_till_sync();
2703
+ pool_unset_query_in_progress();
2704
+ }
2705
+ break;
2706
+
2707
+ case 'C': /* CommandComplete */
2708
+ status = CommandComplete(frontend, backend);
2709
+ pool_set_command_success();
2710
+ if (pool_is_doing_extended_query_message())
2711
+ pool_unset_query_in_progress();
2712
+ break;
2713
+
2714
+ case 'I': /* EmptyQueryResponse */
2715
+ status = SimpleForwardToFrontend(kind, frontend, backend);
2716
+ if (pool_is_doing_extended_query_message())
2717
+ pool_unset_query_in_progress();
2718
+ break;
2719
+
2720
+ case 'T': /* RowDescription */
2721
+ status = SimpleForwardToFrontend(kind, frontend, backend);
2722
+ if (pool_is_doing_extended_query_message())
2723
+ pool_unset_query_in_progress();
2724
+ break;
2725
+
2726
+ case 'n': /* NoData */
2727
+ status = SimpleForwardToFrontend(kind, frontend, backend);
2728
+ if (pool_is_doing_extended_query_message())
2729
+ pool_unset_query_in_progress();
2730
+ break;
2731
+
2732
+ case 's': /* PortalSuspended */
2733
+ status = SimpleForwardToFrontend(kind, frontend, backend);
2734
+ if (pool_is_doing_extended_query_message())
2735
+ pool_unset_query_in_progress();
2736
+ break;
2737
+
2738
+ default:
2739
+ status = SimpleForwardToFrontend(kind, frontend, backend);
2740
+ if (pool_flush(frontend))
2741
+ return POOL_END;
2742
+ break;
2743
+ }
2744
+ }
2745
+ else
2746
+ {
2747
+ switch (kind)
2748
+ {
2749
+ case 'A': /* NotificationResponse */
2750
+ status = NotificationResponse(frontend, backend);
2751
+ break;
2752
+
2753
+ case 'B': /* BinaryRow */
2754
+ status = BinaryRow(frontend, backend, *num_fields);
2755
+ break;
2756
+
2757
+ case 'C': /* CompletedResponse */
2758
+ status = CompletedResponse(frontend, backend);
2759
+ break;
2760
+
2761
+ case 'D': /* AsciiRow */
2762
+ status = AsciiRow(frontend, backend, *num_fields);
2763
+ break;
2764
+
2765
+ case 'E': /* ErrorResponse */
2766
+ status = ErrorResponse(frontend, backend);
2767
+ if (TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID :
2768
+ REAL_MASTER_NODE_ID) != 'I')
2769
+ pool_set_failed_transaction();
2770
+ break;
2771
+
2772
+ case 'G': /* CopyInResponse */
2773
+ status = CopyInResponse(frontend, backend);
2774
+ break;
2775
+
2776
+ case 'H': /* CopyOutResponse */
2777
+ status = CopyOutResponse(frontend, backend);
2778
+ break;
2779
+
2780
+ case 'I': /* EmptyQueryResponse */
2781
+ status = EmptyQueryResponse(frontend, backend);
2782
+ break;
2783
+
2784
+ case 'N': /* NoticeResponse */
2785
+ status = NoticeResponse(frontend, backend);
2786
+ break;
2787
+
2788
+ case 'P': /* CursorResponse */
2789
+ status = CursorResponse(frontend, backend);
2790
+ break;
2791
+
2792
+ case 'T': /* RowDescription */
2793
+ status = RowDescription(frontend, backend, num_fields);
2794
+ break;
2795
+
2796
+ case 'V': /* FunctionResultResponse and FunctionVoidResponse */
2797
+ status = FunctionResultResponse(frontend, backend);
2798
+ break;
2799
+
2800
+ case 'Z': /* ReadyForQuery */
2801
+ status = ReadyForQuery(frontend, backend, true, true);
2802
+ break;
2803
+
2804
+ default:
2805
+ pool_error("Unknown message type %c(%02x)", kind, kind);
2806
+ exit(1);
2807
+ }
2808
+ }
2809
+
2810
+ /* Do we receive ready for query while processing reset
2811
+ * request?
2812
+ */
2813
+ if (kind == 'Z' && frontend->no_forward && *state == 1)
2814
+ {
2815
+ *state = 0;
2816
+ }
2817
+
2818
+ if (status != POOL_CONTINUE)
2819
+ status = POOL_ERROR;
2820
+ return status;
2821
+ }
2822
+
2823
+ POOL_STATUS CopyInResponse(POOL_CONNECTION *frontend,
2824
+ POOL_CONNECTION_POOL *backend)
2825
+ {
2826
+ POOL_STATUS status;
2827
+
2828
+ /* forward to the frontend */
2829
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2830
+ {
2831
+ if (SimpleForwardToFrontend('G', frontend, backend) != POOL_CONTINUE)
2832
+ return POOL_END;
2833
+ if (pool_flush(frontend) != POOL_CONTINUE)
2834
+ return POOL_END;
2835
+ }
2836
+ else
2837
+ if (pool_write_and_flush(frontend, "G", 1) < 0)
2838
+ return POOL_END;
2839
+
2840
+ status = CopyDataRows(frontend, backend, 1);
2841
+ return status;
2842
+ }
2843
+
2844
+ POOL_STATUS CopyOutResponse(POOL_CONNECTION *frontend,
2845
+ POOL_CONNECTION_POOL *backend)
2846
+ {
2847
+ POOL_STATUS status;
2848
+
2849
+ /* forward to the frontend */
2850
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2851
+ {
2852
+ if (SimpleForwardToFrontend('H', frontend, backend) != POOL_CONTINUE)
2853
+ return POOL_END;
2854
+ if (pool_flush(frontend) != POOL_CONTINUE)
2855
+ return POOL_END;
2856
+ }
2857
+ else
2858
+ if (pool_write_and_flush(frontend, "H", 1) < 0)
2859
+ return POOL_END;
2860
+
2861
+ status = CopyDataRows(frontend, backend, 0);
2862
+ return status;
2863
+ }
2864
+
2865
+ POOL_STATUS CopyDataRows(POOL_CONNECTION *frontend,
2866
+ POOL_CONNECTION_POOL *backend, int copyin)
2867
+ {
2868
+ char *string = NULL;
2869
+ int len;
2870
+ int i;
2871
+ DistDefInfo *info = NULL;
2872
+
2873
+ #ifdef DEBUG
2874
+ int j = 0;
2875
+ char buf[1024];
2876
+ #endif
2877
+
2878
+ if (copyin && pool_config->parallel_mode == TRUE)
2879
+ {
2880
+ info = pool_get_dist_def_info(MASTER_CONNECTION(backend)->sp->database,
2881
+ copy_schema,
2882
+ copy_table);
2883
+ }
2884
+
2885
+ for (;;)
2886
+ {
2887
+ if (copyin)
2888
+ {
2889
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
2890
+ {
2891
+ char kind;
2892
+ int sendlen;
2893
+ char *p, *p1;
2894
+
2895
+ if (pool_read(frontend, &kind, 1) < 0)
2896
+ return POOL_END;
2897
+
2898
+ if (info && kind == 'd')
2899
+ {
2900
+ int id;
2901
+ if (pool_read(frontend, &sendlen, sizeof(sendlen)))
2902
+ {
2903
+ return POOL_END;
2904
+ }
2905
+
2906
+ len = ntohl(sendlen) - 4;
2907
+
2908
+ if (len <= 0)
2909
+ return POOL_CONTINUE;
2910
+
2911
+ p = pool_read2(frontend, len);
2912
+ if (p == NULL)
2913
+ return POOL_END;
2914
+
2915
+ /* copy end ? */
2916
+ if (len == 3 && memcmp(p, "\\.\n", 3) == 0)
2917
+ {
2918
+ for (i=0;i<NUM_BACKENDS;i++)
2919
+ {
2920
+ if (VALID_BACKEND(i))
2921
+ {
2922
+ if (pool_write(CONNECTION(backend, i), &kind, 1))
2923
+ return POOL_END;
2924
+ if (pool_write(CONNECTION(backend, i), &sendlen, sizeof(sendlen)))
2925
+ return POOL_END;
2926
+ if (pool_write(CONNECTION(backend, i), p, len))
2927
+ return POOL_END;
2928
+ }
2929
+ }
2930
+ }
2931
+ else
2932
+ {
2933
+ p1 = parse_copy_data(p, len, copy_delimiter, info->dist_key_col_id);
2934
+
2935
+ if (!p1)
2936
+ {
2937
+ pool_error("CopyDataRow: cannot parse data");
2938
+ return POOL_END;
2939
+ }
2940
+ else if (strcmp(p1, copy_null) == 0)
2941
+ {
2942
+ pool_error("CopyDataRow: key parameter is NULL");
2943
+ free(p1);
2944
+ return POOL_END;
2945
+ }
2946
+
2947
+ id = pool_get_id(info, p1);
2948
+ pool_debug("CopyDataRow: copying id: %d", id);
2949
+ free(p1);
2950
+ if (id < 0 || !VALID_BACKEND(id))
2951
+ {
2952
+ pool_error("CopyDataRow: pool_get_id returns invalid id: %d", id);
2953
+ exit(1);
2954
+ }
2955
+ if (pool_write(CONNECTION(backend, id), &kind, 1))
2956
+ {
2957
+ return POOL_END;
2958
+ }
2959
+ if (pool_write(CONNECTION(backend, id), &sendlen, sizeof(sendlen)))
2960
+ {
2961
+ return POOL_END;
2962
+ }
2963
+ if (pool_write_and_flush(CONNECTION(backend, id), p, len))
2964
+ {
2965
+ return POOL_END;
2966
+ }
2967
+ }
2968
+ }
2969
+ else
2970
+ {
2971
+ char *contents = NULL;
2972
+
2973
+ pool_debug("CopyDataRows: read kind from frontend %c(%02x)", kind, kind);
2974
+
2975
+ if (pool_read(frontend, &len, sizeof(len)) < 0)
2976
+ return POOL_END;
2977
+ len = ntohl(len) - 4;
2978
+ if (len > 0)
2979
+ contents = pool_read2(frontend, len);
2980
+
2981
+ SimpleForwardToBackend(kind, frontend, backend, len, contents);
2982
+ }
2983
+
2984
+ /* CopyData? */
2985
+ if (kind == 'd')
2986
+ continue;
2987
+ else
2988
+ {
2989
+ pool_debug("CopyDataRows: copyin kind other than d (%c)", kind);
2990
+ break;
2991
+ }
2992
+ }
2993
+ else
2994
+ string = pool_read_string(frontend, &len, 1);
2995
+ }
2996
+ else
2997
+ {
2998
+ /* CopyOut */
2999
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
3000
+ {
3001
+ signed char kind;
3002
+
3003
+ if ((kind = pool_read_kind(backend)) < 0)
3004
+ return POOL_END;
3005
+
3006
+ SimpleForwardToFrontend(kind, frontend, backend);
3007
+
3008
+ /* CopyData? */
3009
+ if (kind == 'd')
3010
+ continue;
3011
+ else
3012
+ break;
3013
+ }
3014
+ else
3015
+ {
3016
+ for (i=0;i<NUM_BACKENDS;i++)
3017
+ {
3018
+ if (VALID_BACKEND(i))
3019
+ {
3020
+ string = pool_read_string(CONNECTION(backend, i), &len, 1);
3021
+ }
3022
+ }
3023
+ }
3024
+ }
3025
+
3026
+ if (string == NULL)
3027
+ return POOL_END;
3028
+
3029
+ #ifdef DEBUG
3030
+ strlcpy(buf, string, sizeof(buf));
3031
+ pool_debug("copy line %d %d bytes :%s:", j++, len, buf);
3032
+ #endif
3033
+
3034
+ if (copyin)
3035
+ {
3036
+ for (i=0;i<NUM_BACKENDS;i++)
3037
+ {
3038
+ if (VALID_BACKEND(i))
3039
+ {
3040
+ pool_write(CONNECTION(backend, i), string, len);
3041
+ }
3042
+ }
3043
+ }
3044
+ else
3045
+ pool_write(frontend, string, len);
3046
+
3047
+ if (len == PROTO_MAJOR_V3)
3048
+ {
3049
+ /* end of copy? */
3050
+ if (string[0] == '\\' &&
3051
+ string[1] == '.' &&
3052
+ string[2] == '\n')
3053
+ {
3054
+ break;
3055
+ }
3056
+ }
3057
+ }
3058
+
3059
+ if (copyin)
3060
+ {
3061
+ for (i=0;i<NUM_BACKENDS;i++)
3062
+ {
3063
+ if (VALID_BACKEND(i))
3064
+ {
3065
+ if (pool_flush(CONNECTION(backend, i)) <0)
3066
+ return POOL_END;
3067
+
3068
+ if (synchronize(CONNECTION(backend, i)))
3069
+ return POOL_END;
3070
+ }
3071
+ }
3072
+ }
3073
+ else
3074
+ if (pool_flush(frontend) <0)
3075
+ return POOL_END;
3076
+
3077
+ return POOL_CONTINUE;
3078
+ }
3079
+
3080
+ /*
3081
+ * This function raises intentional error to make backends the same
3082
+ * transaction state.
3083
+ */
3084
+ POOL_STATUS raise_intentional_error_if_need(POOL_CONNECTION_POOL *backend)
3085
+ {
3086
+ int i;
3087
+ POOL_STATUS ret;
3088
+ POOL_SESSION_CONTEXT *session_context;
3089
+ POOL_QUERY_CONTEXT *query_context;
3090
+
3091
+ /* Get session context */
3092
+ session_context = pool_get_session_context();
3093
+ if (!session_context)
3094
+ {
3095
+ pool_error("raise_intentional_error_if_need: cannot get session context");
3096
+ return POOL_END;
3097
+ }
3098
+
3099
+ query_context = session_context->query_context;
3100
+
3101
+ if (MASTER_SLAVE &&
3102
+ TSTATE(backend, PRIMARY_NODE_ID) == 'T' &&
3103
+ PRIMARY_NODE_ID != MASTER_NODE_ID &&
3104
+ query_context &&
3105
+ is_select_query(query_context->parse_tree, query_context->original_query))
3106
+ {
3107
+ pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
3108
+ if (pool_is_doing_extended_query_message())
3109
+ {
3110
+ ret = do_error_execute_command(backend, PRIMARY_NODE_ID, PROTO_MAJOR_V3);
3111
+ if (ret != POOL_CONTINUE)
3112
+ return ret;
3113
+ }
3114
+ else
3115
+ {
3116
+ ret = do_error_command(CONNECTION(backend, PRIMARY_NODE_ID), MAJOR(backend));
3117
+ if (ret != POOL_CONTINUE)
3118
+ return ret;
3119
+ }
3120
+ pool_debug("raise_intentional_error: intentional error occurred");
3121
+ }
3122
+
3123
+ if (REPLICATION &&
3124
+ TSTATE(backend, REAL_MASTER_NODE_ID) == 'T' &&
3125
+ !pool_config->replicate_select &&
3126
+ query_context &&
3127
+ is_select_query(query_context->parse_tree, query_context->original_query))
3128
+ {
3129
+ pool_setall_node_to_be_sent(query_context);
3130
+ for (i = 0; i < NUM_BACKENDS; i++)
3131
+ {
3132
+ if (VALID_BACKEND(i) && REAL_MASTER_NODE_ID != i)
3133
+ {
3134
+ /*
3135
+ * We must abort transaction to sync transaction state.
3136
+ * If the error was caused by an Execute message,
3137
+ * we must send invalid Execute message to abort
3138
+ * transaction.
3139
+ *
3140
+ * Because extended query protocol ignores all
3141
+ * messages before receiving Sync message inside error state.
3142
+ */
3143
+ if (pool_is_doing_extended_query_message())
3144
+ {
3145
+ ret = do_error_execute_command(backend, i, PROTO_MAJOR_V3);
3146
+ if (ret != POOL_CONTINUE)
3147
+ return ret;
3148
+ }
3149
+ else
3150
+ {
3151
+ ret = do_error_command(CONNECTION(backend, i), MAJOR(backend));
3152
+ if (ret != POOL_CONTINUE)
3153
+ return ret;
3154
+ }
3155
+ }
3156
+ }
3157
+ }
3158
+
3159
+ return POOL_CONTINUE;
3160
+ }
3161
+
3162
+ void
3163
+ query_cache_register(char kind, POOL_CONNECTION *frontend, char *database, char *data, int data_len)
3164
+ {
3165
+ static int inside_T; /* flag to see the result data sequence */
3166
+ int result;
3167
+
3168
+ if (is_select_pgcatalog || is_select_for_update)
3169
+ return;
3170
+
3171
+ if (kind == 'T' && parsed_query)
3172
+ {
3173
+ result = pool_query_cache_register(kind, frontend, database, data, data_len, parsed_query);
3174
+ if (result < 0)
3175
+ {
3176
+ pool_error("pool_query_cache_register: query cache registration failed");
3177
+ inside_T = 0;
3178
+ }
3179
+ else
3180
+ {
3181
+ inside_T = 1;
3182
+ }
3183
+ }
3184
+ else if ((kind == 'D' || kind == 'C' || kind == 'E') && inside_T)
3185
+ {
3186
+ result = pool_query_cache_register(kind, frontend, database, data, data_len, NULL);
3187
+ if (kind == 'C' || kind == 'E' || result < 0)
3188
+ {
3189
+ if (result < 0)
3190
+ pool_error("pool_query_cache_register: query cache registration failed");
3191
+ else
3192
+ pool_debug("pool_query_cache_register: query cache saved");
3193
+
3194
+ inside_T = 0;
3195
+ free(parsed_query);
3196
+ parsed_query = NULL;
3197
+ }
3198
+ }
3199
+ }
3200
+
3201
+ /*
3202
+ * Check various errors from backend. return values: 0: no error 1:
3203
+ * deadlock detected 2: serialization error detected 3: query cancel
3204
+ * detected: 4
3205
+ */
3206
+ static int check_errors(POOL_CONNECTION_POOL *backend, int backend_id)
3207
+ {
3208
+
3209
+ /*
3210
+ * Check dead lock error on the master node and abort
3211
+ * transactions on all nodes if so.
3212
+ */
3213
+ if (detect_deadlock_error(CONNECTION(backend, backend_id), MAJOR(backend)) == SPECIFIED_ERROR)
3214
+ return 1;
3215
+
3216
+ /*
3217
+ * Check serialization failure error and abort
3218
+ * transactions on all nodes if so. Otherwise we allow
3219
+ * data inconsistency among DB nodes. See following
3220
+ * scenario: (M:master, S:slave)
3221
+ *
3222
+ * M:S1:BEGIN;
3223
+ * M:S2:BEGIN;
3224
+ * S:S1:BEGIN;
3225
+ * S:S2:BEGIN;
3226
+ * M:S1:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3227
+ * M:S2:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3228
+ * S:S1:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3229
+ * S:S2:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3230
+ * M:S1:UPDATE t1 SET i = i + 1;
3231
+ * S:S1:UPDATE t1 SET i = i + 1;
3232
+ * M:S2:UPDATE t1 SET i = i + 1; <-- blocked
3233
+ * S:S1:COMMIT;
3234
+ * M:S1:COMMIT;
3235
+ * M:S2:ERROR: could not serialize access due to concurrent update
3236
+ * S:S2:UPDATE t1 SET i = i + 1; <-- success in UPDATE and data becomes inconsistent!
3237
+ */
3238
+ if (detect_serialization_error(CONNECTION(backend, backend_id), MAJOR(backend), true) == SPECIFIED_ERROR)
3239
+ return 2;
3240
+
3241
+ /*
3242
+ * check "SET TRANSACTION ISOLATION LEVEL must be called before any query" error.
3243
+ * This happens in following scenario:
3244
+ *
3245
+ * M:S1:BEGIN;
3246
+ * S:S1:BEGIN;
3247
+ * M:S1:SELECT 1; <-- only sent to MASTER
3248
+ * M:S1:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3249
+ * S:S1:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3250
+ * M: <-- error
3251
+ * S: <-- ok since no previous SELECT is sent. kind mismatch error occurs!
3252
+ */
3253
+ if (detect_active_sql_transaction_error(CONNECTION(backend, backend_id), MAJOR(backend)) == SPECIFIED_ERROR)
3254
+ return 3;
3255
+
3256
+ /* check query cancel error */
3257
+ if (detect_query_cancel_error(CONNECTION(backend, backend_id), MAJOR(backend)) == SPECIFIED_ERROR)
3258
+ return 4;
3259
+
3260
+ return 0;
3261
+ }
3262
+
3263
+ static void generate_error_message(char *prefix, int specific_error, char *query)
3264
+ {
3265
+ POOL_SESSION_CONTEXT *session_context;
3266
+ POOL_MEMORY_POOL *old_context;
3267
+
3268
+ session_context = pool_get_session_context();
3269
+ if (!session_context)
3270
+ return;
3271
+
3272
+ static char *error_messages[] = {
3273
+ "received deadlock error message from master node. query: %s",
3274
+ "received serialization failure error message from master node. query: %s",
3275
+ "received SET TRANSACTION ISOLATION LEVEL must be called before any query error. query: %s",
3276
+ "received query cancel error message from master node. query: %s"
3277
+ };
3278
+
3279
+ String *msg;
3280
+
3281
+ if (specific_error < 1 || specific_error > sizeof(error_messages)/sizeof(char *))
3282
+ {
3283
+ pool_error("generate_error_message: invalid specific_error: %d", specific_error);
3284
+ return;
3285
+ }
3286
+
3287
+ specific_error--;
3288
+
3289
+ if (session_context->query_context)
3290
+ old_context = pool_memory_context_switch_to(session_context->query_context->memory_context);
3291
+ else
3292
+ old_context = pool_memory_context_switch_to(session_context->memory_context);
3293
+
3294
+ msg = init_string(prefix);
3295
+ string_append_char(msg, error_messages[specific_error]);
3296
+ pool_error(msg->data, query);
3297
+ free_string(msg);
3298
+
3299
+ pool_memory_context_switch_to(old_context);
3300
+ }
3301
+
3302
+ /*
3303
+ * Make per DB node statement log
3304
+ */
3305
+ void per_node_statement_log(POOL_CONNECTION_POOL *backend, int node_id, char *query)
3306
+ {
3307
+ POOL_CONNECTION_POOL_SLOT *slot = backend->slots[node_id];
3308
+
3309
+ if (pool_config->log_per_node_statement)
3310
+ pool_log("DB node id: %d backend pid: %d statement: %s", node_id, ntohl(slot->pid), query);
3311
+ }
3312
+
3313
+ /*
3314
+ * Check kind and produce error message
3315
+ * All data read in this function is returned to stream.
3316
+ */
3317
+ void per_node_error_log(POOL_CONNECTION_POOL *backend, int node_id, char *query, char *prefix, bool unread)
3318
+ {
3319
+ POOL_CONNECTION_POOL_SLOT *slot = backend->slots[node_id];
3320
+ char *message;
3321
+
3322
+ if (pool_extract_error_message(true, CONNECTION(backend, node_id), MAJOR(backend), true, &message) > 0)
3323
+ {
3324
+ pool_log("%s: DB node id: %d backend pid: %d statement: %s message: %s",
3325
+ prefix, node_id, ntohl(slot->pid), query, message);
3326
+ }
3327
+ }
3328
+
3329
+ static POOL_STATUS parse_before_bind(POOL_CONNECTION *frontend,
3330
+ POOL_CONNECTION_POOL *backend,
3331
+ POOL_SENT_MESSAGE *message)
3332
+ {
3333
+ int i;
3334
+ int len = message->len;
3335
+ char kind = '\0';
3336
+ char *contents = message->contents;
3337
+ bool parse_was_sent = false;
3338
+ bool backup[MAX_NUM_BACKENDS];
3339
+ POOL_STATUS status;
3340
+ POOL_QUERY_CONTEXT *qc = message->query_context;
3341
+
3342
+ memcpy(backup, qc->where_to_send, sizeof(qc->where_to_send));
3343
+
3344
+ /* expect to send to master node only */
3345
+ for (i = 0; i < NUM_BACKENDS; i++)
3346
+ {
3347
+ if (qc->where_to_send[i] && statecmp(qc->query_state[i], POOL_PARSE_COMPLETE) < 0)
3348
+ {
3349
+ pool_debug("parse_before_bind: waiting for backend %d completing parse", i);
3350
+ if (pool_extended_send_and_wait(qc, "P", len, contents, 1, i) != POOL_CONTINUE)
3351
+ return POOL_END;
3352
+ }
3353
+ else
3354
+ {
3355
+ qc->where_to_send[i] = 0;
3356
+ }
3357
+ }
3358
+
3359
+ for (i = 0; i < NUM_BACKENDS; i++)
3360
+ {
3361
+ if (qc->where_to_send[i])
3362
+ {
3363
+ parse_was_sent = true;
3364
+ break;
3365
+ }
3366
+ }
3367
+
3368
+ if (parse_was_sent)
3369
+ {
3370
+ while (kind != '1')
3371
+ {
3372
+ status = read_kind_from_backend(frontend, backend, &kind);
3373
+ if (status != POOL_CONTINUE)
3374
+ {
3375
+ memcpy(qc->where_to_send, backup, sizeof(backup));
3376
+ return status;
3377
+ }
3378
+ status = pool_discard_packet_contents(backend);
3379
+ if (status != POOL_CONTINUE)
3380
+ {
3381
+ memcpy(qc->where_to_send, backup, sizeof(backup));
3382
+ return status;
3383
+ }
3384
+ }
3385
+ }
3386
+
3387
+ memcpy(qc->where_to_send, backup, sizeof(backup));
3388
+ return POOL_CONTINUE;
3389
+ }
3390
+
3391
+ /*
3392
+ * Find victim nodes by "decide by majority" rule and returns array
3393
+ * of victim node ids. If no victim is found, return NULL.
3394
+ *
3395
+ * Arguments:
3396
+ * ntuples: Array of number of affected tuples. -1 represents down node.
3397
+ * nmembers: Number of elements in ntuples.
3398
+ * master_node: The master node id. Less than 0 means ignore this parameter.
3399
+ * number_of_nodes: Number of elements in victim nodes array.
3400
+ *
3401
+ * Note: If no one wins and master_node >= 0, winner would be the
3402
+ * master and other nodes who has same number of tuples as the master.
3403
+ *
3404
+ * Caution: Returned victim node array is allocated in static memory
3405
+ * of this function. Subsequent calls to this function will overwrite
3406
+ * the memory.
3407
+ */
3408
+ static int* find_victim_nodes(int *ntuples, int nmembers, int master_node, int *number_of_nodes)
3409
+ {
3410
+ static int victim_nodes[MAX_NUM_BACKENDS];
3411
+ static int votes[MAX_NUM_BACKENDS];
3412
+ int maxvotes;
3413
+ int majority_ntuples;
3414
+ int me;
3415
+ int cnt;
3416
+ int healthy_nodes;
3417
+ int i, j;
3418
+
3419
+ healthy_nodes = 0;
3420
+ *number_of_nodes = 0;
3421
+ maxvotes = 0;
3422
+ majority_ntuples = 0;
3423
+
3424
+ for (i=0;i<nmembers;i++)
3425
+ {
3426
+ me = ntuples[i];
3427
+
3428
+ /* Health node? */
3429
+ if (me < 0)
3430
+ {
3431
+ votes[i] = -1;
3432
+ continue;
3433
+ }
3434
+
3435
+ healthy_nodes++;
3436
+ votes[i] = 1;
3437
+
3438
+ for (j=0;j<nmembers;j++)
3439
+ {
3440
+ if (i != j && me == ntuples[j])
3441
+ {
3442
+ votes[i]++;
3443
+
3444
+ if (votes[i] > maxvotes)
3445
+ {
3446
+ maxvotes = votes[i];
3447
+ majority_ntuples = me;
3448
+ }
3449
+ }
3450
+ }
3451
+ }
3452
+
3453
+ /* Everyone is different */
3454
+ if (maxvotes == 1)
3455
+ {
3456
+ /* Master node is specified? */
3457
+ if (master_node < 0)
3458
+ return NULL;
3459
+
3460
+ /*
3461
+ * If master node is specified, let it and others who has same
3462
+ * ntuples win.
3463
+ */
3464
+ majority_ntuples = ntuples[master_node];
3465
+ }
3466
+ else
3467
+ {
3468
+ /* Find number of majority */
3469
+ cnt = 0;
3470
+ for (i=0;i<nmembers;i++)
3471
+ {
3472
+ if (votes[i] == maxvotes)
3473
+ {
3474
+ cnt++;
3475
+ }
3476
+ }
3477
+
3478
+ if (cnt <= healthy_nodes / 2.0)
3479
+ {
3480
+ /* No one wins */
3481
+
3482
+ /* Master node is specified? */
3483
+ if (master_node < 0)
3484
+ return NULL;
3485
+
3486
+ /*
3487
+ * If master node is specified, let it and others who has same
3488
+ * ntuples win.
3489
+ */
3490
+ majority_ntuples = ntuples[master_node];
3491
+ }
3492
+ }
3493
+
3494
+ /* Make victim nodes list */
3495
+ for (i=0;i<nmembers;i++)
3496
+ {
3497
+ if (ntuples[i] >= 0 && ntuples[i] != majority_ntuples)
3498
+ {
3499
+ victim_nodes[(*number_of_nodes)++] = i;
3500
+ }
3501
+ }
3502
+
3503
+ return victim_nodes;
3504
+ }
3505
+
3506
+ /*
3507
+ * Extract the number of tuples from CommandComplete message
3508
+ */
3509
+ static int extract_ntuples(char *message)
3510
+ {
3511
+ char *rows;
3512
+
3513
+ if ((rows = strstr(message, "UPDATE")) || (rows = strstr(message, "DELETE")))
3514
+ rows +=7;
3515
+ else if ((rows = strstr(message, "INSERT")))
3516
+ {
3517
+ rows += 7;
3518
+ while (*rows && *rows != ' ') rows++;
3519
+ }
3520
+ else
3521
+ return 0;
3522
+
3523
+ return atoi(rows);
3524
+ }