prestogres 0.1.0

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