PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/pgsql/pgsql.c

http://github.com/php/php-src
C | 7202 lines | 5778 code | 805 blank | 619 comment | 1478 complexity | 38495fc75f0dc23018d5a5adc7c27896 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Zeev Suraski <zeev@php.net> |
  14. | Jouni Ahto <jouni.ahto@exdec.fi> |
  15. | Yasuo Ohgaki <yohgaki@php.net> |
  16. | Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*) |
  17. | Chris Kings-Lynne <chriskl@php.net> (v3 protocol) |
  18. +----------------------------------------------------------------------+
  19. */
  20. #include <stdlib.h>
  21. #define PHP_PGSQL_PRIVATE 1
  22. #ifdef HAVE_CONFIG_H
  23. #include "config.h"
  24. #endif
  25. #define SMART_STR_PREALLOC 512
  26. #include "php.h"
  27. #include "php_ini.h"
  28. #include "ext/standard/php_standard.h"
  29. #include "zend_smart_str.h"
  30. #include "ext/pcre/php_pcre.h"
  31. #ifdef PHP_WIN32
  32. # include "win32/time.h"
  33. #endif
  34. #include "php_pgsql.h"
  35. #include "php_globals.h"
  36. #include "zend_exceptions.h"
  37. #if HAVE_PGSQL
  38. #ifndef InvalidOid
  39. #define InvalidOid ((Oid) 0)
  40. #endif
  41. #define PGSQL_ASSOC 1<<0
  42. #define PGSQL_NUM 1<<1
  43. #define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
  44. #define PGSQL_NOTICE_LAST 1 /* Get the last notice */
  45. #define PGSQL_NOTICE_ALL 2 /* Get all notices */
  46. #define PGSQL_NOTICE_CLEAR 3 /* Remove notices */
  47. #define PGSQL_STATUS_LONG 1
  48. #define PGSQL_STATUS_STRING 2
  49. #define PGSQL_MAX_LENGTH_OF_LONG 30
  50. #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
  51. #if ZEND_LONG_MAX < UINT_MAX
  52. #define PGSQL_RETURN_OID(oid) do { \
  53. if (oid > ZEND_LONG_MAX) { \
  54. smart_str s = {0}; \
  55. smart_str_append_unsigned(&s, oid); \
  56. smart_str_0(&s); \
  57. RETURN_NEW_STR(s.s); \
  58. } \
  59. RETURN_LONG((zend_long)oid); \
  60. } while(0)
  61. #else
  62. #define PGSQL_RETURN_OID(oid) RETURN_LONG((zend_long)oid)
  63. #endif
  64. #if HAVE_PQSETNONBLOCKING
  65. #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
  66. #else
  67. #define PQ_SETNONBLOCKING(pg_link, flag) 0
  68. #endif
  69. #define CHECK_DEFAULT_LINK(x) if ((x) == NULL) { php_error_docref(NULL, E_WARNING, "No PostgreSQL link opened yet"); RETURN_FALSE; }
  70. #define FETCH_DEFAULT_LINK() PGG(default_link)
  71. #ifndef HAVE_PQFREEMEM
  72. #define PQfreemem free
  73. #endif
  74. ZEND_DECLARE_MODULE_GLOBALS(pgsql)
  75. static PHP_GINIT_FUNCTION(pgsql);
  76. /* {{{ arginfo */
  77. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1)
  78. ZEND_ARG_INFO(0, connection_string)
  79. ZEND_ARG_INFO(0, connect_type)
  80. ZEND_ARG_INFO(0, host)
  81. ZEND_ARG_INFO(0, port)
  82. ZEND_ARG_INFO(0, options)
  83. ZEND_ARG_INFO(0, tty)
  84. ZEND_ARG_INFO(0, database)
  85. ZEND_END_ARG_INFO()
  86. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1)
  87. ZEND_ARG_INFO(0, connection_string)
  88. ZEND_ARG_INFO(0, host)
  89. ZEND_ARG_INFO(0, port)
  90. ZEND_ARG_INFO(0, options)
  91. ZEND_ARG_INFO(0, tty)
  92. ZEND_ARG_INFO(0, database)
  93. ZEND_END_ARG_INFO()
  94. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect_poll, 0, 0, 0)
  95. ZEND_ARG_INFO(0, connection)
  96. ZEND_END_ARG_INFO()
  97. #if HAVE_PQPARAMETERSTATUS
  98. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1)
  99. ZEND_ARG_INFO(0, connection)
  100. ZEND_ARG_INFO(0, param_name)
  101. ZEND_END_ARG_INFO()
  102. #endif
  103. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0)
  104. ZEND_ARG_INFO(0, connection)
  105. ZEND_END_ARG_INFO()
  106. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0)
  107. ZEND_ARG_INFO(0, connection)
  108. ZEND_END_ARG_INFO()
  109. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0)
  110. ZEND_ARG_INFO(0, connection)
  111. ZEND_END_ARG_INFO()
  112. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0)
  113. ZEND_ARG_INFO(0, connection)
  114. ZEND_END_ARG_INFO()
  115. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0)
  116. ZEND_ARG_INFO(0, connection)
  117. ZEND_END_ARG_INFO()
  118. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0)
  119. ZEND_ARG_INFO(0, connection)
  120. ZEND_END_ARG_INFO()
  121. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0)
  122. ZEND_ARG_INFO(0, connection)
  123. ZEND_END_ARG_INFO()
  124. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0)
  125. ZEND_ARG_INFO(0, connection)
  126. ZEND_END_ARG_INFO()
  127. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0)
  128. ZEND_ARG_INFO(0, connection)
  129. ZEND_END_ARG_INFO()
  130. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0)
  131. ZEND_ARG_INFO(0, connection)
  132. ZEND_ARG_INFO(0, query)
  133. ZEND_END_ARG_INFO()
  134. #if HAVE_PQEXECPARAMS
  135. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0)
  136. ZEND_ARG_INFO(0, connection)
  137. ZEND_ARG_INFO(0, query)
  138. ZEND_ARG_INFO(0, params)
  139. ZEND_END_ARG_INFO()
  140. #endif
  141. #if HAVE_PQPREPARE
  142. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0)
  143. ZEND_ARG_INFO(0, connection)
  144. ZEND_ARG_INFO(0, stmtname)
  145. ZEND_ARG_INFO(0, query)
  146. ZEND_END_ARG_INFO()
  147. #endif
  148. #if HAVE_PQEXECPREPARED
  149. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0)
  150. ZEND_ARG_INFO(0, connection)
  151. ZEND_ARG_INFO(0, stmtname)
  152. ZEND_ARG_INFO(0, params)
  153. ZEND_END_ARG_INFO()
  154. #endif
  155. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1)
  156. ZEND_ARG_INFO(0, result)
  157. ZEND_END_ARG_INFO()
  158. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1)
  159. ZEND_ARG_INFO(0, result)
  160. ZEND_END_ARG_INFO()
  161. #if HAVE_PQCMDTUPLES
  162. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1)
  163. ZEND_ARG_INFO(0, result)
  164. ZEND_END_ARG_INFO()
  165. #endif
  166. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1)
  167. ZEND_ARG_INFO(0, connection)
  168. ZEND_ARG_INFO(0, option)
  169. ZEND_END_ARG_INFO()
  170. #ifdef HAVE_PQFTABLE
  171. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2)
  172. ZEND_ARG_INFO(0, result)
  173. ZEND_ARG_INFO(0, field_number)
  174. ZEND_ARG_INFO(0, oid_only)
  175. ZEND_END_ARG_INFO()
  176. #endif
  177. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2)
  178. ZEND_ARG_INFO(0, result)
  179. ZEND_ARG_INFO(0, field_number)
  180. ZEND_END_ARG_INFO()
  181. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2)
  182. ZEND_ARG_INFO(0, result)
  183. ZEND_ARG_INFO(0, field_number)
  184. ZEND_END_ARG_INFO()
  185. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2)
  186. ZEND_ARG_INFO(0, result)
  187. ZEND_ARG_INFO(0, field_number)
  188. ZEND_END_ARG_INFO()
  189. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2)
  190. ZEND_ARG_INFO(0, result)
  191. ZEND_ARG_INFO(0, field_number)
  192. ZEND_END_ARG_INFO()
  193. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2)
  194. ZEND_ARG_INFO(0, result)
  195. ZEND_ARG_INFO(0, field_name)
  196. ZEND_END_ARG_INFO()
  197. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1)
  198. ZEND_ARG_INFO(0, result)
  199. ZEND_ARG_INFO(0, row_number)
  200. ZEND_ARG_INFO(0, field_name)
  201. ZEND_END_ARG_INFO()
  202. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1)
  203. ZEND_ARG_INFO(0, result)
  204. ZEND_ARG_INFO(0, row)
  205. ZEND_ARG_INFO(0, result_type)
  206. ZEND_END_ARG_INFO()
  207. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1)
  208. ZEND_ARG_INFO(0, result)
  209. ZEND_ARG_INFO(0, row)
  210. ZEND_END_ARG_INFO()
  211. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1)
  212. ZEND_ARG_INFO(0, result)
  213. ZEND_ARG_INFO(0, row)
  214. ZEND_ARG_INFO(0, result_type)
  215. ZEND_END_ARG_INFO()
  216. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1)
  217. ZEND_ARG_INFO(0, result)
  218. ZEND_ARG_INFO(0, row)
  219. ZEND_ARG_INFO(0, class_name)
  220. ZEND_ARG_INFO(0, l)
  221. ZEND_ARG_INFO(0, ctor_params)
  222. ZEND_END_ARG_INFO()
  223. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1)
  224. ZEND_ARG_INFO(0, result)
  225. ZEND_ARG_INFO(0, result_type)
  226. ZEND_END_ARG_INFO()
  227. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1)
  228. ZEND_ARG_INFO(0, result)
  229. ZEND_ARG_INFO(0, column_number)
  230. ZEND_END_ARG_INFO()
  231. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2)
  232. ZEND_ARG_INFO(0, result)
  233. ZEND_ARG_INFO(0, offset)
  234. ZEND_END_ARG_INFO()
  235. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1)
  236. ZEND_ARG_INFO(0, result)
  237. ZEND_ARG_INFO(0, row)
  238. ZEND_ARG_INFO(0, field_name_or_number)
  239. ZEND_END_ARG_INFO()
  240. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 0, 0, 1)
  241. ZEND_ARG_INFO(0, result)
  242. ZEND_ARG_INFO(0, row)
  243. ZEND_ARG_INFO(0, field_name_or_number)
  244. ZEND_END_ARG_INFO()
  245. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_free_result, 0, 0, 1)
  246. ZEND_ARG_INFO(0, result)
  247. ZEND_END_ARG_INFO()
  248. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1)
  249. ZEND_ARG_INFO(0, result)
  250. ZEND_END_ARG_INFO()
  251. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1)
  252. ZEND_ARG_INFO(0, filename)
  253. ZEND_ARG_INFO(0, mode)
  254. ZEND_ARG_INFO(0, connection)
  255. ZEND_END_ARG_INFO()
  256. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0)
  257. ZEND_ARG_INFO(0, connection)
  258. ZEND_END_ARG_INFO()
  259. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0)
  260. ZEND_ARG_INFO(0, connection)
  261. ZEND_ARG_INFO(0, large_object_id)
  262. ZEND_END_ARG_INFO()
  263. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0)
  264. ZEND_ARG_INFO(0, connection)
  265. ZEND_ARG_INFO(0, large_object_oid)
  266. ZEND_END_ARG_INFO()
  267. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0)
  268. ZEND_ARG_INFO(0, connection)
  269. ZEND_ARG_INFO(0, large_object_oid)
  270. ZEND_ARG_INFO(0, mode)
  271. ZEND_END_ARG_INFO()
  272. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1)
  273. ZEND_ARG_INFO(0, large_object)
  274. ZEND_END_ARG_INFO()
  275. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1)
  276. ZEND_ARG_INFO(0, large_object)
  277. ZEND_ARG_INFO(0, len)
  278. ZEND_END_ARG_INFO()
  279. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2)
  280. ZEND_ARG_INFO(0, large_object)
  281. ZEND_ARG_INFO(0, buf)
  282. ZEND_ARG_INFO(0, len)
  283. ZEND_END_ARG_INFO()
  284. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1)
  285. ZEND_ARG_INFO(0, large_object)
  286. ZEND_END_ARG_INFO()
  287. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0)
  288. ZEND_ARG_INFO(0, connection)
  289. ZEND_ARG_INFO(0, filename)
  290. ZEND_ARG_INFO(0, large_object_oid)
  291. ZEND_END_ARG_INFO()
  292. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0)
  293. ZEND_ARG_INFO(0, connection)
  294. ZEND_ARG_INFO(0, objoid)
  295. ZEND_ARG_INFO(0, filename)
  296. ZEND_END_ARG_INFO()
  297. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2)
  298. ZEND_ARG_INFO(0, large_object)
  299. ZEND_ARG_INFO(0, offset)
  300. ZEND_ARG_INFO(0, whence)
  301. ZEND_END_ARG_INFO()
  302. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1)
  303. ZEND_ARG_INFO(0, large_object)
  304. ZEND_END_ARG_INFO()
  305. #if HAVE_PG_LO_TRUNCATE
  306. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_truncate, 0, 0, 1)
  307. ZEND_ARG_INFO(0, large_object)
  308. ZEND_ARG_INFO(0, size)
  309. ZEND_END_ARG_INFO()
  310. #endif
  311. #if HAVE_PQSETERRORVERBOSITY
  312. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0)
  313. ZEND_ARG_INFO(0, connection)
  314. ZEND_ARG_INFO(0, verbosity)
  315. ZEND_END_ARG_INFO()
  316. #endif
  317. #if HAVE_PQCLIENTENCODING
  318. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0)
  319. ZEND_ARG_INFO(0, connection)
  320. ZEND_ARG_INFO(0, encoding)
  321. ZEND_END_ARG_INFO()
  322. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0)
  323. ZEND_ARG_INFO(0, connection)
  324. ZEND_END_ARG_INFO()
  325. #endif
  326. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0)
  327. ZEND_ARG_INFO(0, connection)
  328. ZEND_END_ARG_INFO()
  329. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0)
  330. ZEND_ARG_INFO(0, connection)
  331. ZEND_ARG_INFO(0, query)
  332. ZEND_END_ARG_INFO()
  333. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2)
  334. ZEND_ARG_INFO(0, connection)
  335. ZEND_ARG_INFO(0, table_name)
  336. ZEND_ARG_INFO(0, delimiter)
  337. ZEND_ARG_INFO(0, null_as)
  338. ZEND_END_ARG_INFO()
  339. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3)
  340. ZEND_ARG_INFO(0, connection)
  341. ZEND_ARG_INFO(0, table_name)
  342. ZEND_ARG_INFO(0, rows)
  343. ZEND_ARG_INFO(0, delimiter)
  344. ZEND_ARG_INFO(0, null_as)
  345. ZEND_END_ARG_INFO()
  346. #if HAVE_PQESCAPE
  347. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0)
  348. ZEND_ARG_INFO(0, connection)
  349. ZEND_ARG_INFO(0, data)
  350. ZEND_END_ARG_INFO()
  351. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0)
  352. ZEND_ARG_INFO(0, connection)
  353. ZEND_ARG_INFO(0, data)
  354. ZEND_END_ARG_INFO()
  355. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
  356. ZEND_ARG_INFO(0, data)
  357. ZEND_END_ARG_INFO()
  358. #endif
  359. #if HAVE_PQESCAPE
  360. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0)
  361. ZEND_ARG_INFO(0, connection)
  362. ZEND_ARG_INFO(0, data)
  363. ZEND_END_ARG_INFO()
  364. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0)
  365. ZEND_ARG_INFO(0, connection)
  366. ZEND_ARG_INFO(0, data)
  367. ZEND_END_ARG_INFO()
  368. #endif
  369. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
  370. ZEND_ARG_INFO(0, result)
  371. ZEND_END_ARG_INFO()
  372. #if HAVE_PQRESULTERRORFIELD
  373. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2)
  374. ZEND_ARG_INFO(0, result)
  375. ZEND_ARG_INFO(0, fieldcode)
  376. ZEND_END_ARG_INFO()
  377. #endif
  378. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1)
  379. ZEND_ARG_INFO(0, connection)
  380. ZEND_END_ARG_INFO()
  381. #if HAVE_PGTRANSACTIONSTATUS
  382. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1)
  383. ZEND_ARG_INFO(0, connection)
  384. ZEND_END_ARG_INFO()
  385. #endif
  386. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1)
  387. ZEND_ARG_INFO(0, connection)
  388. ZEND_END_ARG_INFO()
  389. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1)
  390. ZEND_ARG_INFO(0, connection)
  391. ZEND_END_ARG_INFO()
  392. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1)
  393. ZEND_ARG_INFO(0, connection)
  394. ZEND_END_ARG_INFO()
  395. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2)
  396. ZEND_ARG_INFO(0, connection)
  397. ZEND_ARG_INFO(0, query)
  398. ZEND_END_ARG_INFO()
  399. #if HAVE_PQSENDQUERYPARAMS
  400. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3)
  401. ZEND_ARG_INFO(0, connection)
  402. ZEND_ARG_INFO(0, query)
  403. ZEND_ARG_INFO(0, params)
  404. ZEND_END_ARG_INFO()
  405. #endif
  406. #if HAVE_PQSENDPREPARE
  407. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3)
  408. ZEND_ARG_INFO(0, connection)
  409. ZEND_ARG_INFO(0, stmtname)
  410. ZEND_ARG_INFO(0, query)
  411. ZEND_END_ARG_INFO()
  412. #endif
  413. #if HAVE_PQSENDQUERYPREPARED
  414. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3)
  415. ZEND_ARG_INFO(0, connection)
  416. ZEND_ARG_INFO(0, stmtname)
  417. ZEND_ARG_INFO(0, params)
  418. ZEND_END_ARG_INFO()
  419. #endif
  420. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1)
  421. ZEND_ARG_INFO(0, connection)
  422. ZEND_END_ARG_INFO()
  423. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1)
  424. ZEND_ARG_INFO(0, result)
  425. ZEND_ARG_INFO(0, result_type)
  426. ZEND_END_ARG_INFO()
  427. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0)
  428. ZEND_ARG_INFO(0, connection)
  429. ZEND_ARG_INFO(0, e)
  430. ZEND_END_ARG_INFO()
  431. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0)
  432. ZEND_ARG_INFO(0, connection)
  433. ZEND_END_ARG_INFO()
  434. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_socket, 0, 0, 1)
  435. ZEND_ARG_INFO(0, connection)
  436. ZEND_END_ARG_INFO()
  437. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_consume_input, 0, 0, 1)
  438. ZEND_ARG_INFO(0, connection)
  439. ZEND_END_ARG_INFO()
  440. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_flush, 0, 0, 1)
  441. ZEND_ARG_INFO(0, connection)
  442. ZEND_END_ARG_INFO()
  443. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2)
  444. ZEND_ARG_INFO(0, db)
  445. ZEND_ARG_INFO(0, table)
  446. ZEND_END_ARG_INFO()
  447. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3)
  448. ZEND_ARG_INFO(0, db)
  449. ZEND_ARG_INFO(0, table)
  450. ZEND_ARG_INFO(0, values)
  451. ZEND_ARG_INFO(0, options)
  452. ZEND_END_ARG_INFO()
  453. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3)
  454. ZEND_ARG_INFO(0, db)
  455. ZEND_ARG_INFO(0, table)
  456. ZEND_ARG_INFO(0, values)
  457. ZEND_ARG_INFO(0, options)
  458. ZEND_END_ARG_INFO()
  459. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4)
  460. ZEND_ARG_INFO(0, db)
  461. ZEND_ARG_INFO(0, table)
  462. ZEND_ARG_INFO(0, fields)
  463. ZEND_ARG_INFO(0, ids)
  464. ZEND_ARG_INFO(0, options)
  465. ZEND_END_ARG_INFO()
  466. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3)
  467. ZEND_ARG_INFO(0, db)
  468. ZEND_ARG_INFO(0, table)
  469. ZEND_ARG_INFO(0, ids)
  470. ZEND_ARG_INFO(0, options)
  471. ZEND_END_ARG_INFO()
  472. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3)
  473. ZEND_ARG_INFO(0, db)
  474. ZEND_ARG_INFO(0, table)
  475. ZEND_ARG_INFO(0, ids)
  476. ZEND_ARG_INFO(0, options)
  477. ZEND_ARG_INFO(0, result_type)
  478. ZEND_END_ARG_INFO()
  479. /* }}} */
  480. /* {{{ pgsql_functions[]
  481. */
  482. static const zend_function_entry pgsql_functions[] = {
  483. /* connection functions */
  484. PHP_FE(pg_connect, arginfo_pg_connect)
  485. PHP_FE(pg_pconnect, arginfo_pg_pconnect)
  486. PHP_FE(pg_connect_poll, arginfo_pg_connect_poll)
  487. PHP_FE(pg_close, arginfo_pg_close)
  488. PHP_FE(pg_connection_status, arginfo_pg_connection_status)
  489. PHP_FE(pg_connection_busy, arginfo_pg_connection_busy)
  490. PHP_FE(pg_connection_reset, arginfo_pg_connection_reset)
  491. PHP_FE(pg_host, arginfo_pg_host)
  492. PHP_FE(pg_dbname, arginfo_pg_dbname)
  493. PHP_FE(pg_port, arginfo_pg_port)
  494. PHP_FE(pg_tty, arginfo_pg_tty)
  495. PHP_FE(pg_options, arginfo_pg_options)
  496. PHP_FE(pg_version, arginfo_pg_version)
  497. PHP_FE(pg_ping, arginfo_pg_ping)
  498. #if HAVE_PQPARAMETERSTATUS
  499. PHP_FE(pg_parameter_status, arginfo_pg_parameter_status)
  500. #endif
  501. #if HAVE_PGTRANSACTIONSTATUS
  502. PHP_FE(pg_transaction_status, arginfo_pg_transaction_status)
  503. #endif
  504. /* query functions */
  505. PHP_FE(pg_query, arginfo_pg_query)
  506. #if HAVE_PQEXECPARAMS
  507. PHP_FE(pg_query_params, arginfo_pg_query_params)
  508. #endif
  509. #if HAVE_PQPREPARE
  510. PHP_FE(pg_prepare, arginfo_pg_prepare)
  511. #endif
  512. #if HAVE_PQEXECPREPARED
  513. PHP_FE(pg_execute, arginfo_pg_execute)
  514. #endif
  515. PHP_FE(pg_send_query, arginfo_pg_send_query)
  516. #if HAVE_PQSENDQUERYPARAMS
  517. PHP_FE(pg_send_query_params, arginfo_pg_send_query_params)
  518. #endif
  519. #if HAVE_PQSENDPREPARE
  520. PHP_FE(pg_send_prepare, arginfo_pg_send_prepare)
  521. #endif
  522. #if HAVE_PQSENDQUERYPREPARED
  523. PHP_FE(pg_send_execute, arginfo_pg_send_execute)
  524. #endif
  525. PHP_FE(pg_cancel_query, arginfo_pg_cancel_query)
  526. /* result functions */
  527. PHP_FE(pg_fetch_result, arginfo_pg_fetch_result)
  528. PHP_FE(pg_fetch_row, arginfo_pg_fetch_row)
  529. PHP_FE(pg_fetch_assoc, arginfo_pg_fetch_assoc)
  530. PHP_FE(pg_fetch_array, arginfo_pg_fetch_array)
  531. PHP_FE(pg_fetch_object, arginfo_pg_fetch_object)
  532. PHP_FE(pg_fetch_all, arginfo_pg_fetch_all)
  533. PHP_FE(pg_fetch_all_columns, arginfo_pg_fetch_all_columns)
  534. #if HAVE_PQCMDTUPLES
  535. PHP_FE(pg_affected_rows,arginfo_pg_affected_rows)
  536. #endif
  537. PHP_FE(pg_get_result, arginfo_pg_get_result)
  538. PHP_FE(pg_result_seek, arginfo_pg_result_seek)
  539. PHP_FE(pg_result_status,arginfo_pg_result_status)
  540. PHP_FE(pg_free_result, arginfo_pg_free_result)
  541. PHP_FE(pg_last_oid, arginfo_pg_last_oid)
  542. PHP_FE(pg_num_rows, arginfo_pg_num_rows)
  543. PHP_FE(pg_num_fields, arginfo_pg_num_fields)
  544. PHP_FE(pg_field_name, arginfo_pg_field_name)
  545. PHP_FE(pg_field_num, arginfo_pg_field_num)
  546. PHP_FE(pg_field_size, arginfo_pg_field_size)
  547. PHP_FE(pg_field_type, arginfo_pg_field_type)
  548. PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid)
  549. PHP_FE(pg_field_prtlen, arginfo_pg_field_prtlen)
  550. PHP_FE(pg_field_is_null,arginfo_pg_field_is_null)
  551. #ifdef HAVE_PQFTABLE
  552. PHP_FE(pg_field_table, arginfo_pg_field_table)
  553. #endif
  554. /* async message function */
  555. PHP_FE(pg_get_notify, arginfo_pg_get_notify)
  556. PHP_FE(pg_socket, arginfo_pg_socket)
  557. PHP_FE(pg_consume_input,arginfo_pg_consume_input)
  558. PHP_FE(pg_flush, arginfo_pg_flush)
  559. PHP_FE(pg_get_pid, arginfo_pg_get_pid)
  560. /* error message functions */
  561. PHP_FE(pg_result_error, arginfo_pg_result_error)
  562. #if HAVE_PQRESULTERRORFIELD
  563. PHP_FE(pg_result_error_field, arginfo_pg_result_error_field)
  564. #endif
  565. PHP_FE(pg_last_error, arginfo_pg_last_error)
  566. PHP_FE(pg_last_notice, arginfo_pg_last_notice)
  567. /* copy functions */
  568. PHP_FE(pg_put_line, arginfo_pg_put_line)
  569. PHP_FE(pg_end_copy, arginfo_pg_end_copy)
  570. PHP_FE(pg_copy_to, arginfo_pg_copy_to)
  571. PHP_FE(pg_copy_from, arginfo_pg_copy_from)
  572. /* debug functions */
  573. PHP_FE(pg_trace, arginfo_pg_trace)
  574. PHP_FE(pg_untrace, arginfo_pg_untrace)
  575. /* large object functions */
  576. PHP_FE(pg_lo_create, arginfo_pg_lo_create)
  577. PHP_FE(pg_lo_unlink, arginfo_pg_lo_unlink)
  578. PHP_FE(pg_lo_open, arginfo_pg_lo_open)
  579. PHP_FE(pg_lo_close, arginfo_pg_lo_close)
  580. PHP_FE(pg_lo_read, arginfo_pg_lo_read)
  581. PHP_FE(pg_lo_write, arginfo_pg_lo_write)
  582. PHP_FE(pg_lo_read_all, arginfo_pg_lo_read_all)
  583. PHP_FE(pg_lo_import, arginfo_pg_lo_import)
  584. PHP_FE(pg_lo_export, arginfo_pg_lo_export)
  585. PHP_FE(pg_lo_seek, arginfo_pg_lo_seek)
  586. PHP_FE(pg_lo_tell, arginfo_pg_lo_tell)
  587. #if HAVE_PG_LO_TRUNCATE
  588. PHP_FE(pg_lo_truncate, arginfo_pg_lo_truncate)
  589. #endif
  590. /* utility functions */
  591. #if HAVE_PQESCAPE
  592. PHP_FE(pg_escape_string, arginfo_pg_escape_string)
  593. PHP_FE(pg_escape_bytea, arginfo_pg_escape_bytea)
  594. PHP_FE(pg_unescape_bytea, arginfo_pg_unescape_bytea)
  595. PHP_FE(pg_escape_literal, arginfo_pg_escape_literal)
  596. PHP_FE(pg_escape_identifier, arginfo_pg_escape_identifier)
  597. #endif
  598. #if HAVE_PQSETERRORVERBOSITY
  599. PHP_FE(pg_set_error_verbosity, arginfo_pg_set_error_verbosity)
  600. #endif
  601. #if HAVE_PQCLIENTENCODING
  602. PHP_FE(pg_client_encoding, arginfo_pg_client_encoding)
  603. PHP_FE(pg_set_client_encoding, arginfo_pg_set_client_encoding)
  604. #endif
  605. /* misc function */
  606. PHP_FE(pg_meta_data, arginfo_pg_meta_data)
  607. PHP_FE(pg_convert, arginfo_pg_convert)
  608. PHP_FE(pg_insert, arginfo_pg_insert)
  609. PHP_FE(pg_update, arginfo_pg_update)
  610. PHP_FE(pg_delete, arginfo_pg_delete)
  611. PHP_FE(pg_select, arginfo_pg_select)
  612. /* aliases for downwards compatibility */
  613. PHP_FALIAS(pg_exec, pg_query, arginfo_pg_query)
  614. PHP_FALIAS(pg_getlastoid, pg_last_oid, arginfo_pg_last_oid)
  615. #if HAVE_PQCMDTUPLES
  616. PHP_FALIAS(pg_cmdtuples, pg_affected_rows, arginfo_pg_affected_rows)
  617. #endif
  618. PHP_FALIAS(pg_errormessage, pg_last_error, arginfo_pg_last_error)
  619. PHP_FALIAS(pg_numrows, pg_num_rows, arginfo_pg_num_rows)
  620. PHP_FALIAS(pg_numfields, pg_num_fields, arginfo_pg_num_fields)
  621. PHP_FALIAS(pg_fieldname, pg_field_name, arginfo_pg_field_name)
  622. PHP_FALIAS(pg_fieldsize, pg_field_size, arginfo_pg_field_size)
  623. PHP_FALIAS(pg_fieldtype, pg_field_type, arginfo_pg_field_type)
  624. PHP_FALIAS(pg_fieldnum, pg_field_num, arginfo_pg_field_num)
  625. PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, arginfo_pg_field_prtlen)
  626. PHP_FALIAS(pg_fieldisnull, pg_field_is_null, arginfo_pg_field_is_null)
  627. PHP_FALIAS(pg_freeresult, pg_free_result, arginfo_pg_free_result)
  628. PHP_FALIAS(pg_result, pg_fetch_result, arginfo_pg_get_result)
  629. PHP_FALIAS(pg_loreadall, pg_lo_read_all, arginfo_pg_lo_read_all)
  630. PHP_FALIAS(pg_locreate, pg_lo_create, arginfo_pg_lo_create)
  631. PHP_FALIAS(pg_lounlink, pg_lo_unlink, arginfo_pg_lo_unlink)
  632. PHP_FALIAS(pg_loopen, pg_lo_open, arginfo_pg_lo_open)
  633. PHP_FALIAS(pg_loclose, pg_lo_close, arginfo_pg_lo_close)
  634. PHP_FALIAS(pg_loread, pg_lo_read, arginfo_pg_lo_read)
  635. PHP_FALIAS(pg_lowrite, pg_lo_write, arginfo_pg_lo_write)
  636. PHP_FALIAS(pg_loimport, pg_lo_import, arginfo_pg_lo_import)
  637. PHP_FALIAS(pg_loexport, pg_lo_export, arginfo_pg_lo_export)
  638. #if HAVE_PQCLIENTENCODING
  639. PHP_FALIAS(pg_clientencoding, pg_client_encoding, arginfo_pg_client_encoding)
  640. PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, arginfo_pg_set_client_encoding)
  641. #endif
  642. PHP_FE_END
  643. };
  644. /* }}} */
  645. /* {{{ pgsql_module_entry
  646. */
  647. zend_module_entry pgsql_module_entry = {
  648. STANDARD_MODULE_HEADER,
  649. "pgsql",
  650. pgsql_functions,
  651. PHP_MINIT(pgsql),
  652. PHP_MSHUTDOWN(pgsql),
  653. PHP_RINIT(pgsql),
  654. PHP_RSHUTDOWN(pgsql),
  655. PHP_MINFO(pgsql),
  656. PHP_PGSQL_VERSION,
  657. PHP_MODULE_GLOBALS(pgsql),
  658. PHP_GINIT(pgsql),
  659. NULL,
  660. NULL,
  661. STANDARD_MODULE_PROPERTIES_EX
  662. };
  663. /* }}} */
  664. #ifdef COMPILE_DL_PGSQL
  665. #ifdef ZTS
  666. ZEND_TSRMLS_CACHE_DEFINE()
  667. #endif
  668. ZEND_GET_MODULE(pgsql)
  669. #endif
  670. static int le_link, le_plink, le_result, le_lofp, le_string;
  671. /* Compatibility definitions */
  672. #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
  673. #define pg_encoding_to_char(x) "SQL_ASCII"
  674. #endif
  675. #if !HAVE_PQESCAPE_CONN
  676. #define PQescapeStringConn(conn, to, from, len, error) PQescapeString(to, from, len)
  677. #endif
  678. #if HAVE_PQESCAPELITERAL
  679. #define PGSQLescapeLiteral(conn, str, len) PQescapeLiteral(conn, str, len)
  680. #define PGSQLescapeIdentifier(conn, str, len) PQescapeIdentifier(conn, str, len)
  681. #define PGSQLfree(a) PQfreemem(a)
  682. #else
  683. #define PGSQLescapeLiteral(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 0)
  684. #define PGSQLescapeLiteral2(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 1)
  685. #define PGSQLescapeIdentifier(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 0, 0)
  686. #define PGSQLfree(a) efree(a)
  687. /* emulate libpq's PQescapeInternal() 9.0 or later */
  688. static char *php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal, int safe) /* {{{ */
  689. {
  690. char *result, *rp, *s;
  691. if (!conn) {
  692. return NULL;
  693. }
  694. /* allocate enough memory */
  695. rp = result = (char *)safe_emalloc(len, 2, 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */
  696. if (escape_literal) {
  697. if (safe) {
  698. size_t new_len;
  699. char *tmp = (char *)safe_emalloc(len, 2, 1);
  700. *rp++ = '\'';
  701. /* PQescapeString does not escape \, but it handles multibyte chars safely.
  702. This escape is incompatible with PQescapeLiteral. */
  703. new_len = PQescapeStringConn(conn, tmp, str, len, NULL);
  704. strncpy(rp, tmp, new_len);
  705. efree(tmp);
  706. rp += new_len;
  707. } else {
  708. char *encoding;
  709. size_t tmp_len;
  710. /* This is compatible with PQescapeLiteral, but it cannot handle multbyte chars
  711. such as SJIS, BIG5. Raise warning and return NULL by checking
  712. client_encoding. */
  713. encoding = (char *) pg_encoding_to_char(PQclientEncoding(conn));
  714. if (!strncmp(encoding, "SJIS", sizeof("SJIS")-1) ||
  715. !strncmp(encoding, "SHIFT_JIS_2004", sizeof("SHIFT_JIS_2004")-1) ||
  716. !strncmp(encoding, "BIG5", sizeof("BIG5")-1) ||
  717. !strncmp(encoding, "GB18030", sizeof("GB18030")-1) ||
  718. !strncmp(encoding, "GBK", sizeof("GBK")-1) ||
  719. !strncmp(encoding, "JOHAB", sizeof("JOHAB")-1) ||
  720. !strncmp(encoding, "UHC", sizeof("UHC")-1) ) {
  721. php_error_docref(NULL, E_WARNING, "Unsafe encoding is used. Do not use '%s' encoding or use PostgreSQL 9.0 or later libpq.", encoding);
  722. }
  723. /* check backslashes */
  724. tmp_len = strspn(str, "\\");
  725. if (tmp_len != len) {
  726. /* add " E" for escaping slashes */
  727. *rp++ = ' ';
  728. *rp++ = 'E';
  729. }
  730. *rp++ = '\'';
  731. for (s = (char *)str; s - str < len; ++s) {
  732. if (*s == '\'' || *s == '\\') {
  733. *rp++ = *s;
  734. *rp++ = *s;
  735. } else {
  736. *rp++ = *s;
  737. }
  738. }
  739. }
  740. *rp++ = '\'';
  741. } else {
  742. /* Identifier escape. */
  743. *rp++ = '"';
  744. for (s = (char *)str; s - str < len; ++s) {
  745. if (*s == '"') {
  746. *rp++ = '"';
  747. *rp++ = '"';
  748. } else {
  749. *rp++ = *s;
  750. }
  751. }
  752. *rp++ = '"';
  753. }
  754. *rp = '\0';
  755. return result;
  756. }
  757. /* }}} */
  758. #endif
  759. /* {{{ _php_pgsql_trim_message */
  760. static char * _php_pgsql_trim_message(const char *message, size_t *len)
  761. {
  762. register size_t i = strlen(message);
  763. if (i>2 && (message[i-2] == '\r' || message[i-2] == '\n') && message[i-1] == '.') {
  764. --i;
  765. }
  766. while (i>1 && (message[i-1] == '\r' || message[i-1] == '\n')) {
  767. --i;
  768. }
  769. if (len) {
  770. *len = i;
  771. }
  772. return estrndup(message, i);
  773. }
  774. /* }}} */
  775. /* {{{ _php_pgsql_trim_result */
  776. static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
  777. {
  778. return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
  779. }
  780. /* }}} */
  781. #define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
  782. #define PHP_PQ_ERROR(text, pgsql) { \
  783. char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \
  784. php_error_docref(NULL, E_WARNING, text, msgbuf); \
  785. efree(msgbuf); \
  786. } \
  787. /* {{{ php_pgsql_set_default_link
  788. */
  789. static void php_pgsql_set_default_link(zend_resource *res)
  790. {
  791. GC_ADDREF(res);
  792. if (PGG(default_link) != NULL) {
  793. zend_list_delete(PGG(default_link));
  794. }
  795. PGG(default_link) = res;
  796. }
  797. /* }}} */
  798. /* {{{ _close_pgsql_link
  799. */
  800. static void _close_pgsql_link(zend_resource *rsrc)
  801. {
  802. PGconn *link = (PGconn *)rsrc->ptr;
  803. PGresult *res;
  804. zval *hash;
  805. while ((res = PQgetResult(link))) {
  806. PQclear(res);
  807. }
  808. PQfinish(link);
  809. PGG(num_links)--;
  810. /* Remove connection hash for this link */
  811. hash = zend_hash_index_find(&PGG(hashes), (uintptr_t) link);
  812. if (hash) {
  813. zend_hash_index_del(&PGG(hashes), (uintptr_t) link);
  814. zend_hash_del(&EG(regular_list), Z_STR_P(hash));
  815. }
  816. }
  817. /* }}} */
  818. /* {{{ _close_pgsql_plink
  819. */
  820. static void _close_pgsql_plink(zend_resource *rsrc)
  821. {
  822. PGconn *link = (PGconn *)rsrc->ptr;
  823. PGresult *res;
  824. while ((res = PQgetResult(link))) {
  825. PQclear(res);
  826. }
  827. PQfinish(link);
  828. PGG(num_persistent)--;
  829. PGG(num_links)--;
  830. }
  831. /* }}} */
  832. /* {{{ _php_pgsql_notice_handler
  833. */
  834. static void _php_pgsql_notice_handler(void *resource_id, const char *message)
  835. {
  836. zval *notices;
  837. zval tmp;
  838. char *trimed_message;
  839. size_t trimed_message_len;
  840. if (! PGG(ignore_notices)) {
  841. notices = zend_hash_index_find(&PGG(notices), (zend_ulong)resource_id);
  842. if (!notices) {
  843. array_init(&tmp);
  844. notices = &tmp;
  845. zend_hash_index_update(&PGG(notices), (zend_ulong)resource_id, notices);
  846. }
  847. trimed_message = _php_pgsql_trim_message(message, &trimed_message_len);
  848. if (PGG(log_notices)) {
  849. php_error_docref(NULL, E_NOTICE, "%s", trimed_message);
  850. }
  851. add_next_index_stringl(notices, trimed_message, trimed_message_len);
  852. efree(trimed_message);
  853. }
  854. }
  855. /* }}} */
  856. /* {{{ _rollback_transactions
  857. */
  858. static int _rollback_transactions(zval *el)
  859. {
  860. PGconn *link;
  861. PGresult *res;
  862. zend_resource *rsrc = Z_RES_P(el);
  863. if (rsrc->type != le_plink)
  864. return 0;
  865. link = (PGconn *) rsrc->ptr;
  866. if (PQ_SETNONBLOCKING(link, 0)) {
  867. php_error_docref("ref.pgsql", E_NOTICE, "Cannot set connection to blocking mode");
  868. return -1;
  869. }
  870. while ((res = PQgetResult(link))) {
  871. PQclear(res);
  872. }
  873. #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
  874. if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
  875. #endif
  876. {
  877. int orig = PGG(ignore_notices);
  878. PGG(ignore_notices) = 1;
  879. #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
  880. res = PQexec(link,"ROLLBACK;");
  881. #else
  882. res = PQexec(link,"BEGIN;");
  883. PQclear(res);
  884. res = PQexec(link,"ROLLBACK;");
  885. #endif
  886. PQclear(res);
  887. PGG(ignore_notices) = orig;
  888. }
  889. return 0;
  890. }
  891. /* }}} */
  892. /* {{{ _free_ptr
  893. */
  894. static void _free_ptr(zend_resource *rsrc)
  895. {
  896. pgLofp *lofp = (pgLofp *)rsrc->ptr;
  897. efree(lofp);
  898. }
  899. /* }}} */
  900. /* {{{ _free_result
  901. */
  902. static void _free_result(zend_resource *rsrc)
  903. {
  904. pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
  905. PQclear(pg_result->result);
  906. efree(pg_result);
  907. }
  908. /* }}} */
  909. static int _php_pgsql_detect_identifier_escape(const char *identifier, size_t len) /* {{{ */
  910. {
  911. /* Handle edge case. Cannot be a escaped string */
  912. if (len <= 2) {
  913. return FAILURE;
  914. }
  915. /* Detect double quotes */
  916. if (identifier[0] == '"' && identifier[len-1] == '"') {
  917. size_t i;
  918. /* Detect wrong format of " inside of escaped string */
  919. for (i = 1; i < len-1; i++) {
  920. if (identifier[i] == '"' && (identifier[++i] != '"' || i == len-1)) {
  921. return FAILURE;
  922. }
  923. }
  924. } else {
  925. return FAILURE;
  926. }
  927. /* Escaped properly */
  928. return SUCCESS;
  929. }
  930. /* }}} */
  931. /* {{{ PHP_INI
  932. */
  933. PHP_INI_BEGIN()
  934. STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
  935. STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers)
  936. STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers)
  937. STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
  938. STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals)
  939. STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals)
  940. PHP_INI_END()
  941. /* }}} */
  942. /* {{{ PHP_GINIT_FUNCTION
  943. */
  944. static PHP_GINIT_FUNCTION(pgsql)
  945. {
  946. #if defined(COMPILE_DL_PGSQL) && defined(ZTS)
  947. ZEND_TSRMLS_CACHE_UPDATE();
  948. #endif
  949. memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
  950. /* Initialize notice message hash at MINIT only */
  951. zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, ZVAL_PTR_DTOR, 1, 0);
  952. zend_hash_init_ex(&pgsql_globals->hashes, 0, NULL, ZVAL_PTR_DTOR, 1, 0);
  953. }
  954. /* }}} */
  955. /* {{{ PHP_MINIT_FUNCTION
  956. */
  957. PHP_MINIT_FUNCTION(pgsql)
  958. {
  959. REGISTER_INI_ENTRIES();
  960. le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
  961. le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
  962. le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
  963. le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
  964. le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
  965. #if HAVE_PG_CONFIG_H
  966. /* PG_VERSION - libpq version */
  967. REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", PG_VERSION, CONST_CS | CONST_PERSISTENT);
  968. REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", PG_VERSION_STR, CONST_CS | CONST_PERSISTENT);
  969. #endif
  970. /* For connection option */
  971. REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
  972. REGISTER_LONG_CONSTANT("PGSQL_CONNECT_ASYNC", PGSQL_CONNECT_ASYNC, CONST_CS | CONST_PERSISTENT);
  973. /* For pg_fetch_array() */
  974. REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
  975. REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
  976. REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
  977. /* For pg_last_notice() */
  978. REGISTER_LONG_CONSTANT("PGSQL_NOTICE_LAST", PGSQL_NOTICE_LAST, CONST_CS | CONST_PERSISTENT);
  979. REGISTER_LONG_CONSTANT("PGSQL_NOTICE_ALL", PGSQL_NOTICE_ALL, CONST_CS | CONST_PERSISTENT);
  980. REGISTER_LONG_CONSTANT("PGSQL_NOTICE_CLEAR", PGSQL_NOTICE_CLEAR, CONST_CS | CONST_PERSISTENT);
  981. /* For pg_connection_status() */
  982. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
  983. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
  984. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_STARTED", CONNECTION_STARTED, CONST_CS | CONST_PERSISTENT);
  985. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_MADE", CONNECTION_MADE, CONST_CS | CONST_PERSISTENT);
  986. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE, CONST_CS | CONST_PERSISTENT);
  987. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AUTH_OK", CONNECTION_AUTH_OK, CONST_CS | CONST_PERSISTENT);
  988. #ifdef CONNECTION_SSL_STARTUP
  989. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP, CONST_CS | CONST_PERSISTENT);
  990. #endif
  991. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SETENV", CONNECTION_SETENV, CONST_CS | CONST_PERSISTENT);
  992. /* For pg_connect_poll() */
  993. REGISTER_LONG_CONSTANT("PGSQL_POLLING_FAILED", PGRES_POLLING_FAILED, CONST_CS | CONST_PERSISTENT);
  994. REGISTER_LONG_CONSTANT("PGSQL_POLLING_READING", PGRES_POLLING_READING, CONST_CS | CONST_PERSISTENT);
  995. REGISTER_LONG_CONSTANT("PGSQL_POLLING_WRITING", PGRES_POLLING_WRITING, CONST_CS | CONST_PERSISTENT);
  996. REGISTER_LONG_CONSTANT("PGSQL_POLLING_OK", PGRES_POLLING_OK, CONST_CS | CONST_PERSISTENT);
  997. REGISTER_LONG_CONSTANT("PGSQL_POLLING_ACTIVE", PGRES_POLLING_ACTIVE, CONST_CS | CONST_PERSISTENT);
  998. #if HAVE_PGTRANSACTIONSTATUS
  999. /* For pg_transaction_status() */
  1000. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
  1001. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
  1002. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
  1003. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
  1004. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
  1005. #endif
  1006. #if HAVE_PQSETERRORVERBOSITY
  1007. /* For pg_set_error_verbosity() */
  1008. REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
  1009. REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
  1010. REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
  1011. #endif
  1012. /* For lo_seek() */
  1013. REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
  1014. REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
  1015. REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
  1016. /* For pg_result_status() return value type */
  1017. REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
  1018. REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
  1019. /* For pg_result_status() return value */
  1020. REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
  1021. REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
  1022. REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
  1023. REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
  1024. REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
  1025. REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
  1026. REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
  1027. REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
  1028. #if HAVE_PQRESULTERRORFIELD
  1029. /* For pg_result_error_field() field codes */
  1030. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
  1031. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
  1032. REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
  1033. REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
  1034. REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
  1035. REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
  1036. #ifdef PG_DIAG_INTERNAL_POSITION
  1037. REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
  1038. #endif
  1039. #ifdef PG_DIAG_INTERNAL_QUERY
  1040. REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
  1041. #endif
  1042. REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
  1043. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
  1044. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
  1045. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
  1046. #ifdef PG_DIAG_SCHEMA_NAME
  1047. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SCHEMA_NAME", PG_DIAG_SCHEMA_NAME, CONST_CS | CONST_PERSISTENT);
  1048. #endif
  1049. #ifdef PG_DIAG_TABLE_NAME
  1050. REGISTER_LONG_CONSTANT("PGSQL_DIAG_TABLE_NAME", PG_DIAG_TABLE_NAME, CONST_CS | CONST_PERSISTENT);
  1051. #endif
  1052. #ifdef PG_DIAG_COLUMN_NAME
  1053. REGISTER_LONG_CONSTANT("PGSQL_DIAG_COLUMN_NAME", PG_DIAG_COLUMN_NAME, CONST_CS | CONST_PERSISTENT);
  1054. #endif
  1055. #ifdef PG_DIAG_DATATYPE_NAME
  1056. REGISTER_LONG_CONSTANT("PGSQL_DIAG_DATATYPE_NAME", PG_DIAG_DATATYPE_NAME, CONST_CS | CONST_PERSISTENT);
  1057. #endif
  1058. #ifdef PG_DIAG_CONSTRAINT_NAME
  1059. REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONSTRAINT_NAME", PG_DIAG_CONSTRAINT_NAME, CONST_CS | CONST_PERSISTENT);
  1060. #endif
  1061. #ifdef PG_DIAG_SEVERITY_NONLOCALIZED
  1062. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY_NONLOCALIZED", PG_DIAG_SEVERITY_NONLOCALIZED, CONST_CS | CONST_PERSISTENT);
  1063. #endif
  1064. #endif
  1065. /* pg_convert options */
  1066. REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
  1067. REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
  1068. REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
  1069. /* pg_insert/update/delete/select options */
  1070. REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT);
  1071. REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
  1072. REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
  1073. REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
  1074. REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
  1075. return SUCCESS;
  1076. }
  1077. /* }}} */
  1078. /* {{{ PHP_MSHUTDOWN_FUNCTION
  1079. */
  1080. PHP_MSHUTDOWN_FUNCTION(pgsql)
  1081. {
  1082. UNREGISTER_INI_ENTRIES();
  1083. zend_hash_destroy(&PGG(notices));
  1084. zend_hash_destroy(&PGG(hashes));
  1085. return SUCCESS;
  1086. }
  1087. /* }}} */
  1088. /* {{{ PHP_RINIT_FUNCTION
  1089. */
  1090. PHP_RINIT_FUNCTION(pgsql)
  1091. {
  1092. PGG(default_link) = NULL;
  1093. PGG(num_links) = PGG(num_persistent);
  1094. return SUCCESS;
  1095. }
  1096. /* }}} */
  1097. /* {{{ PHP_RSHUTDOWN_FUNCTION
  1098. */
  1099. PHP_RSHUTDOWN_FUNCTION(pgsql)
  1100. {
  1101. /* clean up notice messages */
  1102. zend_hash_clean(&PGG(notices));
  1103. zend_hash_clean(&PGG(hashes));
  1104. /* clean up persistent connection */
  1105. zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions);
  1106. return SUCCESS;
  1107. }
  1108. /* }}} */
  1109. /* {{{ PHP_MINFO_FUNCTION
  1110. */
  1111. PHP_MINFO_FUNCTION(pgsql)
  1112. {
  1113. char buf[256];
  1114. php_info_print_table_start();
  1115. php_info_print_table_header(2, "PostgreSQL Support", "enabled");
  1116. #if HAVE_PG_CONFIG_H
  1117. php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
  1118. php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR);
  1119. #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
  1120. php_info_print_table_row(2, "Multibyte character support", "enabled");
  1121. #else
  1122. php_info_print_table_row(2, "Multibyte character support", "disabled");
  1123. #endif
  1124. #if defined(USE_SSL) || defined(USE_OPENSSL)
  1125. php_info_print_table_row(2, "SSL support", "enabled");
  1126. #else
  1127. php_info_print_table_row(2, "SSL support", "disabled");
  1128. #endif
  1129. #endif /* HAVE_PG_CONFIG_H */
  1130. snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_persistent));
  1131. php_info_print_table_row(2, "Active Persistent Links", buf);
  1132. snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_links));
  1133. php_info_print_table_row(2, "Active Links", buf);
  1134. php_info_print_table_end();
  1135. DISPLAY_INI_ENTRIES();
  1136. }
  1137. /* }}} */
  1138. /* {{{ php_pgsql_do_connect
  1139. */
  1140. static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
  1141. {
  1142. char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
  1143. PGconn *pgsql;
  1144. smart_str str = {0};
  1145. zval *args;
  1146. uint32_t i;
  1147. int connect_type = 0;
  1148. PGresult *pg_result;
  1149. args = (zval *)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
  1150. if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
  1151. || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
  1152. efree(args);
  1153. WRONG_PARAM_COUNT;
  1154. }
  1155. smart_str_appends(&str, "pgsql");
  1156. for (i = 0; i < ZEND_NUM_ARGS(); i++) {
  1157. /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
  1158. * can re-use this connection. Bug #39979
  1159. */
  1160. if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE(args[i]) == IS_LONG) {
  1161. if (Z_LVAL(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
  1162. continue;
  1163. } else if (Z_LVAL(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
  1164. smart_str_append_long(&str, Z_LVAL(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
  1165. }
  1166. }
  1167. ZVAL_STR(&args[i], zval_get_string(&args[i]));
  1168. smart_str_appendc(&str, '_');
  1169. smart_str_appendl(&str, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
  1170. }
  1171. /* Exception thrown during a string conversion. */
  1172. if (EG(exception)) {
  1173. goto cleanup;
  1174. }
  1175. smart_str_0(&str);
  1176. if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
  1177. connstring = Z_STRVAL(args[0]);
  1178. } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
  1179. connstring = Z_STRVAL(args[0]);
  1180. connect_type = (int)zval_get_long(&args[1]);
  1181. } else {
  1182. host = Z_STRVAL(args[0]);
  1183. port = Z_STRVAL(args[1]);
  1184. dbname = Z_STRVAL(args[ZEND_NUM_ARGS()-1]);
  1185. switch (ZEND_NUM_ARGS()) {
  1186. case 5:
  1187. tty = Z_STRVAL(args[3]);
  1188. /* fall through */
  1189. case 4:
  1190. options = Z_STRVAL(args[2]);
  1191. break;
  1192. }
  1193. }
  1194. if (persistent && PGG(allow_persistent)) {
  1195. zend_resource *le;
  1196. /* try to find if we already have this link in our persistent list */
  1197. if ((le = zend_hash_find_ptr(&EG(persistent_list), str.s)) == NULL) { /* we don't */
  1198. if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
  1199. php_error_docref(NULL, E_WARNING,
  1200. "Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
  1201. goto err;
  1202. }
  1203. if (PGG(max_persistent) != -1 && PGG(num_persistent) >= PGG(max_persistent)) {
  1204. php_error_docref(NULL, E_WARNING,
  1205. "Cannot create new link. Too many open persistent links (" ZEND_LONG_FMT ")", PGG(num_persistent));
  1206. goto err;
  1207. }
  1208. /* create the link */
  1209. if (connstring) {
  1210. pgsql = PQconnectdb(connstring);
  1211. } else {
  1212. pgsql = PQsetdb(host, port, options, tty, dbname);
  1213. }
  1214. if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) {
  1215. PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
  1216. if (pgsql) {
  1217. PQfinish(pgsql);
  1218. }
  1219. goto err;
  1220. }
  1221. /* hash it up */
  1222. if (zend_register_persistent_resource(ZSTR_VAL(str.s), ZSTR_LEN(str.s), pgsql, le_plink) == NULL) {
  1223. goto err;
  1224. }
  1225. PGG(num_links)++;
  1226. PGG(num_persistent)++;
  1227. } else { /* we do */
  1228. if (le->type != le_plink) {
  1229. goto err;
  1230. }
  1231. /* ensure that the link did not die */
  1232. if (PGG(auto_reset_persistent) & 1) {
  1233. /* need to send & get something from backend to
  1234. make sure we catch CONNECTION_BAD every time */
  1235. PGresult *pg_result;
  1236. pg_result = PQexec(le->ptr, "select 1");
  1237. PQclear(pg_result);
  1238. }
  1239. if (PQstatus(le->ptr) == CONNECTION_BAD) { /* the link died */
  1240. if (le->ptr == NULL) {
  1241. if (connstring) {
  1242. le->ptr = PQconnectdb(connstring);
  1243. } else {
  1244. le->ptr = PQsetdb(host,port,options,tty,dbname);
  1245. }
  1246. }
  1247. else {
  1248. PQreset(le->ptr);
  1249. }
  1250. if (le->ptr == NULL || PQstatus(le->ptr) == CONNECTION_BAD) {
  1251. php_error_docref(NULL, E_WARNING,"PostgreSQL link lost, unable to reconnect");
  1252. zend_hash_del(&EG(persistent_list), str.s);
  1253. goto err;
  1254. }
  1255. }
  1256. pgsql = (PGconn *) le->ptr;
  1257. #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
  1258. if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
  1259. #else
  1260. if (atof(PG_VERSION) >= 7.2) {
  1261. #endif
  1262. pg_result = PQexec(pgsql, "RESET ALL;");
  1263. PQclear(pg_result);
  1264. }
  1265. }
  1266. RETVAL_RES(zend_register_resource(pgsql, le_plink));
  1267. } else { /* Non persistent connection */
  1268. zend_resource *index_ptr, new_index_ptr;
  1269. /* first we check the hash for the hashed_details key. if it exists,
  1270. * it should point us to the right offset where the actual pgsql link sits.
  1271. * if it doesn't, open a new pgsql link, add it to the resource list,
  1272. * and add a pointer to it with hashed_details as the key.
  1273. */
  1274. if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
  1275. && (index_ptr = zend_hash_find_ptr(&EG(regular_list), str.s)) != NULL) {
  1276. zend_resource *link;
  1277. if (index_ptr->type != le_index_ptr) {
  1278. goto err;
  1279. }
  1280. link = (zend_resource *)index_ptr->ptr;
  1281. ZEND_ASSERT(link->ptr && (link->type == le_link || link->type == le_plink));
  1282. php_pgsql_set_default_link(link);
  1283. GC_ADDREF(link);
  1284. RETVAL_RES(link);
  1285. goto cleanup;
  1286. }
  1287. if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
  1288. php_error_docref(NULL, E_WARNING, "Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
  1289. goto err;
  1290. }
  1291. /* Non-blocking connect */
  1292. if (connect_type & PGSQL_CONNECT_ASYNC) {
  1293. if (connstring) {
  1294. pgsql = PQconnectStart(connstring);
  1295. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  1296. PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
  1297. if (pgsql) {
  1298. PQfinish(pgsql);
  1299. }
  1300. goto err;
  1301. }
  1302. } else {
  1303. php_error_docref(NULL, E_WARNING, "Connection string required for async connections");
  1304. goto err;
  1305. }
  1306. } else {
  1307. if (connstring) {
  1308. pgsql = PQconnectdb(connstring);
  1309. } else {
  1310. pgsql = PQsetdb(host,port,options,tty,dbname);
  1311. }
  1312. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  1313. PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
  1314. if (pgsql) {
  1315. PQfinish(pgsql);
  1316. }
  1317. goto err;
  1318. }
  1319. }
  1320. /* add it to the list */
  1321. RETVAL_RES(zend_register_resource(pgsql, le_link));
  1322. /* add it to the hash */
  1323. new_index_ptr.ptr = (void *) Z_RES_P(return_value);
  1324. new_index_ptr.type = le_index_ptr;
  1325. zend_hash_update_mem(&EG(regular_list), str.s, (void *) &new_index_ptr, sizeof(zend_resource));
  1326. /* Keep track of link => hash mapping, so we can remove the hash entry from regular_list
  1327. * when the connection is closed. This uses the address of the connection rather than the
  1328. * zend_resource, because the resource destructor is passed a stack copy of the resource
  1329. * structure. */
  1330. {
  1331. zval tmp;
  1332. ZVAL_STR_COPY(&tmp, str.s);
  1333. zend_hash_index_update(&PGG(hashes), (uintptr_t) pgsql, &tmp);
  1334. }
  1335. PGG(num_links)++;
  1336. }
  1337. /* set notice processor */
  1338. if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
  1339. PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)(zend_uintptr_t)Z_RES_HANDLE_P(return_value));
  1340. }
  1341. php_pgsql_set_default_link(Z_RES_P(return_value));
  1342. cleanup:
  1343. for (i = 0; i < ZEND_NUM_ARGS(); i++) {
  1344. zval_ptr_dtor(&args[i]);
  1345. }
  1346. efree(args);
  1347. smart_str_free(&str);
  1348. return;
  1349. err:
  1350. for (i = 0; i < ZEND_NUM_ARGS(); i++) {
  1351. zval_ptr_dtor(&args[i]);
  1352. }
  1353. efree(args);
  1354. smart_str_free(&str);
  1355. RETURN_FALSE;
  1356. }
  1357. /* }}} */
  1358. /* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database)
  1359. Open a PostgreSQL connection */
  1360. PHP_FUNCTION(pg_connect)
  1361. {
  1362. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
  1363. }
  1364. /* }}} */
  1365. /* {{{ proto resource pg_connect_poll(resource connection)
  1366. Poll the status of an in-progress async PostgreSQL connection attempt*/
  1367. PHP_FUNCTION(pg_connect_poll)
  1368. {
  1369. zval *pgsql_link;
  1370. PGconn *pgsql;
  1371. int ret;
  1372. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
  1373. RETURN_THROWS();
  1374. }
  1375. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  1376. RETURN_THROWS();
  1377. }
  1378. ret = PQconnectPoll(pgsql);
  1379. RETURN_LONG(ret);
  1380. }
  1381. /* }}} */
  1382. /* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database)
  1383. Open a persistent PostgreSQL connection */
  1384. PHP_FUNCTION(pg_pconnect)
  1385. {
  1386. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
  1387. }
  1388. /* }}} */
  1389. /* {{{ proto bool pg_close([resource connection])
  1390. Close a PostgreSQL connection */
  1391. PHP_FUNCTION(pg_close)
  1392. {
  1393. zval *pgsql_link = NULL;
  1394. zend_resource *link;
  1395. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &pgsql_link) == FAILURE) {
  1396. RETURN_THROWS();
  1397. }
  1398. if (!pgsql_link) {
  1399. link = PGG(default_link);
  1400. CHECK_DEFAULT_LINK(link);
  1401. zend_list_delete(link);
  1402. PGG(default_link) = NULL;
  1403. RETURN_TRUE;
  1404. }
  1405. link = Z_RES_P(pgsql_link);
  1406. if (zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink) == NULL) {
  1407. RETURN_THROWS();
  1408. }
  1409. if (link == PGG(default_link)) {
  1410. zend_list_delete(link);
  1411. PGG(default_link) = NULL;
  1412. }
  1413. zend_list_close(link);
  1414. RETURN_TRUE;
  1415. }
  1416. /* }}} */
  1417. #define PHP_PG_DBNAME 1
  1418. #define PHP_PG_ERROR_MESSAGE 2
  1419. #define PHP_PG_OPTIONS 3
  1420. #define PHP_PG_PORT 4
  1421. #define PHP_PG_TTY 5
  1422. #define PHP_PG_HOST 6
  1423. #define PHP_PG_VERSION 7
  1424. /* {{{ php_pgsql_get_link_info
  1425. */
  1426. static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  1427. {
  1428. zend_resource *link;
  1429. zval *pgsql_link = NULL;
  1430. int argc = ZEND_NUM_ARGS();
  1431. PGconn *pgsql;
  1432. char *msgbuf;
  1433. char *result;
  1434. if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
  1435. RETURN_THROWS();
  1436. }
  1437. if (argc == 0) {
  1438. link = FETCH_DEFAULT_LINK();
  1439. CHECK_DEFAULT_LINK(link);
  1440. } else {
  1441. link = Z_RES_P(pgsql_link);
  1442. }
  1443. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1444. RETURN_THROWS();
  1445. }
  1446. switch(entry_type) {
  1447. case PHP_PG_DBNAME:
  1448. result = PQdb(pgsql);
  1449. break;
  1450. case PHP_PG_ERROR_MESSAGE:
  1451. result = PQErrorMessageTrim(pgsql, &msgbuf);
  1452. RETVAL_STRING(result);
  1453. efree(result);
  1454. return;
  1455. case PHP_PG_OPTIONS:
  1456. result = PQoptions(pgsql);
  1457. break;
  1458. case PHP_PG_PORT:
  1459. result = PQport(pgsql);
  1460. break;
  1461. case PHP_PG_TTY:
  1462. result = PQtty(pgsql);
  1463. break;
  1464. case PHP_PG_HOST:
  1465. result = PQhost(pgsql);
  1466. break;
  1467. case PHP_PG_VERSION:
  1468. array_init(return_value);
  1469. add_assoc_string(return_value, "client", PG_VERSION);
  1470. #if HAVE_PQPROTOCOLVERSION
  1471. add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
  1472. #if HAVE_PQPARAMETERSTATUS
  1473. if (PQprotocolVersion(pgsql) >= 3) {
  1474. /* 8.0 or grater supports protorol version 3 */
  1475. char *tmp;
  1476. add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"));
  1477. #define PHP_PQ_COPY_PARAM(_x) tmp = (char*)PQparameterStatus(pgsql, _x); \
  1478. if(tmp) add_assoc_string(return_value, _x, tmp); \
  1479. else add_assoc_null(return_value, _x);
  1480. PHP_PQ_COPY_PARAM("server_encoding");
  1481. PHP_PQ_COPY_PARAM("client_encoding");
  1482. PHP_PQ_COPY_PARAM("is_superuser");
  1483. PHP_PQ_COPY_PARAM("session_authorization");
  1484. PHP_PQ_COPY_PARAM("DateStyle");
  1485. PHP_PQ_COPY_PARAM("IntervalStyle");
  1486. PHP_PQ_COPY_PARAM("TimeZone");
  1487. PHP_PQ_COPY_PARAM("integer_datetimes");
  1488. PHP_PQ_COPY_PARAM("standard_conforming_strings");
  1489. PHP_PQ_COPY_PARAM("application_name");
  1490. }
  1491. #endif
  1492. #endif
  1493. return;
  1494. default:
  1495. RETURN_FALSE;
  1496. }
  1497. if (result) {
  1498. RETURN_STRING(result);
  1499. } else {
  1500. RETURN_EMPTY_STRING();
  1501. }
  1502. }
  1503. /* }}} */
  1504. /* {{{ proto string pg_dbname([resource connection])
  1505. Get the database name */
  1506. PHP_FUNCTION(pg_dbname)
  1507. {
  1508. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
  1509. }
  1510. /* }}} */
  1511. /* {{{ proto string pg_last_error([resource connection])
  1512. Get the error message string */
  1513. PHP_FUNCTION(pg_last_error)
  1514. {
  1515. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
  1516. }
  1517. /* }}} */
  1518. /* {{{ proto string pg_options([resource connection])
  1519. Get the options associated with the connection */
  1520. PHP_FUNCTION(pg_options)
  1521. {
  1522. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
  1523. }
  1524. /* }}} */
  1525. /* {{{ proto int pg_port([resource connection])
  1526. Return the port number associated with the connection */
  1527. PHP_FUNCTION(pg_port)
  1528. {
  1529. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
  1530. }
  1531. /* }}} */
  1532. /* {{{ proto string pg_tty([resource connection])
  1533. Return the tty name associated with the connection */
  1534. PHP_FUNCTION(pg_tty)
  1535. {
  1536. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
  1537. }
  1538. /* }}} */
  1539. /* {{{ proto string pg_host([resource connection])
  1540. Returns the host name associated with the connection */
  1541. PHP_FUNCTION(pg_host)
  1542. {
  1543. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
  1544. }
  1545. /* }}} */
  1546. /* {{{ proto array pg_version([resource connection])
  1547. Returns an array with client, protocol and server version (when available) */
  1548. PHP_FUNCTION(pg_version)
  1549. {
  1550. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
  1551. }
  1552. /* }}} */
  1553. #if HAVE_PQPARAMETERSTATUS
  1554. /* {{{ proto string|false pg_parameter_status([resource connection,] string param_name)
  1555. Returns the value of a server parameter */
  1556. PHP_FUNCTION(pg_parameter_status)
  1557. {
  1558. zval *pgsql_link = NULL;
  1559. zend_resource *link;
  1560. PGconn *pgsql;
  1561. char *param;
  1562. size_t len;
  1563. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "rs", &pgsql_link, &param, &len) == FAILURE) {
  1564. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &param, &len) == SUCCESS) {
  1565. link = FETCH_DEFAULT_LINK();
  1566. CHECK_DEFAULT_LINK(link);
  1567. } else {
  1568. RETURN_FALSE;
  1569. }
  1570. } else {
  1571. link = Z_RES_P(pgsql_link);
  1572. }
  1573. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1574. RETURN_THROWS();
  1575. }
  1576. param = (char*)PQparameterStatus(pgsql, param);
  1577. if (param) {
  1578. RETURN_STRING(param);
  1579. } else {
  1580. RETURN_FALSE;
  1581. }
  1582. }
  1583. /* }}} */
  1584. #endif
  1585. /* {{{ proto bool pg_ping([resource connection])
  1586. Ping database. If connection is bad, try to reconnect. */
  1587. PHP_FUNCTION(pg_ping)
  1588. {
  1589. zval *pgsql_link;
  1590. PGconn *pgsql;
  1591. PGresult *res;
  1592. zend_resource *link;
  1593. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r", &pgsql_link) == SUCCESS) {
  1594. link = Z_RES_P(pgsql_link);
  1595. } else {
  1596. link = FETCH_DEFAULT_LINK();
  1597. CHECK_DEFAULT_LINK(link);
  1598. }
  1599. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1600. RETURN_THROWS();
  1601. }
  1602. /* ping connection */
  1603. res = PQexec(pgsql, "SELECT 1;");
  1604. PQclear(res);
  1605. /* check status. */
  1606. if (PQstatus(pgsql) == CONNECTION_OK)
  1607. RETURN_TRUE;
  1608. /* reset connection if it's broken */
  1609. PQreset(pgsql);
  1610. if (PQstatus(pgsql) == CONNECTION_OK) {
  1611. RETURN_TRUE;
  1612. }
  1613. RETURN_FALSE;
  1614. }
  1615. /* }}} */
  1616. /* {{{ proto resource pg_query([resource connection,] string query)
  1617. Execute a query */
  1618. PHP_FUNCTION(pg_query)
  1619. {
  1620. zval *pgsql_link = NULL;
  1621. char *query;
  1622. int argc = ZEND_NUM_ARGS();
  1623. size_t query_len;
  1624. int leftover = 0;
  1625. zend_resource *link;
  1626. PGconn *pgsql;
  1627. PGresult *pgsql_result;
  1628. ExecStatusType status;
  1629. if (argc == 1) {
  1630. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query, &query_len) == FAILURE) {
  1631. RETURN_THROWS();
  1632. }
  1633. link = FETCH_DEFAULT_LINK();
  1634. CHECK_DEFAULT_LINK(link);
  1635. } else {
  1636. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &query, &query_len) == FAILURE) {
  1637. RETURN_THROWS();
  1638. }
  1639. link = Z_RES_P(pgsql_link);
  1640. }
  1641. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1642. RETURN_THROWS();
  1643. }
  1644. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1645. php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
  1646. RETURN_FALSE;
  1647. }
  1648. while ((pgsql_result = PQgetResult(pgsql))) {
  1649. PQclear(pgsql_result);
  1650. leftover = 1;
  1651. }
  1652. if (leftover) {
  1653. php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1654. }
  1655. pgsql_result = PQexec(pgsql, query);
  1656. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1657. PQclear(pgsql_result);
  1658. PQreset(pgsql);
  1659. pgsql_result = PQexec(pgsql, query);
  1660. }
  1661. if (pgsql_result) {
  1662. status = PQresultStatus(pgsql_result);
  1663. } else {
  1664. status = (ExecStatusType) PQstatus(pgsql);
  1665. }
  1666. switch (status) {
  1667. case PGRES_EMPTY_QUERY:
  1668. case PGRES_BAD_RESPONSE:
  1669. case PGRES_NONFATAL_ERROR:
  1670. case PGRES_FATAL_ERROR:
  1671. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1672. PQclear(pgsql_result);
  1673. RETURN_FALSE;
  1674. break;
  1675. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1676. default:
  1677. if (pgsql_result) {
  1678. pgsql_result_handle *pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1679. pg_result->conn = pgsql;
  1680. pg_result->result = pgsql_result;
  1681. pg_result->row = 0;
  1682. RETURN_RES(zend_register_resource(pg_result, le_result));
  1683. } else {
  1684. PQclear(pgsql_result);
  1685. RETURN_FALSE;
  1686. }
  1687. break;
  1688. }
  1689. }
  1690. /* }}} */
  1691. #if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED
  1692. /* {{{ _php_pgsql_free_params */
  1693. static void _php_pgsql_free_params(char **params, int num_params)
  1694. {
  1695. if (num_params > 0) {
  1696. int i;
  1697. for (i = 0; i < num_params; i++) {
  1698. if (params[i]) {
  1699. efree(params[i]);
  1700. }
  1701. }
  1702. efree(params);
  1703. }
  1704. }
  1705. /* }}} */
  1706. #endif
  1707. #if HAVE_PQEXECPARAMS
  1708. /* {{{ proto resource pg_query_params([resource connection,] string query, array params)
  1709. Execute a query */
  1710. PHP_FUNCTION(pg_query_params)
  1711. {
  1712. zval *pgsql_link = NULL;
  1713. zval *pv_param_arr, *tmp;
  1714. char *query;
  1715. size_t query_len;
  1716. int argc = ZEND_NUM_ARGS();
  1717. int leftover = 0;
  1718. int num_params = 0;
  1719. char **params = NULL;
  1720. zend_resource *link;
  1721. PGconn *pgsql;
  1722. PGresult *pgsql_result;
  1723. ExecStatusType status;
  1724. pgsql_result_handle *pg_result;
  1725. if (argc == 2) {
  1726. if (zend_parse_parameters(argc, "sa", &query, &query_len, &pv_param_arr) == FAILURE) {
  1727. RETURN_THROWS();
  1728. }
  1729. link = FETCH_DEFAULT_LINK();
  1730. CHECK_DEFAULT_LINK(link);
  1731. } else {
  1732. if (zend_parse_parameters(argc, "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
  1733. RETURN_THROWS();
  1734. }
  1735. link = Z_RES_P(pgsql_link);
  1736. }
  1737. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1738. RETURN_THROWS();
  1739. }
  1740. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1741. php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
  1742. RETURN_FALSE;
  1743. }
  1744. while ((pgsql_result = PQgetResult(pgsql))) {
  1745. PQclear(pgsql_result);
  1746. leftover = 1;
  1747. }
  1748. if (leftover) {
  1749. php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1750. }
  1751. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  1752. if (num_params > 0) {
  1753. int i = 0;
  1754. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  1755. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
  1756. ZVAL_DEREF(tmp);
  1757. if (Z_TYPE_P(tmp) == IS_NULL) {
  1758. params[i] = NULL;
  1759. } else {
  1760. zval tmp_val;
  1761. ZVAL_COPY(&tmp_val, tmp);
  1762. convert_to_string(&tmp_val);
  1763. if (Z_TYPE(tmp_val) != IS_STRING) {
  1764. php_error_docref(NULL, E_WARNING,"Error converting parameter");
  1765. zval_ptr_dtor(&tmp_val);
  1766. _php_pgsql_free_params(params, num_params);
  1767. RETURN_FALSE;
  1768. }
  1769. params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
  1770. zval_ptr_dtor(&tmp_val);
  1771. }
  1772. i++;
  1773. } ZEND_HASH_FOREACH_END();
  1774. }
  1775. pgsql_result = PQexecParams(pgsql, query, num_params,
  1776. NULL, (const char * const *)params, NULL, NULL, 0);
  1777. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1778. PQclear(pgsql_result);
  1779. PQreset(pgsql);
  1780. pgsql_result = PQexecParams(pgsql, query, num_params,
  1781. NULL, (const char * const *)params, NULL, NULL, 0);
  1782. }
  1783. if (pgsql_result) {
  1784. status = PQresultStatus(pgsql_result);
  1785. } else {
  1786. status = (ExecStatusType) PQstatus(pgsql);
  1787. }
  1788. _php_pgsql_free_params(params, num_params);
  1789. switch (status) {
  1790. case PGRES_EMPTY_QUERY:
  1791. case PGRES_BAD_RESPONSE:
  1792. case PGRES_NONFATAL_ERROR:
  1793. case PGRES_FATAL_ERROR:
  1794. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1795. PQclear(pgsql_result);
  1796. RETURN_FALSE;
  1797. break;
  1798. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1799. default:
  1800. if (pgsql_result) {
  1801. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1802. pg_result->conn = pgsql;
  1803. pg_result->result = pgsql_result;
  1804. pg_result->row = 0;
  1805. RETURN_RES(zend_register_resource(pg_result, le_result));
  1806. } else {
  1807. PQclear(pgsql_result);
  1808. RETURN_FALSE;
  1809. }
  1810. break;
  1811. }
  1812. }
  1813. /* }}} */
  1814. #endif
  1815. #if HAVE_PQPREPARE
  1816. /* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query)
  1817. Prepare a query for future execution */
  1818. PHP_FUNCTION(pg_prepare)
  1819. {
  1820. zval *pgsql_link = NULL;
  1821. char *query, *stmtname;
  1822. size_t query_len, stmtname_len;
  1823. int argc = ZEND_NUM_ARGS();
  1824. int leftover = 0;
  1825. PGconn *pgsql;
  1826. zend_resource *link;
  1827. PGresult *pgsql_result;
  1828. ExecStatusType status;
  1829. pgsql_result_handle *pg_result;
  1830. if (argc == 2) {
  1831. if (zend_parse_parameters(argc, "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
  1832. RETURN_THROWS();
  1833. }
  1834. link = FETCH_DEFAULT_LINK();
  1835. CHECK_DEFAULT_LINK(link);
  1836. } else {
  1837. if (zend_parse_parameters(argc, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
  1838. RETURN_THROWS();
  1839. }
  1840. link = Z_RES_P(pgsql_link);
  1841. }
  1842. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1843. RETURN_THROWS();
  1844. }
  1845. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1846. php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
  1847. RETURN_FALSE;
  1848. }
  1849. while ((pgsql_result = PQgetResult(pgsql))) {
  1850. PQclear(pgsql_result);
  1851. leftover = 1;
  1852. }
  1853. if (leftover) {
  1854. php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1855. }
  1856. pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
  1857. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1858. PQclear(pgsql_result);
  1859. PQreset(pgsql);
  1860. pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
  1861. }
  1862. if (pgsql_result) {
  1863. status = PQresultStatus(pgsql_result);
  1864. } else {
  1865. status = (ExecStatusType) PQstatus(pgsql);
  1866. }
  1867. switch (status) {
  1868. case PGRES_EMPTY_QUERY:
  1869. case PGRES_BAD_RESPONSE:
  1870. case PGRES_NONFATAL_ERROR:
  1871. case PGRES_FATAL_ERROR:
  1872. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1873. PQclear(pgsql_result);
  1874. RETURN_FALSE;
  1875. break;
  1876. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1877. default:
  1878. if (pgsql_result) {
  1879. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1880. pg_result->conn = pgsql;
  1881. pg_result->result = pgsql_result;
  1882. pg_result->row = 0;
  1883. RETURN_RES(zend_register_resource(pg_result, le_result));
  1884. } else {
  1885. PQclear(pgsql_result);
  1886. RETURN_FALSE;
  1887. }
  1888. break;
  1889. }
  1890. }
  1891. /* }}} */
  1892. #endif
  1893. #if HAVE_PQEXECPREPARED
  1894. /* {{{ proto resource pg_execute([resource connection,] string stmtname, array params)
  1895. Execute a prepared query */
  1896. PHP_FUNCTION(pg_execute)
  1897. {
  1898. zval *pgsql_link = NULL;
  1899. zval *pv_param_arr, *tmp;
  1900. char *stmtname;
  1901. size_t stmtname_len;
  1902. int argc = ZEND_NUM_ARGS();
  1903. int leftover = 0;
  1904. int num_params = 0;
  1905. char **params = NULL;
  1906. PGconn *pgsql;
  1907. zend_resource *link;
  1908. PGresult *pgsql_result;
  1909. ExecStatusType status;
  1910. pgsql_result_handle *pg_result;
  1911. if (argc == 2) {
  1912. if (zend_parse_parameters(argc, "sa", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) {
  1913. RETURN_THROWS();
  1914. }
  1915. link = FETCH_DEFAULT_LINK();
  1916. CHECK_DEFAULT_LINK(link);
  1917. } else {
  1918. if (zend_parse_parameters(argc, "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
  1919. RETURN_THROWS();
  1920. }
  1921. link = Z_RES_P(pgsql_link);
  1922. }
  1923. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  1924. RETURN_THROWS();
  1925. }
  1926. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1927. php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
  1928. RETURN_FALSE;
  1929. }
  1930. while ((pgsql_result = PQgetResult(pgsql))) {
  1931. PQclear(pgsql_result);
  1932. leftover = 1;
  1933. }
  1934. if (leftover) {
  1935. php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1936. }
  1937. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  1938. if (num_params > 0) {
  1939. int i = 0;
  1940. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  1941. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
  1942. if (Z_TYPE_P(tmp) == IS_NULL) {
  1943. params[i] = NULL;
  1944. } else {
  1945. zend_string *tmp_str;
  1946. zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
  1947. params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
  1948. zend_tmp_string_release(tmp_str);
  1949. }
  1950. i++;
  1951. } ZEND_HASH_FOREACH_END();
  1952. }
  1953. pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
  1954. (const char * const *)params, NULL, NULL, 0);
  1955. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1956. PQclear(pgsql_result);
  1957. PQreset(pgsql);
  1958. pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
  1959. (const char * const *)params, NULL, NULL, 0);
  1960. }
  1961. if (pgsql_result) {
  1962. status = PQresultStatus(pgsql_result);
  1963. } else {
  1964. status = (ExecStatusType) PQstatus(pgsql);
  1965. }
  1966. _php_pgsql_free_params(params, num_params);
  1967. switch (status) {
  1968. case PGRES_EMPTY_QUERY:
  1969. case PGRES_BAD_RESPONSE:
  1970. case PGRES_NONFATAL_ERROR:
  1971. case PGRES_FATAL_ERROR:
  1972. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1973. PQclear(pgsql_result);
  1974. RETURN_FALSE;
  1975. break;
  1976. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1977. default:
  1978. if (pgsql_result) {
  1979. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1980. pg_result->conn = pgsql;
  1981. pg_result->result = pgsql_result;
  1982. pg_result->row = 0;
  1983. RETURN_RES(zend_register_resource(pg_result, le_result));
  1984. } else {
  1985. PQclear(pgsql_result);
  1986. RETURN_FALSE;
  1987. }
  1988. break;
  1989. }
  1990. }
  1991. /* }}} */
  1992. #endif
  1993. #define PHP_PG_NUM_ROWS 1
  1994. #define PHP_PG_NUM_FIELDS 2
  1995. #define PHP_PG_CMD_TUPLES 3
  1996. /* {{{ php_pgsql_get_result_info
  1997. */
  1998. static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  1999. {
  2000. zval *result;
  2001. PGresult *pgsql_result;
  2002. pgsql_result_handle *pg_result;
  2003. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
  2004. RETURN_THROWS();
  2005. }
  2006. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2007. RETURN_THROWS();
  2008. }
  2009. pgsql_result = pg_result->result;
  2010. switch (entry_type) {
  2011. case PHP_PG_NUM_ROWS:
  2012. RETVAL_LONG(PQntuples(pgsql_result));
  2013. break;
  2014. case PHP_PG_NUM_FIELDS:
  2015. RETVAL_LONG(PQnfields(pgsql_result));
  2016. break;
  2017. case PHP_PG_CMD_TUPLES:
  2018. #if HAVE_PQCMDTUPLES
  2019. RETVAL_LONG(atoi(PQcmdTuples(pgsql_result)));
  2020. #else
  2021. php_error_docref(NULL, E_WARNING, "Not supported under this build");
  2022. RETVAL_LONG(0);
  2023. #endif
  2024. break;
  2025. default:
  2026. RETURN_FALSE;
  2027. }
  2028. }
  2029. /* }}} */
  2030. /* {{{ proto int pg_num_rows(resource result)
  2031. Return the number of rows in the result */
  2032. PHP_FUNCTION(pg_num_rows)
  2033. {
  2034. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
  2035. }
  2036. /* }}} */
  2037. /* {{{ proto int pg_num_fields(resource result)
  2038. Return the number of fields in the result */
  2039. PHP_FUNCTION(pg_num_fields)
  2040. {
  2041. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
  2042. }
  2043. /* }}} */
  2044. #if HAVE_PQCMDTUPLES
  2045. /* {{{ proto int pg_affected_rows(resource result)
  2046. Returns the number of affected tuples */
  2047. PHP_FUNCTION(pg_affected_rows)
  2048. {
  2049. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
  2050. }
  2051. /* }}} */
  2052. #endif
  2053. /* {{{ proto mixed pg_last_notice(resource connection [, int option])
  2054. Returns the last notice set by the backend */
  2055. PHP_FUNCTION(pg_last_notice)
  2056. {
  2057. zval *pgsql_link = NULL;
  2058. zval *notice, *notices;
  2059. PGconn *pg_link;
  2060. zend_long option = PGSQL_NOTICE_LAST;
  2061. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &pgsql_link, &option) == FAILURE) {
  2062. RETURN_THROWS();
  2063. }
  2064. /* Just to check if user passed valid resoruce */
  2065. if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  2066. RETURN_THROWS();
  2067. }
  2068. notices = zend_hash_index_find(&PGG(notices), (zend_ulong)Z_RES_HANDLE_P(pgsql_link));
  2069. switch (option) {
  2070. case PGSQL_NOTICE_LAST:
  2071. if (notices) {
  2072. zend_hash_internal_pointer_end(Z_ARRVAL_P(notices));
  2073. if ((notice = zend_hash_get_current_data(Z_ARRVAL_P(notices))) == NULL) {
  2074. RETURN_EMPTY_STRING();
  2075. }
  2076. RETURN_COPY(notice);
  2077. } else {
  2078. RETURN_EMPTY_STRING();
  2079. }
  2080. break;
  2081. case PGSQL_NOTICE_ALL:
  2082. if (notices) {
  2083. RETURN_COPY(notices);
  2084. } else {
  2085. array_init(return_value);
  2086. return;
  2087. }
  2088. break;
  2089. case PGSQL_NOTICE_CLEAR:
  2090. if (notices) {
  2091. zend_hash_clean(&PGG(notices));
  2092. }
  2093. RETURN_TRUE;
  2094. break;
  2095. default:
  2096. php_error_docref(NULL, E_WARNING,
  2097. "Invalid option specified (" ZEND_LONG_FMT ")", option);
  2098. }
  2099. RETURN_FALSE;
  2100. }
  2101. /* }}} */
  2102. /* {{{ get_field_name
  2103. */
  2104. static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list)
  2105. {
  2106. smart_str str = {0};
  2107. zend_resource *field_type;
  2108. char *ret=NULL;
  2109. /* try to lookup the type in the resource list */
  2110. smart_str_appends(&str, "pgsql_oid_");
  2111. smart_str_append_unsigned(&str, oid);
  2112. smart_str_0(&str);
  2113. if ((field_type = zend_hash_find_ptr(list, str.s)) != NULL) {
  2114. ret = estrdup((char *)field_type->ptr);
  2115. } else { /* hash all oid's */
  2116. int i, num_rows;
  2117. int oid_offset,name_offset;
  2118. char *tmp_oid, *end_ptr, *tmp_name;
  2119. zend_resource new_oid_entry;
  2120. PGresult *result;
  2121. if ((result = PQexec(pgsql, "select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) {
  2122. if (result) {
  2123. PQclear(result);
  2124. }
  2125. smart_str_free(&str);
  2126. return estrndup("", sizeof("") - 1);
  2127. }
  2128. num_rows = PQntuples(result);
  2129. oid_offset = PQfnumber(result,"oid");
  2130. name_offset = PQfnumber(result,"typname");
  2131. for (i=0; i<num_rows; i++) {
  2132. if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
  2133. continue;
  2134. }
  2135. smart_str_free(&str);
  2136. smart_str_appends(&str, "pgsql_oid_");
  2137. smart_str_appends(&str, tmp_oid);
  2138. smart_str_0(&str);
  2139. if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
  2140. continue;
  2141. }
  2142. new_oid_entry.type = le_string;
  2143. new_oid_entry.ptr = estrdup(tmp_name);
  2144. zend_hash_update_mem(list, str.s, (void *) &new_oid_entry, sizeof(zend_resource));
  2145. if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) {
  2146. ret = estrdup(tmp_name);
  2147. }
  2148. }
  2149. PQclear(result);
  2150. }
  2151. smart_str_free(&str);
  2152. return ret;
  2153. }
  2154. /* }}} */
  2155. #ifdef HAVE_PQFTABLE
  2156. /* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only])
  2157. Returns the name of the table field belongs to, or table's oid if oid_only is true */
  2158. PHP_FUNCTION(pg_field_table)
  2159. {
  2160. zval *result;
  2161. pgsql_result_handle *pg_result;
  2162. zend_long fnum = -1;
  2163. zend_bool return_oid = 0;
  2164. Oid oid;
  2165. smart_str hash_key = {0};
  2166. char *table_name;
  2167. zend_resource *field_table;
  2168. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|b", &result, &fnum, &return_oid) == FAILURE) {
  2169. RETURN_THROWS();
  2170. }
  2171. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2172. RETURN_THROWS();
  2173. }
  2174. if (fnum < 0 || fnum >= PQnfields(pg_result->result)) {
  2175. php_error_docref(NULL, E_WARNING, "Bad field offset specified");
  2176. RETURN_FALSE;
  2177. }
  2178. oid = PQftable(pg_result->result, (int)fnum);
  2179. if (InvalidOid == oid) {
  2180. RETURN_FALSE;
  2181. }
  2182. if (return_oid) {
  2183. #if UINT_MAX > ZEND_LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */
  2184. if (oid > ZEND_LONG_MAX) {
  2185. smart_str oidstr = {0};
  2186. smart_str_append_unsigned(&oidstr, oid);
  2187. smart_str_0(&oidstr);
  2188. RETURN_NEW_STR(oidstr.s);
  2189. } else
  2190. #endif
  2191. RETURN_LONG((zend_long)oid);
  2192. }
  2193. /* try to lookup the table name in the resource list */
  2194. smart_str_appends(&hash_key, "pgsql_table_oid_");
  2195. smart_str_append_unsigned(&hash_key, oid);
  2196. smart_str_0(&hash_key);
  2197. if ((field_table = zend_hash_find_ptr(&EG(regular_list), hash_key.s)) != NULL) {
  2198. smart_str_free(&hash_key);
  2199. RETURN_STRING((char *)field_table->ptr);
  2200. } else { /* Not found, lookup by querying PostgreSQL system tables */
  2201. PGresult *tmp_res;
  2202. smart_str querystr = {0};
  2203. zend_resource new_field_table;
  2204. smart_str_appends(&querystr, "select relname from pg_class where oid=");
  2205. smart_str_append_unsigned(&querystr, oid);
  2206. smart_str_0(&querystr);
  2207. if ((tmp_res = PQexec(pg_result->conn, ZSTR_VAL(querystr.s))) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
  2208. if (tmp_res) {
  2209. PQclear(tmp_res);
  2210. }
  2211. smart_str_free(&querystr);
  2212. smart_str_free(&hash_key);
  2213. RETURN_FALSE;
  2214. }
  2215. smart_str_free(&querystr);
  2216. if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) {
  2217. PQclear(tmp_res);
  2218. smart_str_free(&hash_key);
  2219. RETURN_FALSE;
  2220. }
  2221. new_field_table.type = le_string;
  2222. new_field_table.ptr = estrdup(table_name);
  2223. zend_hash_update_mem(&EG(regular_list), hash_key.s, (void *)&new_field_table, sizeof(zend_resource));
  2224. smart_str_free(&hash_key);
  2225. PQclear(tmp_res);
  2226. RETURN_STRING(table_name);
  2227. }
  2228. }
  2229. /* }}} */
  2230. #endif
  2231. #define PHP_PG_FIELD_NAME 1
  2232. #define PHP_PG_FIELD_SIZE 2
  2233. #define PHP_PG_FIELD_TYPE 3
  2234. #define PHP_PG_FIELD_TYPE_OID 4
  2235. /* {{{ php_pgsql_get_field_info
  2236. */
  2237. static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  2238. {
  2239. zval *result;
  2240. zend_long field;
  2241. PGresult *pgsql_result;
  2242. pgsql_result_handle *pg_result;
  2243. Oid oid;
  2244. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &result, &field) == FAILURE) {
  2245. RETURN_THROWS();
  2246. }
  2247. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2248. RETURN_THROWS();
  2249. }
  2250. pgsql_result = pg_result->result;
  2251. if (field < 0 || field >= PQnfields(pgsql_result)) {
  2252. php_error_docref(NULL, E_WARNING, "Bad field offset specified");
  2253. RETURN_FALSE;
  2254. }
  2255. switch (entry_type) {
  2256. case PHP_PG_FIELD_NAME:
  2257. RETURN_STRING(PQfname(pgsql_result, (int)field));
  2258. break;
  2259. case PHP_PG_FIELD_SIZE:
  2260. RETURN_LONG(PQfsize(pgsql_result, (int)field));
  2261. break;
  2262. case PHP_PG_FIELD_TYPE: {
  2263. char *name = get_field_name(pg_result->conn, PQftype(pgsql_result, (int)field), &EG(regular_list));
  2264. RETVAL_STRING(name);
  2265. efree(name);
  2266. }
  2267. break;
  2268. case PHP_PG_FIELD_TYPE_OID:
  2269. oid = PQftype(pgsql_result, (int)field);
  2270. #if UINT_MAX > ZEND_LONG_MAX
  2271. if (oid > ZEND_LONG_MAX) {
  2272. smart_str s = {0};
  2273. smart_str_append_unsigned(&s, oid);
  2274. smart_str_0(&s);
  2275. RETURN_NEW_STR(s.s);
  2276. } else
  2277. #endif
  2278. {
  2279. RETURN_LONG((zend_long)oid);
  2280. }
  2281. break;
  2282. default:
  2283. RETURN_FALSE;
  2284. }
  2285. }
  2286. /* }}} */
  2287. /* {{{ proto string pg_field_name(resource result, int field_number)
  2288. Returns the name of the field */
  2289. PHP_FUNCTION(pg_field_name)
  2290. {
  2291. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
  2292. }
  2293. /* }}} */
  2294. /* {{{ proto int pg_field_size(resource result, int field_number)
  2295. Returns the internal size of the field */
  2296. PHP_FUNCTION(pg_field_size)
  2297. {
  2298. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
  2299. }
  2300. /* }}} */
  2301. /* {{{ proto string pg_field_type(resource result, int field_number)
  2302. Returns the type name for the given field */
  2303. PHP_FUNCTION(pg_field_type)
  2304. {
  2305. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
  2306. }
  2307. /* }}} */
  2308. /* {{{ proto string pg_field_type_oid(resource result, int field_number)
  2309. Returns the type oid for the given field */
  2310. PHP_FUNCTION(pg_field_type_oid)
  2311. {
  2312. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
  2313. }
  2314. /* }}} */
  2315. /* {{{ proto int pg_field_num(resource result, string field_name)
  2316. Returns the field number of the named field */
  2317. PHP_FUNCTION(pg_field_num)
  2318. {
  2319. zval *result;
  2320. char *field;
  2321. size_t field_len;
  2322. PGresult *pgsql_result;
  2323. pgsql_result_handle *pg_result;
  2324. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &result, &field, &field_len) == FAILURE) {
  2325. RETURN_THROWS();
  2326. }
  2327. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2328. RETURN_THROWS();
  2329. }
  2330. pgsql_result = pg_result->result;
  2331. RETURN_LONG(PQfnumber(pgsql_result, field));
  2332. }
  2333. /* }}} */
  2334. /* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
  2335. Returns values from a result identifier */
  2336. PHP_FUNCTION(pg_fetch_result)
  2337. {
  2338. zval *result, *field=NULL;
  2339. zend_long row;
  2340. PGresult *pgsql_result;
  2341. pgsql_result_handle *pg_result;
  2342. int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
  2343. if (argc == 2) {
  2344. if (zend_parse_parameters(argc, "rz", &result, &field) == FAILURE) {
  2345. RETURN_THROWS();
  2346. }
  2347. } else {
  2348. if (zend_parse_parameters(argc, "rlz", &result, &row, &field) == FAILURE) {
  2349. RETURN_THROWS();
  2350. }
  2351. }
  2352. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2353. RETURN_THROWS();
  2354. }
  2355. pgsql_result = pg_result->result;
  2356. if (argc == 2) {
  2357. if (pg_result->row < 0) {
  2358. pg_result->row = 0;
  2359. }
  2360. pgsql_row = pg_result->row;
  2361. if (pgsql_row >= PQntuples(pgsql_result)) {
  2362. RETURN_FALSE;
  2363. }
  2364. pg_result->row++;
  2365. } else {
  2366. if (row < 0 || row >= PQntuples(pgsql_result)) {
  2367. php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
  2368. row, Z_LVAL_P(result));
  2369. RETURN_FALSE;
  2370. }
  2371. pgsql_row = (int)row;
  2372. }
  2373. switch (Z_TYPE_P(field)) {
  2374. case IS_STRING:
  2375. field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
  2376. if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
  2377. php_error_docref(NULL, E_WARNING, "Bad column offset specified");
  2378. RETURN_FALSE;
  2379. }
  2380. break;
  2381. default:
  2382. convert_to_long_ex(field);
  2383. if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
  2384. php_error_docref(NULL, E_WARNING, "Bad column offset specified");
  2385. RETURN_FALSE;
  2386. }
  2387. field_offset = (int)Z_LVAL_P(field);
  2388. break;
  2389. }
  2390. if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
  2391. RETVAL_NULL();
  2392. } else {
  2393. RETVAL_STRINGL(PQgetvalue(pgsql_result, pgsql_row, field_offset),
  2394. PQgetlength(pgsql_result, pgsql_row, field_offset));
  2395. }
  2396. }
  2397. /* }}} */
  2398. /* {{{ void php_pgsql_fetch_hash */
  2399. static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_type, int into_object)
  2400. {
  2401. zval *result, *zrow = NULL;
  2402. PGresult *pgsql_result;
  2403. pgsql_result_handle *pg_result;
  2404. int i, num_fields, pgsql_row, use_row;
  2405. zend_long row = -1;
  2406. char *field_name;
  2407. zval *ctor_params = NULL;
  2408. zend_class_entry *ce = NULL;
  2409. if (into_object) {
  2410. zend_string *class_name = NULL;
  2411. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!Sz", &result, &zrow, &class_name, &ctor_params) == FAILURE) {
  2412. RETURN_THROWS();
  2413. }
  2414. if (!class_name) {
  2415. ce = zend_standard_class_def;
  2416. } else {
  2417. ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
  2418. }
  2419. if (!ce) {
  2420. php_error_docref(NULL, E_WARNING, "Could not find class '%s'", ZSTR_VAL(class_name));
  2421. return;
  2422. }
  2423. result_type = PGSQL_ASSOC;
  2424. } else {
  2425. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!l", &result, &zrow, &result_type) == FAILURE) {
  2426. RETURN_THROWS();
  2427. }
  2428. }
  2429. if (zrow == NULL) {
  2430. row = -1;
  2431. } else {
  2432. convert_to_long(zrow);
  2433. row = Z_LVAL_P(zrow);
  2434. if (row < 0) {
  2435. php_error_docref(NULL, E_WARNING, "The row parameter must be greater or equal to zero");
  2436. RETURN_FALSE;
  2437. }
  2438. }
  2439. use_row = ZEND_NUM_ARGS() > 1 && row != -1;
  2440. if (!(result_type & PGSQL_BOTH)) {
  2441. php_error_docref(NULL, E_WARNING, "Invalid result type");
  2442. RETURN_FALSE;
  2443. }
  2444. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2445. RETURN_THROWS();
  2446. }
  2447. pgsql_result = pg_result->result;
  2448. if (use_row) {
  2449. if (row < 0 || row >= PQntuples(pgsql_result)) {
  2450. php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
  2451. row, Z_LVAL_P(result));
  2452. RETURN_FALSE;
  2453. }
  2454. pgsql_row = (int)row;
  2455. pg_result->row = pgsql_row;
  2456. } else {
  2457. /* If 2nd param is NULL, use internal row counter to access next row */
  2458. pgsql_row = pg_result->row;
  2459. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2460. RETURN_FALSE;
  2461. }
  2462. pg_result->row++;
  2463. }
  2464. array_init(return_value);
  2465. for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
  2466. if (PQgetisnull(pgsql_result, pgsql_row, i)) {
  2467. if (result_type & PGSQL_NUM) {
  2468. add_index_null(return_value, i);
  2469. }
  2470. if (result_type & PGSQL_ASSOC) {
  2471. field_name = PQfname(pgsql_result, i);
  2472. add_assoc_null(return_value, field_name);
  2473. }
  2474. } else {
  2475. char *element = PQgetvalue(pgsql_result, pgsql_row, i);
  2476. if (element) {
  2477. const size_t element_len = strlen(element);
  2478. if (result_type & PGSQL_NUM) {
  2479. add_index_stringl(return_value, i, element, element_len);
  2480. }
  2481. if (result_type & PGSQL_ASSOC) {
  2482. field_name = PQfname(pgsql_result, i);
  2483. add_assoc_stringl(return_value, field_name, element, element_len);
  2484. }
  2485. }
  2486. }
  2487. }
  2488. if (into_object) {
  2489. zval dataset;
  2490. zend_fcall_info fci;
  2491. zend_fcall_info_cache fcc;
  2492. zval retval;
  2493. ZVAL_COPY_VALUE(&dataset, return_value);
  2494. object_init_ex(return_value, ce);
  2495. if (!ce->default_properties_count && !ce->__set) {
  2496. Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
  2497. } else {
  2498. zend_merge_properties(return_value, Z_ARRVAL(dataset));
  2499. zval_ptr_dtor(&dataset);
  2500. }
  2501. if (ce->constructor) {
  2502. fci.size = sizeof(fci);
  2503. ZVAL_UNDEF(&fci.function_name);
  2504. fci.object = Z_OBJ_P(return_value);
  2505. fci.retval = &retval;
  2506. fci.params = NULL;
  2507. fci.param_count = 0;
  2508. fci.no_separation = 1;
  2509. if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
  2510. if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) {
  2511. /* Two problems why we throw exceptions here: PHP is typeless
  2512. * and hence passing one argument that's not an array could be
  2513. * by mistake and the other way round is possible, too. The
  2514. * single value is an array. Also we'd have to make that one
  2515. * argument passed by reference.
  2516. */
  2517. zend_throw_exception(zend_ce_exception, "Parameter ctor_params must be an array", 0);
  2518. RETURN_THROWS();
  2519. }
  2520. }
  2521. fcc.function_handler = ce->constructor;
  2522. fcc.called_scope = Z_OBJCE_P(return_value);
  2523. fcc.object = Z_OBJ_P(return_value);
  2524. if (zend_call_function(&fci, &fcc) == FAILURE) {
  2525. zend_throw_exception_ex(zend_ce_exception, 0, "Could not execute %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
  2526. } else {
  2527. zval_ptr_dtor(&retval);
  2528. }
  2529. if (fci.params) {
  2530. efree(fci.params);
  2531. }
  2532. } else if (ctor_params) {
  2533. zend_throw_exception_ex(zend_ce_exception, 0, "Class %s does not have a constructor hence you cannot use ctor_params", ZSTR_VAL(ce->name));
  2534. }
  2535. }
  2536. }
  2537. /* }}} */
  2538. /* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
  2539. Get a row as an enumerated array */
  2540. PHP_FUNCTION(pg_fetch_row)
  2541. {
  2542. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
  2543. }
  2544. /* }}} */
  2545. /* {{{ proto array pg_fetch_assoc(resource result [, int row])
  2546. Fetch a row as an assoc array */
  2547. PHP_FUNCTION(pg_fetch_assoc)
  2548. {
  2549. /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
  2550. there is 3rd parameter */
  2551. if (ZEND_NUM_ARGS() > 2)
  2552. WRONG_PARAM_COUNT;
  2553. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
  2554. }
  2555. /* }}} */
  2556. /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
  2557. Fetch a row as an array */
  2558. PHP_FUNCTION(pg_fetch_array)
  2559. {
  2560. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
  2561. }
  2562. /* }}} */
  2563. /* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
  2564. Fetch a row as an object */
  2565. PHP_FUNCTION(pg_fetch_object)
  2566. {
  2567. /* pg_fetch_object() allowed result_type used to be. 3rd parameter
  2568. must be allowed for compatibility */
  2569. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
  2570. }
  2571. /* }}} */
  2572. /* {{{ proto array pg_fetch_all(resource result [, int result_type])
  2573. Fetch all rows into array */
  2574. PHP_FUNCTION(pg_fetch_all)
  2575. {
  2576. zval *result;
  2577. long result_type = PGSQL_ASSOC;
  2578. PGresult *pgsql_result;
  2579. pgsql_result_handle *pg_result;
  2580. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result, &result_type) == FAILURE) {
  2581. RETURN_THROWS();
  2582. }
  2583. if (!(result_type & PGSQL_BOTH)) {
  2584. php_error_docref(NULL, E_WARNING, "Invalid result type");
  2585. RETURN_FALSE;
  2586. }
  2587. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2588. RETURN_THROWS();
  2589. }
  2590. pgsql_result = pg_result->result;
  2591. array_init(return_value);
  2592. if (php_pgsql_result2array(pgsql_result, return_value, result_type) == FAILURE) {
  2593. zend_array_destroy(Z_ARR_P(return_value));
  2594. RETURN_FALSE;
  2595. }
  2596. }
  2597. /* }}} */
  2598. /* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
  2599. Fetch all rows into array */
  2600. PHP_FUNCTION(pg_fetch_all_columns)
  2601. {
  2602. zval *result;
  2603. PGresult *pgsql_result;
  2604. pgsql_result_handle *pg_result;
  2605. zend_long colno=0;
  2606. int pg_numrows, pg_row;
  2607. size_t num_fields;
  2608. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result, &colno) == FAILURE) {
  2609. RETURN_THROWS();
  2610. }
  2611. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2612. RETURN_THROWS();
  2613. }
  2614. pgsql_result = pg_result->result;
  2615. num_fields = PQnfields(pgsql_result);
  2616. if (colno >= (zend_long)num_fields || colno < 0) {
  2617. php_error_docref(NULL, E_WARNING, "Invalid column number '" ZEND_LONG_FMT "'", colno);
  2618. RETURN_FALSE;
  2619. }
  2620. array_init(return_value);
  2621. if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
  2622. return;
  2623. }
  2624. for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
  2625. if (PQgetisnull(pgsql_result, pg_row, (int)colno)) {
  2626. add_next_index_null(return_value);
  2627. } else {
  2628. add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, (int)colno));
  2629. }
  2630. }
  2631. }
  2632. /* }}} */
  2633. /* {{{ proto bool pg_result_seek(resource result, int offset)
  2634. Set internal row offset */
  2635. PHP_FUNCTION(pg_result_seek)
  2636. {
  2637. zval *result;
  2638. zend_long row;
  2639. pgsql_result_handle *pg_result;
  2640. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &result, &row) == FAILURE) {
  2641. RETURN_THROWS();
  2642. }
  2643. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2644. RETURN_THROWS();
  2645. }
  2646. if (row < 0 || row >= PQntuples(pg_result->result)) {
  2647. RETURN_FALSE;
  2648. }
  2649. /* seek to offset */
  2650. pg_result->row = (int)row;
  2651. RETURN_TRUE;
  2652. }
  2653. /* }}} */
  2654. #define PHP_PG_DATA_LENGTH 1
  2655. #define PHP_PG_DATA_ISNULL 2
  2656. /* {{{ php_pgsql_data_info
  2657. */
  2658. static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  2659. {
  2660. zval *result, *field;
  2661. zend_long row;
  2662. PGresult *pgsql_result;
  2663. pgsql_result_handle *pg_result;
  2664. int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
  2665. if (argc == 2) {
  2666. if (zend_parse_parameters(argc, "rz", &result, &field) == FAILURE) {
  2667. RETURN_THROWS();
  2668. }
  2669. } else {
  2670. if (zend_parse_parameters(argc, "rlz", &result, &row, &field) == FAILURE) {
  2671. RETURN_THROWS();
  2672. }
  2673. }
  2674. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2675. RETURN_THROWS();
  2676. }
  2677. pgsql_result = pg_result->result;
  2678. if (argc == 2) {
  2679. if (pg_result->row < 0) {
  2680. pg_result->row = 0;
  2681. }
  2682. pgsql_row = pg_result->row;
  2683. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2684. RETURN_FALSE;
  2685. }
  2686. } else {
  2687. if (row < 0 || row >= PQntuples(pgsql_result)) {
  2688. php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
  2689. row, Z_LVAL_P(result));
  2690. RETURN_FALSE;
  2691. }
  2692. pgsql_row = (int)row;
  2693. }
  2694. switch (Z_TYPE_P(field)) {
  2695. case IS_STRING:
  2696. field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
  2697. if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
  2698. php_error_docref(NULL, E_WARNING, "Bad column offset specified");
  2699. RETURN_FALSE;
  2700. }
  2701. break;
  2702. default:
  2703. convert_to_long_ex(field);
  2704. if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
  2705. php_error_docref(NULL, E_WARNING, "Bad column offset specified");
  2706. RETURN_FALSE;
  2707. }
  2708. field_offset = (int)Z_LVAL_P(field);
  2709. break;
  2710. }
  2711. switch (entry_type) {
  2712. case PHP_PG_DATA_LENGTH:
  2713. RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset));
  2714. break;
  2715. case PHP_PG_DATA_ISNULL:
  2716. RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset));
  2717. break;
  2718. }
  2719. }
  2720. /* }}} */
  2721. /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
  2722. Returns the printed length */
  2723. PHP_FUNCTION(pg_field_prtlen)
  2724. {
  2725. php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
  2726. }
  2727. /* }}} */
  2728. /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
  2729. Test if a field is NULL */
  2730. PHP_FUNCTION(pg_field_is_null)
  2731. {
  2732. php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
  2733. }
  2734. /* }}} */
  2735. /* {{{ proto bool pg_free_result(resource result)
  2736. Free result memory */
  2737. PHP_FUNCTION(pg_free_result)
  2738. {
  2739. zval *result;
  2740. pgsql_result_handle *pg_result;
  2741. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
  2742. RETURN_THROWS();
  2743. }
  2744. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2745. RETURN_THROWS();
  2746. }
  2747. zend_list_close(Z_RES_P(result));
  2748. RETURN_TRUE;
  2749. }
  2750. /* }}} */
  2751. /* {{{ proto string pg_last_oid(resource result)
  2752. Returns the last object identifier */
  2753. PHP_FUNCTION(pg_last_oid)
  2754. {
  2755. zval *result;
  2756. PGresult *pgsql_result;
  2757. pgsql_result_handle *pg_result;
  2758. #ifdef HAVE_PQOIDVALUE
  2759. Oid oid;
  2760. #endif
  2761. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
  2762. RETURN_THROWS();
  2763. }
  2764. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  2765. RETURN_THROWS();
  2766. }
  2767. pgsql_result = pg_result->result;
  2768. #ifdef HAVE_PQOIDVALUE
  2769. oid = PQoidValue(pgsql_result);
  2770. if (oid == InvalidOid) {
  2771. RETURN_FALSE;
  2772. }
  2773. PGSQL_RETURN_OID(oid);
  2774. #else
  2775. Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
  2776. if (Z_STRVAL_P(return_value)) {
  2777. RETURN_STRING(Z_STRVAL_P(return_value));
  2778. }
  2779. RETURN_EMPTY_STRING();
  2780. #endif
  2781. }
  2782. /* }}} */
  2783. /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
  2784. Enable tracing a PostgreSQL connection */
  2785. PHP_FUNCTION(pg_trace)
  2786. {
  2787. char *z_filename, *mode = "w";
  2788. size_t z_filename_len, mode_len;
  2789. zval *pgsql_link = NULL;
  2790. int argc = ZEND_NUM_ARGS();
  2791. PGconn *pgsql;
  2792. FILE *fp = NULL;
  2793. php_stream *stream;
  2794. zend_resource *link;
  2795. if (zend_parse_parameters(argc, "p|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) {
  2796. RETURN_THROWS();
  2797. }
  2798. if (argc < 3) {
  2799. link = FETCH_DEFAULT_LINK();
  2800. CHECK_DEFAULT_LINK(link);
  2801. } else {
  2802. link = Z_RES_P(pgsql_link);
  2803. }
  2804. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  2805. RETURN_THROWS();
  2806. }
  2807. stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
  2808. if (!stream) {
  2809. RETURN_FALSE;
  2810. }
  2811. if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
  2812. php_stream_close(stream);
  2813. RETURN_FALSE;
  2814. }
  2815. php_stream_auto_cleanup(stream);
  2816. PQtrace(pgsql, fp);
  2817. RETURN_TRUE;
  2818. }
  2819. /* }}} */
  2820. /* {{{ proto bool pg_untrace([resource connection])
  2821. Disable tracing of a PostgreSQL connection */
  2822. PHP_FUNCTION(pg_untrace)
  2823. {
  2824. zval *pgsql_link = NULL;
  2825. int argc = ZEND_NUM_ARGS();
  2826. PGconn *pgsql;
  2827. zend_resource *link;
  2828. if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
  2829. RETURN_THROWS();
  2830. }
  2831. if (argc == 0) {
  2832. link = FETCH_DEFAULT_LINK();
  2833. CHECK_DEFAULT_LINK(link);
  2834. } else {
  2835. link = Z_RES_P(pgsql_link);
  2836. }
  2837. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  2838. RETURN_THROWS();
  2839. }
  2840. PQuntrace(pgsql);
  2841. RETURN_TRUE;
  2842. }
  2843. /* }}} */
  2844. /* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid])
  2845. Create a large object */
  2846. PHP_FUNCTION(pg_lo_create)
  2847. {
  2848. zval *pgsql_link = NULL, *oid = NULL;
  2849. PGconn *pgsql;
  2850. Oid pgsql_oid, wanted_oid = InvalidOid;
  2851. int argc = ZEND_NUM_ARGS();
  2852. zend_resource *link;
  2853. if (zend_parse_parameters(argc, "|zz", &pgsql_link, &oid) == FAILURE) {
  2854. RETURN_THROWS();
  2855. }
  2856. if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) {
  2857. oid = pgsql_link;
  2858. pgsql_link = NULL;
  2859. }
  2860. if (pgsql_link == NULL) {
  2861. link = FETCH_DEFAULT_LINK();
  2862. CHECK_DEFAULT_LINK(link);
  2863. } else if ((Z_TYPE_P(pgsql_link) == IS_RESOURCE)) {
  2864. link = Z_RES_P(pgsql_link);
  2865. } else {
  2866. link = NULL;
  2867. }
  2868. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  2869. RETURN_THROWS();
  2870. }
  2871. if (oid) {
  2872. #ifndef HAVE_PG_LO_CREATE
  2873. php_error_docref(NULL, E_NOTICE, "Passing OID value is not supported. Upgrade your PostgreSQL");
  2874. #else
  2875. switch (Z_TYPE_P(oid)) {
  2876. case IS_STRING:
  2877. {
  2878. char *end_ptr;
  2879. wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
  2880. if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
  2881. /* wrong integer format */
  2882. php_error_docref(NULL, E_NOTICE, "Invalid OID value passed");
  2883. RETURN_FALSE;
  2884. }
  2885. }
  2886. break;
  2887. case IS_LONG:
  2888. if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
  2889. php_error_docref(NULL, E_NOTICE, "Invalid OID value passed");
  2890. RETURN_FALSE;
  2891. }
  2892. wanted_oid = (Oid)Z_LVAL_P(oid);
  2893. break;
  2894. default:
  2895. php_error_docref(NULL, E_NOTICE, "Invalid OID value passed");
  2896. RETURN_FALSE;
  2897. }
  2898. if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
  2899. php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
  2900. RETURN_FALSE;
  2901. }
  2902. PGSQL_RETURN_OID(pgsql_oid);
  2903. #endif
  2904. }
  2905. if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
  2906. php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
  2907. RETURN_FALSE;
  2908. }
  2909. PGSQL_RETURN_OID(pgsql_oid);
  2910. }
  2911. /* }}} */
  2912. /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
  2913. Delete a large object */
  2914. PHP_FUNCTION(pg_lo_unlink)
  2915. {
  2916. zval *pgsql_link = NULL;
  2917. zend_long oid_long;
  2918. char *oid_string, *end_ptr;
  2919. size_t oid_strlen;
  2920. PGconn *pgsql;
  2921. Oid oid;
  2922. zend_resource *link;
  2923. int argc = ZEND_NUM_ARGS();
  2924. /* accept string type since Oid type is unsigned int */
  2925. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  2926. "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
  2927. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2928. if ((oid_string+oid_strlen) != end_ptr) {
  2929. /* wrong integer format */
  2930. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  2931. RETURN_FALSE;
  2932. }
  2933. link = Z_RES_P(pgsql_link);
  2934. }
  2935. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  2936. "rl", &pgsql_link, &oid_long) == SUCCESS) {
  2937. if (oid_long <= (zend_long)InvalidOid) {
  2938. php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
  2939. RETURN_FALSE;
  2940. }
  2941. oid = (Oid)oid_long;
  2942. link = Z_RES_P(pgsql_link);
  2943. }
  2944. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  2945. "s", &oid_string, &oid_strlen) == SUCCESS) {
  2946. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2947. if ((oid_string+oid_strlen) != end_ptr) {
  2948. /* wrong integer format */
  2949. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  2950. RETURN_FALSE;
  2951. }
  2952. link = FETCH_DEFAULT_LINK();
  2953. CHECK_DEFAULT_LINK(link);
  2954. }
  2955. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  2956. "l", &oid_long) == SUCCESS) {
  2957. if (oid_long <= (zend_long)InvalidOid) {
  2958. php_error_docref(NULL, E_NOTICE, "Invalid OID is specified");
  2959. RETURN_FALSE;
  2960. }
  2961. oid = (Oid)oid_long;
  2962. link = FETCH_DEFAULT_LINK();
  2963. CHECK_DEFAULT_LINK(link);
  2964. }
  2965. else {
  2966. php_error_docref(NULL, E_WARNING, "Requires 1 or 2 arguments");
  2967. RETURN_FALSE;
  2968. }
  2969. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  2970. RETURN_THROWS();
  2971. }
  2972. if (lo_unlink(pgsql, oid) == -1) {
  2973. php_error_docref(NULL, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
  2974. RETURN_FALSE;
  2975. }
  2976. RETURN_TRUE;
  2977. }
  2978. /* }}} */
  2979. /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
  2980. Open a large object and return fd */
  2981. PHP_FUNCTION(pg_lo_open)
  2982. {
  2983. zval *pgsql_link = NULL;
  2984. zend_long oid_long;
  2985. char *oid_string, *end_ptr, *mode_string;
  2986. size_t oid_strlen, mode_strlen;
  2987. PGconn *pgsql;
  2988. Oid oid;
  2989. int pgsql_mode=0, pgsql_lofd;
  2990. int create = 0;
  2991. pgLofp *pgsql_lofp;
  2992. int argc = ZEND_NUM_ARGS();
  2993. zend_resource *link;
  2994. /* accept string type since Oid is unsigned int */
  2995. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  2996. "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
  2997. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2998. if ((oid_string+oid_strlen) != end_ptr) {
  2999. /* wrong integer format */
  3000. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  3001. RETURN_FALSE;
  3002. }
  3003. link = Z_RES_P(pgsql_link);
  3004. }
  3005. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3006. "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
  3007. if (oid_long <= (zend_long)InvalidOid) {
  3008. php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
  3009. RETURN_FALSE;
  3010. }
  3011. oid = (Oid)oid_long;
  3012. link = Z_RES_P(pgsql_link);
  3013. }
  3014. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3015. "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
  3016. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3017. if ((oid_string+oid_strlen) != end_ptr) {
  3018. /* wrong integer format */
  3019. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  3020. RETURN_FALSE;
  3021. }
  3022. link = FETCH_DEFAULT_LINK();
  3023. CHECK_DEFAULT_LINK(link);
  3024. }
  3025. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3026. "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
  3027. if (oid_long <= (zend_long)InvalidOid) {
  3028. php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
  3029. RETURN_FALSE;
  3030. }
  3031. oid = (Oid)oid_long;
  3032. link = FETCH_DEFAULT_LINK();
  3033. CHECK_DEFAULT_LINK(link);
  3034. }
  3035. else {
  3036. php_error_docref(NULL, E_WARNING, "Requires 1 or 2 arguments");
  3037. RETURN_FALSE;
  3038. }
  3039. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3040. RETURN_THROWS();
  3041. }
  3042. /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
  3043. faster to type. Unfortunately, doesn't behave the same way as fopen()...
  3044. (Jouni)
  3045. */
  3046. if (strchr(mode_string, 'r') == mode_string) {
  3047. pgsql_mode |= INV_READ;
  3048. if (strchr(mode_string, '+') == mode_string+1) {
  3049. pgsql_mode |= INV_WRITE;
  3050. }
  3051. }
  3052. if (strchr(mode_string, 'w') == mode_string) {
  3053. pgsql_mode |= INV_WRITE;
  3054. create = 1;
  3055. if (strchr(mode_string, '+') == mode_string+1) {
  3056. pgsql_mode |= INV_READ;
  3057. }
  3058. }
  3059. pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
  3060. if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
  3061. if (create) {
  3062. if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
  3063. efree(pgsql_lofp);
  3064. php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
  3065. RETURN_FALSE;
  3066. } else {
  3067. if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
  3068. if (lo_unlink(pgsql, oid) == -1) {
  3069. efree(pgsql_lofp);
  3070. php_error_docref(NULL, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
  3071. RETURN_FALSE;
  3072. }
  3073. efree(pgsql_lofp);
  3074. php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
  3075. RETURN_FALSE;
  3076. } else {
  3077. pgsql_lofp->conn = pgsql;
  3078. pgsql_lofp->lofd = pgsql_lofd;
  3079. RETURN_RES(zend_register_resource(pgsql_lofp, le_lofp));
  3080. }
  3081. }
  3082. } else {
  3083. efree(pgsql_lofp);
  3084. php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
  3085. RETURN_FALSE;
  3086. }
  3087. } else {
  3088. pgsql_lofp->conn = pgsql;
  3089. pgsql_lofp->lofd = pgsql_lofd;
  3090. RETURN_RES(zend_register_resource(pgsql_lofp, le_lofp));
  3091. }
  3092. }
  3093. /* }}} */
  3094. /* {{{ proto bool pg_lo_close(resource large_object)
  3095. Close a large object */
  3096. PHP_FUNCTION(pg_lo_close)
  3097. {
  3098. zval *pgsql_lofp;
  3099. pgLofp *pgsql;
  3100. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_lofp) == FAILURE) {
  3101. RETURN_THROWS();
  3102. }
  3103. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_lofp), "PostgreSQL large object", le_lofp)) == NULL) {
  3104. RETURN_THROWS();
  3105. }
  3106. if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
  3107. php_error_docref(NULL, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
  3108. RETVAL_FALSE;
  3109. } else {
  3110. RETVAL_TRUE;
  3111. }
  3112. zend_list_close(Z_RES_P(pgsql_lofp));
  3113. return;
  3114. }
  3115. /* }}} */
  3116. #define PGSQL_LO_READ_BUF_SIZE 8192
  3117. /* {{{ proto string pg_lo_read(resource large_object [, int len])
  3118. Read a large object */
  3119. PHP_FUNCTION(pg_lo_read)
  3120. {
  3121. zval *pgsql_id;
  3122. zend_long len;
  3123. size_t buf_len = PGSQL_LO_READ_BUF_SIZE;
  3124. int nbytes, argc = ZEND_NUM_ARGS();
  3125. zend_string *buf;
  3126. pgLofp *pgsql;
  3127. if (zend_parse_parameters(argc, "r|l", &pgsql_id, &len) == FAILURE) {
  3128. RETURN_THROWS();
  3129. }
  3130. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
  3131. RETURN_THROWS();
  3132. }
  3133. if (argc > 1) {
  3134. buf_len = len < 0 ? 0 : len;
  3135. }
  3136. buf = zend_string_alloc(buf_len, 0);
  3137. if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, ZSTR_VAL(buf), ZSTR_LEN(buf)))<0) {
  3138. zend_string_efree(buf);
  3139. RETURN_FALSE;
  3140. }
  3141. ZSTR_LEN(buf) = nbytes;
  3142. ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0';
  3143. RETURN_NEW_STR(buf);
  3144. }
  3145. /* }}} */
  3146. /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
  3147. Write a large object */
  3148. PHP_FUNCTION(pg_lo_write)
  3149. {
  3150. zval *pgsql_id;
  3151. char *str;
  3152. zend_long z_len;
  3153. size_t str_len, nbytes;
  3154. size_t len;
  3155. pgLofp *pgsql;
  3156. int argc = ZEND_NUM_ARGS();
  3157. if (zend_parse_parameters(argc, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) {
  3158. RETURN_THROWS();
  3159. }
  3160. if (argc > 2) {
  3161. if (z_len > (zend_long)str_len) {
  3162. php_error_docref(NULL, E_WARNING, "Cannot write more than buffer size %zu. Tried to write " ZEND_LONG_FMT, str_len, z_len);
  3163. RETURN_FALSE;
  3164. }
  3165. if (z_len < 0) {
  3166. php_error_docref(NULL, E_WARNING, "Buffer size must be larger than 0, but " ZEND_LONG_FMT " was specified", z_len);
  3167. RETURN_FALSE;
  3168. }
  3169. len = z_len;
  3170. }
  3171. else {
  3172. len = str_len;
  3173. }
  3174. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
  3175. RETURN_THROWS();
  3176. }
  3177. if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == (size_t)-1) {
  3178. RETURN_FALSE;
  3179. }
  3180. RETURN_LONG(nbytes);
  3181. }
  3182. /* }}} */
  3183. /* {{{ proto int pg_lo_read_all(resource large_object)
  3184. Read a large object and send straight to browser */
  3185. PHP_FUNCTION(pg_lo_read_all)
  3186. {
  3187. zval *pgsql_id;
  3188. int tbytes;
  3189. volatile int nbytes;
  3190. char buf[PGSQL_LO_READ_BUF_SIZE];
  3191. pgLofp *pgsql;
  3192. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_id) == FAILURE) {
  3193. RETURN_THROWS();
  3194. }
  3195. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
  3196. RETURN_THROWS();
  3197. }
  3198. tbytes = 0;
  3199. while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
  3200. PHPWRITE(buf, nbytes);
  3201. tbytes += nbytes;
  3202. }
  3203. RETURN_LONG(tbytes);
  3204. }
  3205. /* }}} */
  3206. /* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid])
  3207. Import large object direct from filesystem */
  3208. PHP_FUNCTION(pg_lo_import)
  3209. {
  3210. zval *pgsql_link = NULL, *oid = NULL;
  3211. char *file_in;
  3212. size_t name_len;
  3213. int argc = ZEND_NUM_ARGS();
  3214. PGconn *pgsql;
  3215. Oid returned_oid;
  3216. zend_resource *link;
  3217. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3218. "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
  3219. link = Z_RES_P(pgsql_link);
  3220. }
  3221. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3222. "p|z", &file_in, &name_len, &oid) == SUCCESS) {
  3223. link = FETCH_DEFAULT_LINK();
  3224. CHECK_DEFAULT_LINK(link);
  3225. }
  3226. /* old calling convention, deprecated since PHP 4.2 */
  3227. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3228. "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
  3229. php_error_docref(NULL, E_NOTICE, "Old API is used");
  3230. link = Z_RES_P(pgsql_link);
  3231. }
  3232. else {
  3233. WRONG_PARAM_COUNT;
  3234. }
  3235. if (php_check_open_basedir(file_in)) {
  3236. RETURN_FALSE;
  3237. }
  3238. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3239. RETURN_THROWS();
  3240. }
  3241. if (oid) {
  3242. #ifndef HAVE_PG_LO_IMPORT_WITH_OID
  3243. php_error_docref(NULL, E_NOTICE, "OID value passing not supported");
  3244. #else
  3245. Oid wanted_oid;
  3246. switch (Z_TYPE_P(oid)) {
  3247. case IS_STRING:
  3248. {
  3249. char *end_ptr;
  3250. wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
  3251. if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
  3252. /* wrong integer format */
  3253. php_error_docref(NULL, E_NOTICE, "Invalid OID value passed");
  3254. RETURN_FALSE;
  3255. }
  3256. }
  3257. break;
  3258. case IS_LONG:
  3259. if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
  3260. php_error_docref(NULL, E_NOTICE, "Invalid OID value passed");
  3261. RETURN_FALSE;
  3262. }
  3263. wanted_oid = (Oid)Z_LVAL_P(oid);
  3264. break;
  3265. default:
  3266. php_error_docref(NULL, E_NOTICE, "Invalid OID value passed");
  3267. RETURN_FALSE;
  3268. }
  3269. returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid);
  3270. if (returned_oid == InvalidOid) {
  3271. RETURN_FALSE;
  3272. }
  3273. PGSQL_RETURN_OID(returned_oid);
  3274. #endif
  3275. }
  3276. returned_oid = lo_import(pgsql, file_in);
  3277. if (returned_oid == InvalidOid) {
  3278. RETURN_FALSE;
  3279. }
  3280. PGSQL_RETURN_OID(returned_oid);
  3281. }
  3282. /* }}} */
  3283. /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
  3284. Export large object direct to filesystem */
  3285. PHP_FUNCTION(pg_lo_export)
  3286. {
  3287. zval *pgsql_link = NULL;
  3288. char *file_out, *oid_string, *end_ptr;
  3289. size_t oid_strlen;
  3290. size_t name_len;
  3291. zend_long oid_long;
  3292. Oid oid;
  3293. PGconn *pgsql;
  3294. int argc = ZEND_NUM_ARGS();
  3295. zend_resource *link;
  3296. /* allow string to handle large OID value correctly */
  3297. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3298. "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
  3299. if (oid_long <= (zend_long)InvalidOid) {
  3300. php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
  3301. RETURN_FALSE;
  3302. }
  3303. oid = (Oid)oid_long;
  3304. link = Z_RES_P(pgsql_link);
  3305. }
  3306. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3307. "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
  3308. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3309. if ((oid_string+oid_strlen) != end_ptr) {
  3310. /* wrong integer format */
  3311. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  3312. RETURN_FALSE;
  3313. }
  3314. link = Z_RES_P(pgsql_link);
  3315. }
  3316. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3317. "lp", &oid_long, &file_out, &name_len) == SUCCESS) {
  3318. if (oid_long <= (zend_long)InvalidOid) {
  3319. php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
  3320. RETURN_FALSE;
  3321. }
  3322. oid = (Oid)oid_long;
  3323. link = FETCH_DEFAULT_LINK();
  3324. CHECK_DEFAULT_LINK(link);
  3325. }
  3326. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3327. "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
  3328. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3329. if ((oid_string+oid_strlen) != end_ptr) {
  3330. /* wrong integer format */
  3331. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  3332. RETURN_FALSE;
  3333. }
  3334. link = FETCH_DEFAULT_LINK();
  3335. CHECK_DEFAULT_LINK(link);
  3336. }
  3337. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3338. "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
  3339. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3340. if ((oid_string+oid_strlen) != end_ptr) {
  3341. /* wrong integer format */
  3342. php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
  3343. RETURN_FALSE;
  3344. }
  3345. link = Z_RES_P(pgsql_link);
  3346. }
  3347. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
  3348. "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
  3349. php_error_docref(NULL, E_NOTICE, "Old API is used");
  3350. if (oid_long <= (zend_long)InvalidOid) {
  3351. php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
  3352. RETURN_FALSE;
  3353. }
  3354. oid = (Oid)oid_long;
  3355. link = Z_RES_P(pgsql_link);
  3356. }
  3357. else {
  3358. php_error_docref(NULL, E_WARNING, "Requires 2 or 3 arguments");
  3359. RETURN_FALSE;
  3360. }
  3361. if (php_check_open_basedir(file_out)) {
  3362. RETURN_FALSE;
  3363. }
  3364. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3365. RETURN_THROWS();
  3366. }
  3367. if (lo_export(pgsql, oid, file_out) == -1) {
  3368. RETURN_FALSE;
  3369. }
  3370. RETURN_TRUE;
  3371. }
  3372. /* }}} */
  3373. /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
  3374. Seeks position of large object */
  3375. PHP_FUNCTION(pg_lo_seek)
  3376. {
  3377. zval *pgsql_id = NULL;
  3378. zend_long result, offset = 0, whence = SEEK_CUR;
  3379. pgLofp *pgsql;
  3380. int argc = ZEND_NUM_ARGS();
  3381. if (zend_parse_parameters(argc, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
  3382. RETURN_THROWS();
  3383. }
  3384. if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
  3385. php_error_docref(NULL, E_WARNING, "Invalid whence parameter");
  3386. return;
  3387. }
  3388. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
  3389. RETURN_THROWS();
  3390. }
  3391. #if HAVE_PG_LO64
  3392. if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
  3393. result = lo_lseek64((PGconn *)pgsql->conn, pgsql->lofd, offset, (int)whence);
  3394. } else {
  3395. result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, (int)offset, (int)whence);
  3396. }
  3397. #else
  3398. result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
  3399. #endif
  3400. if (result > -1) {
  3401. RETURN_TRUE;
  3402. } else {
  3403. RETURN_FALSE;
  3404. }
  3405. }
  3406. /* }}} */
  3407. /* {{{ proto int pg_lo_tell(resource large_object)
  3408. Returns current position of large object */
  3409. PHP_FUNCTION(pg_lo_tell)
  3410. {
  3411. zval *pgsql_id = NULL;
  3412. zend_long offset = 0;
  3413. pgLofp *pgsql;
  3414. int argc = ZEND_NUM_ARGS();
  3415. if (zend_parse_parameters(argc, "r", &pgsql_id) == FAILURE) {
  3416. RETURN_THROWS();
  3417. }
  3418. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
  3419. RETURN_THROWS();
  3420. }
  3421. #if HAVE_PG_LO64
  3422. if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
  3423. offset = lo_tell64((PGconn *)pgsql->conn, pgsql->lofd);
  3424. } else {
  3425. offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
  3426. }
  3427. #else
  3428. offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
  3429. #endif
  3430. RETURN_LONG(offset);
  3431. }
  3432. /* }}} */
  3433. #if HAVE_PG_LO_TRUNCATE
  3434. /* {{{ proto bool pg_lo_truncate(resource large_object, int size)
  3435. Truncate large object to size */
  3436. PHP_FUNCTION(pg_lo_truncate)
  3437. {
  3438. zval *pgsql_id = NULL;
  3439. size_t size;
  3440. pgLofp *pgsql;
  3441. int argc = ZEND_NUM_ARGS();
  3442. int result;
  3443. if (zend_parse_parameters(argc, "rl", &pgsql_id, &size) == FAILURE) {
  3444. RETURN_THROWS();
  3445. }
  3446. if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
  3447. RETURN_THROWS();
  3448. }
  3449. #if HAVE_PG_LO64
  3450. if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
  3451. result = lo_truncate64((PGconn *)pgsql->conn, pgsql->lofd, size);
  3452. } else {
  3453. result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
  3454. }
  3455. #else
  3456. result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
  3457. #endif
  3458. if (!result) {
  3459. RETURN_TRUE;
  3460. } else {
  3461. RETURN_FALSE;
  3462. }
  3463. }
  3464. /* }}} */
  3465. #endif
  3466. #if HAVE_PQSETERRORVERBOSITY
  3467. /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
  3468. Set error verbosity */
  3469. PHP_FUNCTION(pg_set_error_verbosity)
  3470. {
  3471. zval *pgsql_link = NULL;
  3472. zend_long verbosity;
  3473. int argc = ZEND_NUM_ARGS();
  3474. PGconn *pgsql;
  3475. zend_resource *link;
  3476. if (argc == 1) {
  3477. if (zend_parse_parameters(argc, "l", &verbosity) == FAILURE) {
  3478. RETURN_THROWS();
  3479. }
  3480. link = FETCH_DEFAULT_LINK();
  3481. CHECK_DEFAULT_LINK(link);
  3482. } else {
  3483. if (zend_parse_parameters(argc, "rl", &pgsql_link, &verbosity) == FAILURE) {
  3484. RETURN_THROWS();
  3485. }
  3486. link = Z_RES_P(pgsql_link);
  3487. }
  3488. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3489. RETURN_THROWS();
  3490. }
  3491. if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
  3492. RETURN_LONG(PQsetErrorVerbosity(pgsql, verbosity));
  3493. } else {
  3494. RETURN_FALSE;
  3495. }
  3496. }
  3497. /* }}} */
  3498. #endif
  3499. #ifdef HAVE_PQCLIENTENCODING
  3500. /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
  3501. Set client encoding */
  3502. PHP_FUNCTION(pg_set_client_encoding)
  3503. {
  3504. char *encoding;
  3505. size_t encoding_len;
  3506. zval *pgsql_link = NULL;
  3507. int argc = ZEND_NUM_ARGS();
  3508. PGconn *pgsql;
  3509. zend_resource *link;
  3510. if (argc == 1) {
  3511. if (zend_parse_parameters(argc, "s", &encoding, &encoding_len) == FAILURE) {
  3512. RETURN_THROWS();
  3513. }
  3514. link = FETCH_DEFAULT_LINK();
  3515. CHECK_DEFAULT_LINK(link);
  3516. } else {
  3517. if (zend_parse_parameters(argc, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) {
  3518. RETURN_THROWS();
  3519. }
  3520. link = Z_RES_P(pgsql_link);
  3521. }
  3522. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3523. RETURN_THROWS();
  3524. }
  3525. RETURN_LONG(PQsetClientEncoding(pgsql, encoding));
  3526. }
  3527. /* }}} */
  3528. /* {{{ proto string pg_client_encoding([resource connection])
  3529. Get the current client encoding */
  3530. PHP_FUNCTION(pg_client_encoding)
  3531. {
  3532. zval *pgsql_link = NULL;
  3533. int argc = ZEND_NUM_ARGS();
  3534. PGconn *pgsql;
  3535. zend_resource *link;
  3536. if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
  3537. RETURN_THROWS();
  3538. }
  3539. if (argc == 0) {
  3540. link = FETCH_DEFAULT_LINK();
  3541. CHECK_DEFAULT_LINK(link);
  3542. } else {
  3543. link = Z_RES_P(pgsql_link);
  3544. }
  3545. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3546. RETURN_THROWS();
  3547. }
  3548. /* Just do the same as found in PostgreSQL sources... */
  3549. RETURN_STRING((char *) pg_encoding_to_char(PQclientEncoding(pgsql)));
  3550. }
  3551. /* }}} */
  3552. #endif
  3553. #if !HAVE_PQGETCOPYDATA
  3554. #define COPYBUFSIZ 8192
  3555. #endif
  3556. /* {{{ proto bool pg_end_copy([resource connection])
  3557. Sync with backend. Completes the Copy command */
  3558. PHP_FUNCTION(pg_end_copy)
  3559. {
  3560. zval *pgsql_link = NULL;
  3561. int argc = ZEND_NUM_ARGS();
  3562. PGconn *pgsql;
  3563. int result = 0;
  3564. zend_resource *link;
  3565. if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
  3566. RETURN_THROWS();
  3567. }
  3568. if (argc == 0) {
  3569. link = FETCH_DEFAULT_LINK();
  3570. CHECK_DEFAULT_LINK(link);
  3571. } else {
  3572. link = Z_RES_P(pgsql_link);
  3573. }
  3574. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3575. RETURN_THROWS();
  3576. }
  3577. result = PQendcopy(pgsql);
  3578. if (result!=0) {
  3579. PHP_PQ_ERROR("Query failed: %s", pgsql);
  3580. RETURN_FALSE;
  3581. }
  3582. RETURN_TRUE;
  3583. }
  3584. /* }}} */
  3585. /* {{{ proto bool pg_put_line([resource connection,] string query)
  3586. Send null-terminated string to backend server*/
  3587. PHP_FUNCTION(pg_put_line)
  3588. {
  3589. char *query;
  3590. zval *pgsql_link = NULL;
  3591. size_t query_len;
  3592. PGconn *pgsql;
  3593. zend_resource *link;
  3594. int result = 0, argc = ZEND_NUM_ARGS();
  3595. if (argc == 1) {
  3596. if (zend_parse_parameters(argc, "s", &query, &query_len) == FAILURE) {
  3597. RETURN_THROWS();
  3598. }
  3599. link = FETCH_DEFAULT_LINK();
  3600. CHECK_DEFAULT_LINK(link);
  3601. } else {
  3602. if (zend_parse_parameters(argc, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
  3603. RETURN_THROWS();
  3604. }
  3605. link = Z_RES_P(pgsql_link);
  3606. }
  3607. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3608. RETURN_THROWS();
  3609. }
  3610. result = PQputline(pgsql, query);
  3611. if (result==EOF) {
  3612. PHP_PQ_ERROR("Query failed: %s", pgsql);
  3613. RETURN_FALSE;
  3614. }
  3615. RETURN_TRUE;
  3616. }
  3617. /* }}} */
  3618. /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
  3619. Copy table to array */
  3620. PHP_FUNCTION(pg_copy_to)
  3621. {
  3622. zval *pgsql_link;
  3623. char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
  3624. size_t table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0;
  3625. char *query;
  3626. PGconn *pgsql;
  3627. PGresult *pgsql_result;
  3628. ExecStatusType status;
  3629. char *csv = (char *)NULL;
  3630. int argc = ZEND_NUM_ARGS();
  3631. if (zend_parse_parameters(argc, "rs|ss",
  3632. &pgsql_link, &table_name, &table_name_len,
  3633. &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
  3634. RETURN_THROWS();
  3635. }
  3636. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  3637. RETURN_THROWS();
  3638. }
  3639. if (!pg_delim) {
  3640. pg_delim = "\t";
  3641. }
  3642. if (!pg_null_as) {
  3643. pg_null_as = estrdup("\\\\N");
  3644. free_pg_null = 1;
  3645. }
  3646. spprintf(&query, 0, "COPY %s TO STDOUT DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
  3647. while ((pgsql_result = PQgetResult(pgsql))) {
  3648. PQclear(pgsql_result);
  3649. }
  3650. pgsql_result = PQexec(pgsql, query);
  3651. if (free_pg_null) {
  3652. efree(pg_null_as);
  3653. }
  3654. efree(query);
  3655. if (pgsql_result) {
  3656. status = PQresultStatus(pgsql_result);
  3657. } else {
  3658. status = (ExecStatusType) PQstatus(pgsql);
  3659. }
  3660. switch (status) {
  3661. case PGRES_COPY_OUT:
  3662. if (pgsql_result) {
  3663. int copydone = 0;
  3664. #if !HAVE_PQGETCOPYDATA
  3665. char copybuf[COPYBUFSIZ];
  3666. #endif
  3667. PQclear(pgsql_result);
  3668. array_init(return_value);
  3669. #if HAVE_PQGETCOPYDATA
  3670. while (!copydone)
  3671. {
  3672. int ret = PQgetCopyData(pgsql, &csv, 0);
  3673. switch (ret) {
  3674. case -1:
  3675. copydone = 1;
  3676. break;
  3677. case 0:
  3678. case -2:
  3679. PHP_PQ_ERROR("getline failed: %s", pgsql);
  3680. RETURN_FALSE;
  3681. break;
  3682. default:
  3683. add_next_index_string(return_value, csv);
  3684. PQfreemem(csv);
  3685. break;
  3686. }
  3687. }
  3688. #else
  3689. while (!copydone)
  3690. {
  3691. if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
  3692. PHP_PQ_ERROR("getline failed: %s", pgsql);
  3693. RETURN_FALSE;
  3694. }
  3695. if (copybuf[0] == '\\' &&
  3696. copybuf[1] == '.' &&
  3697. copybuf[2] == '\0')
  3698. {
  3699. copydone = 1;
  3700. }
  3701. else
  3702. {
  3703. if (csv == (char *)NULL) {
  3704. csv = estrdup(copybuf);
  3705. } else {
  3706. csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
  3707. strcat(csv, copybuf);
  3708. }
  3709. switch (ret)
  3710. {
  3711. case EOF:
  3712. copydone = 1;
  3713. case 0:
  3714. add_next_index_string(return_value, csv);
  3715. efree(csv);
  3716. csv = (char *)NULL;
  3717. break;
  3718. case 1:
  3719. break;
  3720. }
  3721. }
  3722. }
  3723. if (PQendcopy(pgsql)) {
  3724. PHP_PQ_ERROR("endcopy failed: %s", pgsql);
  3725. RETURN_FALSE;
  3726. }
  3727. #endif
  3728. while ((pgsql_result = PQgetResult(pgsql))) {
  3729. PQclear(pgsql_result);
  3730. }
  3731. } else {
  3732. PQclear(pgsql_result);
  3733. RETURN_FALSE;
  3734. }
  3735. break;
  3736. default:
  3737. PQclear(pgsql_result);
  3738. PHP_PQ_ERROR("Copy command failed: %s", pgsql);
  3739. RETURN_FALSE;
  3740. break;
  3741. }
  3742. }
  3743. /* }}} */
  3744. /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
  3745. Copy table from array */
  3746. PHP_FUNCTION(pg_copy_from)
  3747. {
  3748. zval *pgsql_link = NULL, *pg_rows;
  3749. zval *value;
  3750. char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
  3751. size_t table_name_len, pg_delim_len, pg_null_as_len;
  3752. int pg_null_as_free = 0;
  3753. char *query;
  3754. PGconn *pgsql;
  3755. PGresult *pgsql_result;
  3756. ExecStatusType status;
  3757. int argc = ZEND_NUM_ARGS();
  3758. if (zend_parse_parameters(argc, "rsa|ss",
  3759. &pgsql_link, &table_name, &table_name_len, &pg_rows,
  3760. &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
  3761. RETURN_THROWS();
  3762. }
  3763. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  3764. RETURN_THROWS();
  3765. }
  3766. if (!pg_delim) {
  3767. pg_delim = "\t";
  3768. }
  3769. if (!pg_null_as) {
  3770. pg_null_as = estrdup("\\\\N");
  3771. pg_null_as_free = 1;
  3772. }
  3773. spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
  3774. while ((pgsql_result = PQgetResult(pgsql))) {
  3775. PQclear(pgsql_result);
  3776. }
  3777. pgsql_result = PQexec(pgsql, query);
  3778. if (pg_null_as_free) {
  3779. efree(pg_null_as);
  3780. }
  3781. efree(query);
  3782. if (pgsql_result) {
  3783. status = PQresultStatus(pgsql_result);
  3784. } else {
  3785. status = (ExecStatusType) PQstatus(pgsql);
  3786. }
  3787. switch (status) {
  3788. case PGRES_COPY_IN:
  3789. if (pgsql_result) {
  3790. int command_failed = 0;
  3791. PQclear(pgsql_result);
  3792. #if HAVE_PQPUTCOPYDATA
  3793. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
  3794. zend_string *tmp = zval_try_get_string(value);
  3795. if (UNEXPECTED(!tmp)) {
  3796. return;
  3797. }
  3798. query = (char *)emalloc(ZSTR_LEN(tmp) + 2);
  3799. strlcpy(query, ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 2);
  3800. if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') {
  3801. strlcat(query, "\n", ZSTR_LEN(tmp) + 2);
  3802. }
  3803. if (PQputCopyData(pgsql, query, (int)strlen(query)) != 1) {
  3804. efree(query);
  3805. zend_string_release(tmp);
  3806. PHP_PQ_ERROR("copy failed: %s", pgsql);
  3807. RETURN_FALSE;
  3808. }
  3809. efree(query);
  3810. zend_string_release(tmp);
  3811. } ZEND_HASH_FOREACH_END();
  3812. if (PQputCopyEnd(pgsql, NULL) != 1) {
  3813. PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
  3814. RETURN_FALSE;
  3815. }
  3816. #else
  3817. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
  3818. zend_string *tmp = zval_try_get_string(value);
  3819. if (UNEXPECTED(!tmp)) {
  3820. return;
  3821. }
  3822. query = (char *)emalloc(ZSTR_LEN(tmp) + 2);
  3823. strlcpy(query, ZSTR_LVAL(tmp), ZSTR_LEN(tmp) + 2);
  3824. if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') {
  3825. strlcat(query, "\n", ZSTR_LEN(tmp) + 2);
  3826. }
  3827. if (PQputline(pgsql, query)==EOF) {
  3828. efree(query);
  3829. zend_string_release(tmp);
  3830. PHP_PQ_ERROR("copy failed: %s", pgsql);
  3831. RETURN_FALSE;
  3832. }
  3833. efree(query);
  3834. zend_string_release(tmp);
  3835. } ZEND_HASH_FOREACH_END();
  3836. if (PQputline(pgsql, "\\.\n") == EOF) {
  3837. PHP_PQ_ERROR("putline failed: %s", pgsql);
  3838. RETURN_FALSE;
  3839. }
  3840. if (PQendcopy(pgsql)) {
  3841. PHP_PQ_ERROR("endcopy failed: %s", pgsql);
  3842. RETURN_FALSE;
  3843. }
  3844. #endif
  3845. while ((pgsql_result = PQgetResult(pgsql))) {
  3846. if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
  3847. PHP_PQ_ERROR("Copy command failed: %s", pgsql);
  3848. command_failed = 1;
  3849. }
  3850. PQclear(pgsql_result);
  3851. }
  3852. if (command_failed) {
  3853. RETURN_FALSE;
  3854. }
  3855. } else {
  3856. PQclear(pgsql_result);
  3857. RETURN_FALSE;
  3858. }
  3859. RETURN_TRUE;
  3860. break;
  3861. default:
  3862. PQclear(pgsql_result);
  3863. PHP_PQ_ERROR("Copy command failed: %s", pgsql);
  3864. RETURN_FALSE;
  3865. break;
  3866. }
  3867. }
  3868. /* }}} */
  3869. #ifdef HAVE_PQESCAPE
  3870. /* {{{ proto string pg_escape_string([resource connection,] string data)
  3871. Escape string for text/char type */
  3872. PHP_FUNCTION(pg_escape_string)
  3873. {
  3874. zend_string *from = NULL, *to = NULL;
  3875. zval *pgsql_link;
  3876. zend_resource *link;
  3877. #ifdef HAVE_PQESCAPE_CONN
  3878. PGconn *pgsql;
  3879. #endif
  3880. switch (ZEND_NUM_ARGS()) {
  3881. case 1:
  3882. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
  3883. RETURN_THROWS();
  3884. }
  3885. link = FETCH_DEFAULT_LINK();
  3886. break;
  3887. default:
  3888. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &pgsql_link, &from) == FAILURE) {
  3889. RETURN_THROWS();
  3890. }
  3891. link = Z_RES_P(pgsql_link);
  3892. break;
  3893. }
  3894. to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
  3895. #ifdef HAVE_PQESCAPE_CONN
  3896. if (link) {
  3897. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3898. RETURN_THROWS();
  3899. }
  3900. ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
  3901. } else
  3902. #endif
  3903. {
  3904. ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
  3905. }
  3906. to = zend_string_truncate(to, ZSTR_LEN(to), 0);
  3907. RETURN_NEW_STR(to);
  3908. }
  3909. /* }}} */
  3910. /* {{{ proto string pg_escape_bytea([resource connection,] string data)
  3911. Escape binary for bytea type */
  3912. PHP_FUNCTION(pg_escape_bytea)
  3913. {
  3914. char *from = NULL, *to = NULL;
  3915. size_t to_len;
  3916. size_t from_len;
  3917. #ifdef HAVE_PQESCAPE_BYTEA_CONN
  3918. PGconn *pgsql;
  3919. #endif
  3920. zval *pgsql_link;
  3921. zend_resource *link;
  3922. switch (ZEND_NUM_ARGS()) {
  3923. case 1:
  3924. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
  3925. RETURN_THROWS();
  3926. }
  3927. link = FETCH_DEFAULT_LINK();
  3928. break;
  3929. default:
  3930. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &from, &from_len) == FAILURE) {
  3931. RETURN_THROWS();
  3932. }
  3933. link = Z_RES_P(pgsql_link);
  3934. break;
  3935. }
  3936. #ifdef HAVE_PQESCAPE_BYTEA_CONN
  3937. if (link) {
  3938. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  3939. RETURN_THROWS();
  3940. }
  3941. to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
  3942. } else
  3943. #endif
  3944. to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
  3945. RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
  3946. PQfreemem(to);
  3947. }
  3948. /* }}} */
  3949. #if !HAVE_PQUNESCAPEBYTEA
  3950. /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
  3951. Renamed to php_pgsql_unescape_bytea() */
  3952. /*
  3953. * PQunescapeBytea - converts the null terminated string representation
  3954. * of a bytea, strtext, into binary, filling a buffer. It returns a
  3955. * pointer to the buffer which is NULL on error, and the size of the
  3956. * buffer in retbuflen. The pointer may subsequently be used as an
  3957. * argument to the function free(3). It is the reverse of PQescapeBytea.
  3958. *
  3959. * The following transformations are reversed:
  3960. * '\0' == ASCII 0 == \000
  3961. * '\'' == ASCII 39 == \'
  3962. * '\\' == ASCII 92 == \\
  3963. *
  3964. * States:
  3965. * 0 normal 0->1->2->3->4
  3966. * 1 \ 1->5
  3967. * 2 \0 1->6
  3968. * 3 \00
  3969. * 4 \000
  3970. * 5 \'
  3971. * 6 \\
  3972. */
  3973. static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen) /* {{{ */
  3974. {
  3975. size_t buflen;
  3976. unsigned char *buffer,
  3977. *sp,
  3978. *bp;
  3979. unsigned int state = 0;
  3980. if (strtext == NULL)
  3981. return NULL;
  3982. buflen = strlen(strtext); /* will shrink, also we discover if
  3983. * strtext */
  3984. buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */
  3985. for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
  3986. {
  3987. switch (state)
  3988. {
  3989. case 0:
  3990. if (*sp == '\\')
  3991. state = 1;
  3992. *bp = *sp;
  3993. break;
  3994. case 1:
  3995. if (*sp == '\'') /* state=5 */
  3996. { /* replace \' with 39 */
  3997. bp--;
  3998. *bp = '\'';
  3999. buflen--;
  4000. state = 0;
  4001. }
  4002. else if (*sp == '\\') /* state=6 */
  4003. { /* replace \\ with 92 */
  4004. bp--;
  4005. *bp = '\\';
  4006. buflen--;
  4007. state = 0;
  4008. }
  4009. else
  4010. {
  4011. if (isdigit(*sp))
  4012. state = 2;
  4013. else
  4014. state = 0;
  4015. *bp = *sp;
  4016. }
  4017. break;
  4018. case 2:
  4019. if (isdigit(*sp))
  4020. state = 3;
  4021. else
  4022. state = 0;
  4023. *bp = *sp;
  4024. break;
  4025. case 3:
  4026. if (isdigit(*sp)) /* state=4 */
  4027. {
  4028. unsigned char *start, *end, buf[4]; /* 000 + '\0' */
  4029. bp -= 3;
  4030. memcpy(buf, sp-2, 3);
  4031. buf[3] = '\0';
  4032. start = buf;
  4033. *bp = (unsigned char)strtoul(start, (char **)&end, 8);
  4034. buflen -= 3;
  4035. state = 0;
  4036. }
  4037. else
  4038. {
  4039. *bp = *sp;
  4040. state = 0;
  4041. }
  4042. break;
  4043. }
  4044. }
  4045. buffer = erealloc(buffer, buflen+1);
  4046. buffer[buflen] = '\0';
  4047. *retbuflen = buflen;
  4048. return buffer;
  4049. }
  4050. /* }}} */
  4051. #endif
  4052. /* {{{ proto string pg_unescape_bytea(string data)
  4053. Unescape binary for bytea type */
  4054. PHP_FUNCTION(pg_unescape_bytea)
  4055. {
  4056. char *from = NULL, *to = NULL, *tmp = NULL;
  4057. size_t to_len;
  4058. size_t from_len;
  4059. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
  4060. &from, &from_len) == FAILURE) {
  4061. RETURN_THROWS();
  4062. }
  4063. #if HAVE_PQUNESCAPEBYTEA
  4064. tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
  4065. to = estrndup(tmp, to_len);
  4066. PQfreemem(tmp);
  4067. #else
  4068. to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
  4069. #endif
  4070. if (!to) {
  4071. php_error_docref(NULL, E_WARNING,"Invalid parameter");
  4072. RETURN_FALSE;
  4073. }
  4074. RETVAL_STRINGL(to, to_len);
  4075. efree(to);
  4076. }
  4077. /* }}} */
  4078. #endif
  4079. #ifdef HAVE_PQESCAPE
  4080. static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) /* {{{ */ {
  4081. char *from = NULL;
  4082. zval *pgsql_link = NULL;
  4083. PGconn *pgsql;
  4084. size_t from_len;
  4085. char *tmp;
  4086. zend_resource *link;
  4087. switch (ZEND_NUM_ARGS()) {
  4088. case 1:
  4089. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
  4090. RETURN_THROWS();
  4091. }
  4092. link = FETCH_DEFAULT_LINK();
  4093. CHECK_DEFAULT_LINK(link);
  4094. break;
  4095. default:
  4096. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &from, &from_len) == FAILURE) {
  4097. RETURN_THROWS();
  4098. }
  4099. link = Z_RES_P(pgsql_link);
  4100. break;
  4101. }
  4102. if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
  4103. RETURN_THROWS();
  4104. }
  4105. if (pgsql == NULL) {
  4106. php_error_docref(NULL, E_WARNING,"Cannot get pgsql link");
  4107. RETURN_FALSE;
  4108. }
  4109. if (escape_literal) {
  4110. tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len);
  4111. } else {
  4112. tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len);
  4113. }
  4114. if (!tmp) {
  4115. php_error_docref(NULL, E_WARNING,"Failed to escape");
  4116. RETURN_FALSE;
  4117. }
  4118. RETVAL_STRING(tmp);
  4119. PGSQLfree(tmp);
  4120. }
  4121. /* }}} */
  4122. /* {{{ proto string pg_escape_literal([resource connection,] string data)
  4123. Escape parameter as string literal (i.e. parameter) */
  4124. PHP_FUNCTION(pg_escape_literal)
  4125. {
  4126. php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  4127. }
  4128. /* }}} */
  4129. /* {{{ proto string pg_escape_identifier([resource connection,] string data)
  4130. Escape identifier (i.e. table name, field name) */
  4131. PHP_FUNCTION(pg_escape_identifier)
  4132. {
  4133. php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  4134. }
  4135. /* }}} */
  4136. #endif
  4137. /* {{{ proto string pg_result_error(resource result)
  4138. Get error message associated with result */
  4139. PHP_FUNCTION(pg_result_error)
  4140. {
  4141. zval *result;
  4142. PGresult *pgsql_result;
  4143. pgsql_result_handle *pg_result;
  4144. char *err = NULL;
  4145. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
  4146. &result) == FAILURE) {
  4147. RETURN_FALSE;
  4148. }
  4149. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  4150. RETURN_THROWS();
  4151. }
  4152. pgsql_result = pg_result->result;
  4153. if (!pgsql_result) {
  4154. RETURN_FALSE;
  4155. }
  4156. err = (char *)PQresultErrorMessage(pgsql_result);
  4157. RETURN_STRING(err);
  4158. }
  4159. /* }}} */
  4160. #if HAVE_PQRESULTERRORFIELD
  4161. /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
  4162. Get error message field associated with result */
  4163. PHP_FUNCTION(pg_result_error_field)
  4164. {
  4165. zval *result;
  4166. zend_long fieldcode;
  4167. PGresult *pgsql_result;
  4168. pgsql_result_handle *pg_result;
  4169. char *field = NULL;
  4170. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "rl",
  4171. &result, &fieldcode) == FAILURE) {
  4172. RETURN_FALSE;
  4173. }
  4174. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  4175. RETURN_THROWS();
  4176. }
  4177. pgsql_result = pg_result->result;
  4178. if (!pgsql_result) {
  4179. RETURN_FALSE;
  4180. }
  4181. if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
  4182. |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
  4183. #if PG_DIAG_INTERNAL_POSITION
  4184. |PG_DIAG_INTERNAL_POSITION
  4185. #endif
  4186. #if PG_DIAG_INTERNAL_QUERY
  4187. |PG_DIAG_INTERNAL_QUERY
  4188. #endif
  4189. |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
  4190. |PG_DIAG_SOURCE_FUNCTION)) {
  4191. field = (char *)PQresultErrorField(pgsql_result, (int)fieldcode);
  4192. if (field == NULL) {
  4193. RETURN_NULL();
  4194. } else {
  4195. RETURN_STRING(field);
  4196. }
  4197. } else {
  4198. RETURN_FALSE;
  4199. }
  4200. }
  4201. /* }}} */
  4202. #endif
  4203. /* {{{ proto int pg_connection_status(resource connection)
  4204. Get connection status */
  4205. PHP_FUNCTION(pg_connection_status)
  4206. {
  4207. zval *pgsql_link = NULL;
  4208. PGconn *pgsql;
  4209. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
  4210. &pgsql_link) == FAILURE) {
  4211. RETURN_FALSE;
  4212. }
  4213. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4214. RETURN_THROWS();
  4215. }
  4216. RETURN_LONG(PQstatus(pgsql));
  4217. }
  4218. /* }}} */
  4219. #if HAVE_PGTRANSACTIONSTATUS
  4220. /* {{{ proto int pg_transaction_status(resource connection)
  4221. Get transaction status */
  4222. PHP_FUNCTION(pg_transaction_status)
  4223. {
  4224. zval *pgsql_link = NULL;
  4225. PGconn *pgsql;
  4226. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
  4227. &pgsql_link) == FAILURE) {
  4228. RETURN_FALSE;
  4229. }
  4230. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4231. RETURN_THROWS();
  4232. }
  4233. RETURN_LONG(PQtransactionStatus(pgsql));
  4234. }
  4235. #endif
  4236. /* }}} */
  4237. /* {{{ proto bool pg_connection_reset(resource connection)
  4238. Reset connection (reconnect) */
  4239. PHP_FUNCTION(pg_connection_reset)
  4240. {
  4241. zval *pgsql_link;
  4242. PGconn *pgsql;
  4243. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
  4244. &pgsql_link) == FAILURE) {
  4245. RETURN_FALSE;
  4246. }
  4247. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4248. RETURN_THROWS();
  4249. }
  4250. PQreset(pgsql);
  4251. if (PQstatus(pgsql) == CONNECTION_BAD) {
  4252. RETURN_FALSE;
  4253. }
  4254. RETURN_TRUE;
  4255. }
  4256. /* }}} */
  4257. #define PHP_PG_ASYNC_IS_BUSY 1
  4258. #define PHP_PG_ASYNC_REQUEST_CANCEL 2
  4259. /* {{{ php_pgsql_flush_query
  4260. */
  4261. static int php_pgsql_flush_query(PGconn *pgsql)
  4262. {
  4263. PGresult *res;
  4264. int leftover = 0;
  4265. if (PQ_SETNONBLOCKING(pgsql, 1)) {
  4266. php_error_docref(NULL, E_NOTICE,"Cannot set connection to nonblocking mode");
  4267. return -1;
  4268. }
  4269. while ((res = PQgetResult(pgsql))) {
  4270. PQclear(res);
  4271. leftover++;
  4272. }
  4273. PQ_SETNONBLOCKING(pgsql, 0);
  4274. return leftover;
  4275. }
  4276. /* }}} */
  4277. /* {{{ php_pgsql_do_async
  4278. */
  4279. static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  4280. {
  4281. zval *pgsql_link;
  4282. PGconn *pgsql;
  4283. PGresult *pgsql_result;
  4284. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
  4285. &pgsql_link) == FAILURE) {
  4286. RETURN_FALSE;
  4287. }
  4288. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4289. RETURN_THROWS();
  4290. }
  4291. if (PQ_SETNONBLOCKING(pgsql, 1)) {
  4292. php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
  4293. RETURN_FALSE;
  4294. }
  4295. switch(entry_type) {
  4296. case PHP_PG_ASYNC_IS_BUSY:
  4297. PQconsumeInput(pgsql);
  4298. RETVAL_LONG(PQisBusy(pgsql));
  4299. break;
  4300. case PHP_PG_ASYNC_REQUEST_CANCEL:
  4301. RETVAL_LONG(PQrequestCancel(pgsql));
  4302. while ((pgsql_result = PQgetResult(pgsql))) {
  4303. PQclear(pgsql_result);
  4304. }
  4305. break;
  4306. default:
  4307. php_error_docref(NULL, E_ERROR, "PostgreSQL module error, please report this error");
  4308. break;
  4309. }
  4310. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  4311. php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
  4312. }
  4313. convert_to_boolean_ex(return_value);
  4314. }
  4315. /* }}} */
  4316. /* {{{ proto bool pg_cancel_query(resource connection)
  4317. Cancel request */
  4318. PHP_FUNCTION(pg_cancel_query)
  4319. {
  4320. php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
  4321. }
  4322. /* }}} */
  4323. /* {{{ proto bool pg_connection_busy(resource connection)
  4324. Get connection is busy or not */
  4325. PHP_FUNCTION(pg_connection_busy)
  4326. {
  4327. php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
  4328. }
  4329. /* }}} */
  4330. static int _php_pgsql_link_has_results(PGconn *pgsql) /* {{{ */
  4331. {
  4332. PGresult *result;
  4333. while ((result = PQgetResult(pgsql))) {
  4334. PQclear(result);
  4335. return 1;
  4336. }
  4337. return 0;
  4338. }
  4339. /* }}} */
  4340. /* {{{ proto bool pg_send_query(resource connection, string query)
  4341. Send asynchronous query */
  4342. PHP_FUNCTION(pg_send_query)
  4343. {
  4344. zval *pgsql_link;
  4345. char *query;
  4346. size_t len;
  4347. PGconn *pgsql;
  4348. int is_non_blocking;
  4349. int ret;
  4350. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &query, &len) == FAILURE) {
  4351. RETURN_THROWS();
  4352. }
  4353. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4354. RETURN_THROWS();
  4355. }
  4356. is_non_blocking = PQisnonblocking(pgsql);
  4357. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4358. php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
  4359. RETURN_FALSE;
  4360. }
  4361. if (_php_pgsql_link_has_results(pgsql)) {
  4362. php_error_docref(NULL, E_NOTICE,
  4363. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4364. }
  4365. if (is_non_blocking) {
  4366. if (!PQsendQuery(pgsql, query)) {
  4367. RETURN_FALSE;
  4368. }
  4369. ret = PQflush(pgsql);
  4370. } else {
  4371. if (!PQsendQuery(pgsql, query)) {
  4372. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4373. PQreset(pgsql);
  4374. }
  4375. if (!PQsendQuery(pgsql, query)) {
  4376. RETURN_FALSE;
  4377. }
  4378. }
  4379. /* Wait to finish sending buffer */
  4380. while ((ret = PQflush(pgsql))) {
  4381. if (ret == -1) {
  4382. php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4383. break;
  4384. }
  4385. usleep(10000);
  4386. }
  4387. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  4388. php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
  4389. }
  4390. }
  4391. if (ret == 0) {
  4392. RETURN_TRUE;
  4393. } else if (ret == -1) {
  4394. RETURN_FALSE;
  4395. } else {
  4396. RETURN_LONG(0);
  4397. }
  4398. }
  4399. /* }}} */
  4400. #if HAVE_PQSENDQUERYPARAMS
  4401. /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
  4402. Send asynchronous parameterized query */
  4403. PHP_FUNCTION(pg_send_query_params)
  4404. {
  4405. zval *pgsql_link, *pv_param_arr, *tmp;
  4406. int num_params = 0;
  4407. char **params = NULL;
  4408. char *query;
  4409. size_t query_len;
  4410. PGconn *pgsql;
  4411. int is_non_blocking;
  4412. int ret;
  4413. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
  4414. RETURN_THROWS();
  4415. }
  4416. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4417. RETURN_THROWS();
  4418. }
  4419. is_non_blocking = PQisnonblocking(pgsql);
  4420. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4421. php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
  4422. RETURN_FALSE;
  4423. }
  4424. if (_php_pgsql_link_has_results(pgsql)) {
  4425. php_error_docref(NULL, E_NOTICE,
  4426. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4427. }
  4428. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  4429. if (num_params > 0) {
  4430. int i = 0;
  4431. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  4432. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
  4433. if (Z_TYPE_P(tmp) == IS_NULL) {
  4434. params[i] = NULL;
  4435. } else {
  4436. zend_string *tmp_str;
  4437. zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
  4438. params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
  4439. zend_tmp_string_release(tmp_str);
  4440. }
  4441. i++;
  4442. } ZEND_HASH_FOREACH_END();
  4443. }
  4444. if (PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
  4445. _php_pgsql_free_params(params, num_params);
  4446. } else if (is_non_blocking) {
  4447. _php_pgsql_free_params(params, num_params);
  4448. RETURN_FALSE;
  4449. } else {
  4450. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4451. PQreset(pgsql);
  4452. }
  4453. if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
  4454. _php_pgsql_free_params(params, num_params);
  4455. RETURN_FALSE;
  4456. }
  4457. }
  4458. if (is_non_blocking) {
  4459. ret = PQflush(pgsql);
  4460. } else {
  4461. /* Wait to finish sending buffer */
  4462. while ((ret = PQflush(pgsql))) {
  4463. if (ret == -1) {
  4464. php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4465. break;
  4466. }
  4467. usleep(10000);
  4468. }
  4469. if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
  4470. php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
  4471. }
  4472. }
  4473. if (ret == 0) {
  4474. RETURN_TRUE;
  4475. } else if (ret == -1) {
  4476. RETURN_FALSE;
  4477. } else {
  4478. RETURN_LONG(0);
  4479. }
  4480. }
  4481. /* }}} */
  4482. #endif
  4483. #if HAVE_PQSENDPREPARE
  4484. /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
  4485. Asynchronously prepare a query for future execution */
  4486. PHP_FUNCTION(pg_send_prepare)
  4487. {
  4488. zval *pgsql_link;
  4489. char *query, *stmtname;
  4490. size_t stmtname_len, query_len;
  4491. PGconn *pgsql;
  4492. int is_non_blocking;
  4493. int ret;
  4494. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
  4495. RETURN_THROWS();
  4496. }
  4497. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4498. RETURN_THROWS();
  4499. }
  4500. is_non_blocking = PQisnonblocking(pgsql);
  4501. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4502. php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
  4503. RETURN_FALSE;
  4504. }
  4505. if (_php_pgsql_link_has_results(pgsql)) {
  4506. php_error_docref(NULL, E_NOTICE,
  4507. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4508. }
  4509. if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
  4510. if (is_non_blocking) {
  4511. RETURN_FALSE;
  4512. } else {
  4513. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4514. PQreset(pgsql);
  4515. }
  4516. if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
  4517. RETURN_FALSE;
  4518. }
  4519. }
  4520. }
  4521. if (is_non_blocking) {
  4522. ret = PQflush(pgsql);
  4523. } else {
  4524. /* Wait to finish sending buffer */
  4525. while ((ret = PQflush(pgsql))) {
  4526. if (ret == -1) {
  4527. php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4528. break;
  4529. }
  4530. usleep(10000);
  4531. }
  4532. if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
  4533. php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
  4534. }
  4535. }
  4536. if (ret == 0) {
  4537. RETURN_TRUE;
  4538. } else if (ret == -1) {
  4539. RETURN_FALSE;
  4540. } else {
  4541. RETURN_LONG(0);
  4542. }
  4543. }
  4544. /* }}} */
  4545. #endif
  4546. #if HAVE_PQSENDQUERYPREPARED
  4547. /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
  4548. Executes prevriously prepared stmtname asynchronously */
  4549. PHP_FUNCTION(pg_send_execute)
  4550. {
  4551. zval *pgsql_link;
  4552. zval *pv_param_arr, *tmp;
  4553. int num_params = 0;
  4554. char **params = NULL;
  4555. char *stmtname;
  4556. size_t stmtname_len;
  4557. PGconn *pgsql;
  4558. int is_non_blocking;
  4559. int ret;
  4560. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
  4561. RETURN_THROWS();
  4562. }
  4563. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4564. RETURN_THROWS();
  4565. }
  4566. is_non_blocking = PQisnonblocking(pgsql);
  4567. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4568. php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
  4569. RETURN_FALSE;
  4570. }
  4571. if (_php_pgsql_link_has_results(pgsql)) {
  4572. php_error_docref(NULL, E_NOTICE,
  4573. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4574. }
  4575. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  4576. if (num_params > 0) {
  4577. int i = 0;
  4578. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  4579. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
  4580. if (Z_TYPE_P(tmp) == IS_NULL) {
  4581. params[i] = NULL;
  4582. } else {
  4583. zend_string *tmp_str = zval_try_get_string(tmp);
  4584. if (UNEXPECTED(!tmp)) {
  4585. _php_pgsql_free_params(params, num_params);
  4586. return;
  4587. }
  4588. params[i] = estrndup(ZSTR_VAL(tmp_str), ZSTR_LEN(tmp_str));
  4589. zend_string_release(tmp_str);
  4590. }
  4591. i++;
  4592. } ZEND_HASH_FOREACH_END();
  4593. }
  4594. if (PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
  4595. _php_pgsql_free_params(params, num_params);
  4596. } else if (is_non_blocking) {
  4597. _php_pgsql_free_params(params, num_params);
  4598. RETURN_FALSE;
  4599. } else {
  4600. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4601. PQreset(pgsql);
  4602. }
  4603. if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
  4604. _php_pgsql_free_params(params, num_params);
  4605. RETURN_FALSE;
  4606. }
  4607. }
  4608. if (is_non_blocking) {
  4609. ret = PQflush(pgsql);
  4610. } else {
  4611. /* Wait to finish sending buffer */
  4612. while ((ret = PQflush(pgsql))) {
  4613. if (ret == -1) {
  4614. php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4615. break;
  4616. }
  4617. usleep(10000);
  4618. }
  4619. if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
  4620. php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
  4621. }
  4622. }
  4623. if (ret == 0) {
  4624. RETURN_TRUE;
  4625. } else if (ret == -1) {
  4626. RETURN_FALSE;
  4627. } else {
  4628. RETURN_LONG(0);
  4629. }
  4630. }
  4631. /* }}} */
  4632. #endif
  4633. /* {{{ proto resource pg_get_result(resource connection)
  4634. Get asynchronous query result */
  4635. PHP_FUNCTION(pg_get_result)
  4636. {
  4637. zval *pgsql_link;
  4638. PGconn *pgsql;
  4639. PGresult *pgsql_result;
  4640. pgsql_result_handle *pg_result;
  4641. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
  4642. RETURN_FALSE;
  4643. }
  4644. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4645. RETURN_THROWS();
  4646. }
  4647. pgsql_result = PQgetResult(pgsql);
  4648. if (!pgsql_result) {
  4649. /* no result */
  4650. RETURN_FALSE;
  4651. }
  4652. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  4653. pg_result->conn = pgsql;
  4654. pg_result->result = pgsql_result;
  4655. pg_result->row = 0;
  4656. RETURN_RES(zend_register_resource(pg_result, le_result));
  4657. }
  4658. /* }}} */
  4659. /* {{{ proto mixed pg_result_status(resource result[, int result_type])
  4660. Get status of query result */
  4661. PHP_FUNCTION(pg_result_status)
  4662. {
  4663. zval *result;
  4664. zend_long result_type = PGSQL_STATUS_LONG;
  4665. ExecStatusType status;
  4666. PGresult *pgsql_result;
  4667. pgsql_result_handle *pg_result;
  4668. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l",
  4669. &result, &result_type) == FAILURE) {
  4670. RETURN_FALSE;
  4671. }
  4672. if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
  4673. RETURN_THROWS();
  4674. }
  4675. pgsql_result = pg_result->result;
  4676. if (result_type == PGSQL_STATUS_LONG) {
  4677. status = PQresultStatus(pgsql_result);
  4678. RETURN_LONG((int)status);
  4679. }
  4680. else if (result_type == PGSQL_STATUS_STRING) {
  4681. RETURN_STRING(PQcmdStatus(pgsql_result));
  4682. }
  4683. else {
  4684. php_error_docref(NULL, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
  4685. RETURN_FALSE;
  4686. }
  4687. }
  4688. /* }}} */
  4689. /* {{{ proto mixed pg_get_notify([resource connection[, int result_type]])
  4690. Get asynchronous notification */
  4691. PHP_FUNCTION(pg_get_notify)
  4692. {
  4693. zval *pgsql_link;
  4694. zend_long result_type = PGSQL_ASSOC;
  4695. PGconn *pgsql;
  4696. PGnotify *pgsql_notify;
  4697. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l",
  4698. &pgsql_link, &result_type) == FAILURE) {
  4699. RETURN_FALSE;
  4700. }
  4701. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4702. RETURN_THROWS();
  4703. }
  4704. if (!(result_type & PGSQL_BOTH)) {
  4705. php_error_docref(NULL, E_WARNING, "Invalid result type");
  4706. RETURN_FALSE;
  4707. }
  4708. PQconsumeInput(pgsql);
  4709. pgsql_notify = PQnotifies(pgsql);
  4710. if (!pgsql_notify) {
  4711. /* no notify message */
  4712. RETURN_FALSE;
  4713. }
  4714. array_init(return_value);
  4715. if (result_type & PGSQL_NUM) {
  4716. add_index_string(return_value, 0, pgsql_notify->relname);
  4717. add_index_long(return_value, 1, pgsql_notify->be_pid);
  4718. #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
  4719. if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
  4720. #else
  4721. if (atof(PG_VERSION) >= 9.0) {
  4722. #endif
  4723. #if HAVE_PQPARAMETERSTATUS
  4724. add_index_string(return_value, 2, pgsql_notify->extra);
  4725. #endif
  4726. }
  4727. }
  4728. if (result_type & PGSQL_ASSOC) {
  4729. add_assoc_string(return_value, "message", pgsql_notify->relname);
  4730. add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
  4731. #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
  4732. if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
  4733. #else
  4734. if (atof(PG_VERSION) >= 9.0) {
  4735. #endif
  4736. #if HAVE_PQPARAMETERSTATUS
  4737. add_assoc_string(return_value, "payload", pgsql_notify->extra);
  4738. #endif
  4739. }
  4740. }
  4741. PQfreemem(pgsql_notify);
  4742. }
  4743. /* }}} */
  4744. /* {{{ proto int pg_get_pid([resource connection)
  4745. Get backend(server) pid */
  4746. PHP_FUNCTION(pg_get_pid)
  4747. {
  4748. zval *pgsql_link;
  4749. PGconn *pgsql;
  4750. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
  4751. &pgsql_link) == FAILURE) {
  4752. RETURN_FALSE;
  4753. }
  4754. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4755. RETURN_THROWS();
  4756. }
  4757. RETURN_LONG(PQbackendPID(pgsql));
  4758. }
  4759. /* }}} */
  4760. static ssize_t php_pgsql_fd_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
  4761. {
  4762. return -1;
  4763. }
  4764. /* }}} */
  4765. static ssize_t php_pgsql_fd_read(php_stream *stream, char *buf, size_t count) /* {{{ */
  4766. {
  4767. return -1;
  4768. }
  4769. /* }}} */
  4770. static int php_pgsql_fd_close(php_stream *stream, int close_handle) /* {{{ */
  4771. {
  4772. return EOF;
  4773. }
  4774. /* }}} */
  4775. static int php_pgsql_fd_flush(php_stream *stream) /* {{{ */
  4776. {
  4777. return FAILURE;
  4778. }
  4779. /* }}} */
  4780. static int php_pgsql_fd_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */
  4781. {
  4782. PGconn *pgsql = (PGconn *) stream->abstract;
  4783. switch (option) {
  4784. case PHP_STREAM_OPTION_BLOCKING:
  4785. return PQ_SETNONBLOCKING(pgsql, value);
  4786. default:
  4787. return FAILURE;
  4788. }
  4789. }
  4790. /* }}} */
  4791. static int php_pgsql_fd_cast(php_stream *stream, int cast_as, void **ret) /* {{{ */
  4792. {
  4793. PGconn *pgsql = (PGconn *) stream->abstract;
  4794. switch (cast_as) {
  4795. case PHP_STREAM_AS_FD_FOR_SELECT:
  4796. case PHP_STREAM_AS_FD:
  4797. case PHP_STREAM_AS_SOCKETD:
  4798. if (ret) {
  4799. int fd_number = PQsocket(pgsql);
  4800. if (fd_number == -1) {
  4801. return FAILURE;
  4802. }
  4803. *(php_socket_t *)ret = fd_number;
  4804. return SUCCESS;
  4805. }
  4806. default:
  4807. return FAILURE;
  4808. }
  4809. }
  4810. /* }}} */
  4811. /* {{{ proto resource pg_socket(resource connection)
  4812. Get a read-only handle to the socket underlying the pgsql connection */
  4813. PHP_FUNCTION(pg_socket)
  4814. {
  4815. zval *pgsql_link;
  4816. php_stream *stream;
  4817. PGconn *pgsql;
  4818. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
  4819. RETURN_THROWS();
  4820. }
  4821. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4822. RETURN_THROWS();
  4823. }
  4824. stream = php_stream_alloc(&php_stream_pgsql_fd_ops, pgsql, NULL, "r");
  4825. if (stream) {
  4826. php_stream_to_zval(stream, return_value);
  4827. return;
  4828. }
  4829. RETURN_FALSE;
  4830. }
  4831. /* }}} */
  4832. /* {{{ proto bool pg_consume_input(resource connection)
  4833. Reads input on the connection */
  4834. PHP_FUNCTION(pg_consume_input)
  4835. {
  4836. zval *pgsql_link;
  4837. PGconn *pgsql;
  4838. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
  4839. RETURN_THROWS();
  4840. }
  4841. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4842. RETURN_THROWS();
  4843. }
  4844. RETURN_BOOL(PQconsumeInput(pgsql));
  4845. }
  4846. /* }}} */
  4847. /* {{{ proto mixed pg_flush(resource connection)
  4848. Flush outbound query data on the connection */
  4849. PHP_FUNCTION(pg_flush)
  4850. {
  4851. zval *pgsql_link;
  4852. PGconn *pgsql;
  4853. int ret;
  4854. int is_non_blocking;
  4855. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
  4856. RETURN_THROWS();
  4857. }
  4858. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4859. RETURN_THROWS();
  4860. }
  4861. is_non_blocking = PQisnonblocking(pgsql);
  4862. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4863. php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
  4864. RETURN_FALSE;
  4865. }
  4866. ret = PQflush(pgsql);
  4867. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 0) == -1) {
  4868. php_error_docref(NULL, E_NOTICE, "Failed resetting connection to blocking mode");
  4869. }
  4870. switch (ret) {
  4871. case 0: RETURN_TRUE; break;
  4872. case 1: RETURN_LONG(0); break;
  4873. default: RETURN_FALSE;
  4874. }
  4875. }
  4876. /* }}} */
  4877. /* {{{ php_pgsql_meta_data
  4878. * TODO: Add meta_data cache for better performance
  4879. */
  4880. PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta, zend_bool extended)
  4881. {
  4882. PGresult *pg_result;
  4883. char *src, *tmp_name, *tmp_name2 = NULL;
  4884. char *escaped;
  4885. smart_str querystr = {0};
  4886. size_t new_len;
  4887. int i, num_rows;
  4888. zval elem;
  4889. if (!*table_name) {
  4890. php_error_docref(NULL, E_WARNING, "The table name must be specified");
  4891. return FAILURE;
  4892. }
  4893. src = estrdup(table_name);
  4894. tmp_name = php_strtok_r(src, ".", &tmp_name2);
  4895. if (!tmp_name) {
  4896. efree(src);
  4897. php_error_docref(NULL, E_WARNING, "The table name must be specified");
  4898. return FAILURE;
  4899. }
  4900. if (!tmp_name2 || !*tmp_name2) {
  4901. /* Default schema */
  4902. tmp_name2 = tmp_name;
  4903. tmp_name = "public";
  4904. }
  4905. if (extended) {
  4906. smart_str_appends(&querystr,
  4907. "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims, t.typtype, "
  4908. "d.description "
  4909. "FROM pg_class as c "
  4910. " JOIN pg_attribute a ON (a.attrelid = c.oid) "
  4911. " JOIN pg_type t ON (a.atttypid = t.oid) "
  4912. " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
  4913. " LEFT JOIN pg_description d ON (d.objoid=a.attrelid AND d.objsubid=a.attnum AND c.oid=d.objoid) "
  4914. "WHERE a.attnum > 0 AND c.relname = '");
  4915. } else {
  4916. smart_str_appends(&querystr,
  4917. "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype "
  4918. "FROM pg_class as c "
  4919. " JOIN pg_attribute a ON (a.attrelid = c.oid) "
  4920. " JOIN pg_type t ON (a.atttypid = t.oid) "
  4921. " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
  4922. "WHERE a.attnum > 0 AND c.relname = '");
  4923. }
  4924. escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
  4925. new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
  4926. if (new_len) {
  4927. smart_str_appendl(&querystr, escaped, new_len);
  4928. }
  4929. efree(escaped);
  4930. smart_str_appends(&querystr, "' AND n.nspname = '");
  4931. escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
  4932. new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
  4933. if (new_len) {
  4934. smart_str_appendl(&querystr, escaped, new_len);
  4935. }
  4936. efree(escaped);
  4937. smart_str_appends(&querystr, "' ORDER BY a.attnum;");
  4938. smart_str_0(&querystr);
  4939. efree(src);
  4940. pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
  4941. if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
  4942. php_error_docref(NULL, E_WARNING, "Table '%s' doesn't exists", table_name);
  4943. smart_str_free(&querystr);
  4944. PQclear(pg_result);
  4945. return FAILURE;
  4946. }
  4947. smart_str_free(&querystr);
  4948. for (i = 0; i < num_rows; i++) {
  4949. char *name;
  4950. array_init(&elem);
  4951. /* pg_attribute.attnum */
  4952. add_assoc_long_ex(&elem, "num", sizeof("num") - 1, atoi(PQgetvalue(pg_result, i, 1)));
  4953. /* pg_type.typname */
  4954. add_assoc_string_ex(&elem, "type", sizeof("type") - 1, PQgetvalue(pg_result, i, 2));
  4955. /* pg_attribute.attlen */
  4956. add_assoc_long_ex(&elem, "len", sizeof("len") - 1, atoi(PQgetvalue(pg_result,i,3)));
  4957. /* pg_attribute.attnonull */
  4958. add_assoc_bool_ex(&elem, "not null", sizeof("not null") - 1, !strcmp(PQgetvalue(pg_result, i, 4), "t"));
  4959. /* pg_attribute.atthasdef */
  4960. add_assoc_bool_ex(&elem, "has default", sizeof("has default") - 1, !strcmp(PQgetvalue(pg_result,i,5), "t"));
  4961. /* pg_attribute.attndims */
  4962. add_assoc_long_ex(&elem, "array dims", sizeof("array dims") - 1, atoi(PQgetvalue(pg_result, i, 6)));
  4963. /* pg_type.typtype */
  4964. add_assoc_bool_ex(&elem, "is enum", sizeof("is enum") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "e"));
  4965. if (extended) {
  4966. /* pg_type.typtype */
  4967. add_assoc_bool_ex(&elem, "is base", sizeof("is base") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "b"));
  4968. add_assoc_bool_ex(&elem, "is composite", sizeof("is composite") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "c"));
  4969. add_assoc_bool_ex(&elem, "is pesudo", sizeof("is pesudo") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "p"));
  4970. /* pg_description.description */
  4971. add_assoc_string_ex(&elem, "description", sizeof("description") - 1, PQgetvalue(pg_result, i, 8));
  4972. }
  4973. /* pg_attribute.attname */
  4974. name = PQgetvalue(pg_result,i,0);
  4975. add_assoc_zval(meta, name, &elem);
  4976. }
  4977. PQclear(pg_result);
  4978. return SUCCESS;
  4979. }
  4980. /* }}} */
  4981. /* {{{ proto array pg_meta_data(resource db, string table [, bool extended])
  4982. Get meta_data */
  4983. PHP_FUNCTION(pg_meta_data)
  4984. {
  4985. zval *pgsql_link;
  4986. char *table_name;
  4987. size_t table_name_len;
  4988. zend_bool extended=0;
  4989. PGconn *pgsql;
  4990. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|b",
  4991. &pgsql_link, &table_name, &table_name_len, &extended) == FAILURE) {
  4992. RETURN_THROWS();
  4993. }
  4994. if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  4995. RETURN_THROWS();
  4996. }
  4997. array_init(return_value);
  4998. if (php_pgsql_meta_data(pgsql, table_name, return_value, extended) == FAILURE) {
  4999. zend_array_destroy(Z_ARR_P(return_value)); /* destroy array */
  5000. RETURN_FALSE;
  5001. }
  5002. }
  5003. /* }}} */
  5004. /* {{{ php_pgsql_get_data_type
  5005. */
  5006. static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
  5007. {
  5008. /* This is stupid way to do. I'll fix it when I decied how to support
  5009. user defined types. (Yasuo) */
  5010. /* boolean */
  5011. if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
  5012. return PG_BOOL;
  5013. /* object id */
  5014. if (!strcmp(type_name, "oid"))
  5015. return PG_OID;
  5016. /* integer */
  5017. if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
  5018. return PG_INT2;
  5019. if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
  5020. return PG_INT4;
  5021. if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
  5022. return PG_INT8;
  5023. /* real and other */
  5024. if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
  5025. return PG_FLOAT4;
  5026. if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
  5027. return PG_FLOAT8;
  5028. if (!strcmp(type_name, "numeric"))
  5029. return PG_NUMERIC;
  5030. if (!strcmp(type_name, "money"))
  5031. return PG_MONEY;
  5032. /* character */
  5033. if (!strcmp(type_name, "text"))
  5034. return PG_TEXT;
  5035. if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
  5036. return PG_CHAR;
  5037. if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
  5038. return PG_VARCHAR;
  5039. /* time and interval */
  5040. if (!strcmp(type_name, "abstime"))
  5041. return PG_UNIX_TIME;
  5042. if (!strcmp(type_name, "reltime"))
  5043. return PG_UNIX_TIME_INTERVAL;
  5044. if (!strcmp(type_name, "tinterval"))
  5045. return PG_UNIX_TIME_INTERVAL;
  5046. if (!strcmp(type_name, "date"))
  5047. return PG_DATE;
  5048. if (!strcmp(type_name, "time"))
  5049. return PG_TIME;
  5050. if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
  5051. return PG_TIME_WITH_TIMEZONE;
  5052. if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
  5053. return PG_TIMESTAMP;
  5054. if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
  5055. return PG_TIMESTAMP_WITH_TIMEZONE;
  5056. if (!strcmp(type_name, "interval"))
  5057. return PG_INTERVAL;
  5058. /* binary */
  5059. if (!strcmp(type_name, "bytea"))
  5060. return PG_BYTEA;
  5061. /* network */
  5062. if (!strcmp(type_name, "cidr"))
  5063. return PG_CIDR;
  5064. if (!strcmp(type_name, "inet"))
  5065. return PG_INET;
  5066. if (!strcmp(type_name, "macaddr"))
  5067. return PG_MACADDR;
  5068. /* bit */
  5069. if (!strcmp(type_name, "bit"))
  5070. return PG_BIT;
  5071. if (!strcmp(type_name, "bit varying"))
  5072. return PG_VARBIT;
  5073. /* geometric */
  5074. if (!strcmp(type_name, "line"))
  5075. return PG_LINE;
  5076. if (!strcmp(type_name, "lseg"))
  5077. return PG_LSEG;
  5078. if (!strcmp(type_name, "box"))
  5079. return PG_BOX;
  5080. if (!strcmp(type_name, "path"))
  5081. return PG_PATH;
  5082. if (!strcmp(type_name, "point"))
  5083. return PG_POINT;
  5084. if (!strcmp(type_name, "polygon"))
  5085. return PG_POLYGON;
  5086. if (!strcmp(type_name, "circle"))
  5087. return PG_CIRCLE;
  5088. return PG_UNKNOWN;
  5089. }
  5090. /* }}} */
  5091. /* {{{ php_pgsql_convert_match
  5092. * test field value with regular expression specified.
  5093. */
  5094. static int php_pgsql_convert_match(const char *str, size_t str_len, const char *regex , size_t regex_len, int icase)
  5095. {
  5096. pcre2_code *re;
  5097. PCRE2_SIZE err_offset;
  5098. int res, errnumber;
  5099. uint32_t options = PCRE2_NO_AUTO_CAPTURE;
  5100. size_t i;
  5101. pcre2_match_data *match_data;
  5102. /* Check invalid chars for POSIX regex */
  5103. for (i = 0; i < str_len; i++) {
  5104. if (str[i] == '\n' ||
  5105. str[i] == '\r' ||
  5106. str[i] == '\0' ) {
  5107. return FAILURE;
  5108. }
  5109. }
  5110. if (icase) {
  5111. options |= PCRE2_CASELESS;
  5112. }
  5113. re = pcre2_compile((PCRE2_SPTR)regex, regex_len, options, &errnumber, &err_offset, php_pcre_cctx());
  5114. if (NULL == re) {
  5115. PCRE2_UCHAR err_msg[128];
  5116. pcre2_get_error_message(errnumber, err_msg, sizeof(err_msg));
  5117. php_error_docref(NULL, E_WARNING, "Cannot compile regex: '%s'", err_msg);
  5118. return FAILURE;
  5119. }
  5120. match_data = php_pcre_create_match_data(0, re);
  5121. if (NULL == match_data) {
  5122. pcre2_code_free(re);
  5123. php_error_docref(NULL, E_WARNING, "Cannot allocate match data");
  5124. return FAILURE;
  5125. }
  5126. res = pcre2_match(re, (PCRE2_SPTR)str, str_len, 0, 0, match_data, php_pcre_mctx());
  5127. php_pcre_free_match_data(match_data);
  5128. pcre2_code_free(re);
  5129. if (res == PCRE2_ERROR_NOMATCH) {
  5130. return FAILURE;
  5131. } else if (res < 0) {
  5132. php_error_docref(NULL, E_WARNING, "Cannot exec regex");
  5133. return FAILURE;
  5134. }
  5135. return SUCCESS;
  5136. }
  5137. /* }}} */
  5138. /* {{{ php_pgsql_add_quote
  5139. * add quotes around string.
  5140. */
  5141. static int php_pgsql_add_quotes(zval *src, zend_bool should_free)
  5142. {
  5143. smart_str str = {0};
  5144. assert(Z_TYPE_P(src) == IS_STRING);
  5145. assert(should_free == 1 || should_free == 0);
  5146. smart_str_appendc(&str, 'E');
  5147. smart_str_appendc(&str, '\'');
  5148. smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
  5149. smart_str_appendc(&str, '\'');
  5150. smart_str_0(&str);
  5151. if (should_free) {
  5152. zval_ptr_dtor(src);
  5153. }
  5154. ZVAL_NEW_STR(src, str.s);
  5155. return SUCCESS;
  5156. }
  5157. /* }}} */
  5158. #define PGSQL_CONV_CHECK_IGNORE() \
  5159. if (!err && Z_TYPE(new_val) == IS_STRING && !strcmp(Z_STRVAL(new_val), "NULL")) { \
  5160. /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
  5161. if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_TYPE_P(has_default) == IS_TRUE) { \
  5162. zval_ptr_dtor(&new_val); \
  5163. skip_field = 1; \
  5164. } \
  5165. /* raise error if it's not null and cannot be ignored */ \
  5166. else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_TYPE_P(not_null) == IS_TRUE) { \
  5167. php_error_docref(NULL, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", ZSTR_VAL(field)); \
  5168. err = 1; \
  5169. } \
  5170. }
  5171. /* {{{ php_pgsql_convert
  5172. * check and convert array values (fieldname=>value pair) for sql
  5173. */
  5174. PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, zend_ulong opt)
  5175. {
  5176. zend_string *field = NULL;
  5177. zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
  5178. int err = 0, skip_field;
  5179. php_pgsql_data_type data_type;
  5180. assert(pg_link != NULL);
  5181. assert(Z_TYPE_P(values) == IS_ARRAY);
  5182. assert(Z_TYPE_P(result) == IS_ARRAY);
  5183. assert(!(opt & ~PGSQL_CONV_OPTS));
  5184. if (!table_name) {
  5185. return FAILURE;
  5186. }
  5187. array_init(&meta);
  5188. /* table_name is escaped by php_pgsql_meta_data */
  5189. if (php_pgsql_meta_data(pg_link, table_name, &meta, 0) == FAILURE) {
  5190. zval_ptr_dtor(&meta);
  5191. return FAILURE;
  5192. }
  5193. ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(values), field, val) {
  5194. skip_field = 0;
  5195. ZVAL_NULL(&new_val);
  5196. if (!err && field == NULL) {
  5197. php_error_docref(NULL, E_WARNING, "Accepts only string key for values");
  5198. err = 1;
  5199. }
  5200. if (!err && (def = zend_hash_find(Z_ARRVAL(meta), field)) == NULL) {
  5201. php_error_docref(NULL, E_NOTICE, "Invalid field name (%s) in values", ZSTR_VAL(field));
  5202. err = 1;
  5203. }
  5204. if (!err && (type = zend_hash_str_find(Z_ARRVAL_P(def), "type", sizeof("type") - 1)) == NULL) {
  5205. php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'type'");
  5206. err = 1;
  5207. }
  5208. if (!err && (not_null = zend_hash_str_find(Z_ARRVAL_P(def), "not null", sizeof("not null") - 1)) == NULL) {
  5209. php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'not null'");
  5210. err = 1;
  5211. }
  5212. if (!err && (has_default = zend_hash_str_find(Z_ARRVAL_P(def), "has default", sizeof("has default") - 1)) == NULL) {
  5213. php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'has default'");
  5214. err = 1;
  5215. }
  5216. if (!err && (is_enum = zend_hash_str_find(Z_ARRVAL_P(def), "is enum", sizeof("is enum") - 1)) == NULL) {
  5217. php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'is enum'");
  5218. err = 1;
  5219. }
  5220. if (!err && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT)) {
  5221. php_error_docref(NULL, E_NOTICE, "Expects scalar values as field values");
  5222. err = 1;
  5223. }
  5224. if (err) {
  5225. break; /* break out for() */
  5226. }
  5227. convert_to_boolean(is_enum);
  5228. if (Z_TYPE_P(is_enum) == IS_TRUE) {
  5229. /* enums need to be treated like strings */
  5230. data_type = PG_TEXT;
  5231. } else {
  5232. data_type = php_pgsql_get_data_type(Z_STRVAL_P(type), Z_STRLEN_P(type));
  5233. }
  5234. switch(data_type)
  5235. {
  5236. case PG_BOOL:
  5237. switch (Z_TYPE_P(val)) {
  5238. case IS_STRING:
  5239. if (Z_STRLEN_P(val) == 0) {
  5240. ZVAL_STRING(&new_val, "NULL");
  5241. }
  5242. else {
  5243. if (!strcmp(Z_STRVAL_P(val), "t") || !strcmp(Z_STRVAL_P(val), "T") ||
  5244. !strcmp(Z_STRVAL_P(val), "y") || !strcmp(Z_STRVAL_P(val), "Y") ||
  5245. !strcmp(Z_STRVAL_P(val), "true") || !strcmp(Z_STRVAL_P(val), "True") ||
  5246. !strcmp(Z_STRVAL_P(val), "yes") || !strcmp(Z_STRVAL_P(val), "Yes") ||
  5247. !strcmp(Z_STRVAL_P(val), "1")) {
  5248. ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
  5249. }
  5250. else if (!strcmp(Z_STRVAL_P(val), "f") || !strcmp(Z_STRVAL_P(val), "F") ||
  5251. !strcmp(Z_STRVAL_P(val), "n") || !strcmp(Z_STRVAL_P(val), "N") ||
  5252. !strcmp(Z_STRVAL_P(val), "false") || !strcmp(Z_STRVAL_P(val), "False") ||
  5253. !strcmp(Z_STRVAL_P(val), "no") || !strcmp(Z_STRVAL_P(val), "No") ||
  5254. !strcmp(Z_STRVAL_P(val), "0")) {
  5255. ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
  5256. }
  5257. else {
  5258. php_error_docref(NULL, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
  5259. err = 1;
  5260. }
  5261. }
  5262. break;
  5263. case IS_LONG:
  5264. if (Z_LVAL_P(val)) {
  5265. ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
  5266. }
  5267. else {
  5268. ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
  5269. }
  5270. break;
  5271. case IS_TRUE:
  5272. ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
  5273. break;
  5274. case IS_FALSE:
  5275. ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
  5276. break;
  5277. case IS_NULL:
  5278. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5279. break;
  5280. default:
  5281. err = 1;
  5282. }
  5283. PGSQL_CONV_CHECK_IGNORE();
  5284. if (err) {
  5285. php_error_docref(NULL, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5286. }
  5287. break;
  5288. case PG_OID:
  5289. case PG_INT2:
  5290. case PG_INT4:
  5291. case PG_INT8:
  5292. switch (Z_TYPE_P(val)) {
  5293. case IS_STRING:
  5294. if (Z_STRLEN_P(val) == 0) {
  5295. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5296. }
  5297. else {
  5298. /* FIXME: better regex must be used */
  5299. #define REGEX0 "^([+-]{0,1}[0-9]+)$"
  5300. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE) {
  5301. err = 1;
  5302. }
  5303. else {
  5304. ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5305. }
  5306. #undef REGEX0
  5307. }
  5308. break;
  5309. case IS_DOUBLE:
  5310. ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
  5311. convert_to_long_ex(&new_val);
  5312. break;
  5313. case IS_LONG:
  5314. ZVAL_LONG(&new_val, Z_LVAL_P(val));
  5315. break;
  5316. case IS_NULL:
  5317. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5318. break;
  5319. default:
  5320. err = 1;
  5321. }
  5322. PGSQL_CONV_CHECK_IGNORE();
  5323. if (err) {
  5324. php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5325. }
  5326. break;
  5327. case PG_NUMERIC:
  5328. case PG_MONEY:
  5329. case PG_FLOAT4:
  5330. case PG_FLOAT8:
  5331. switch (Z_TYPE_P(val)) {
  5332. case IS_STRING:
  5333. if (Z_STRLEN_P(val) == 0) {
  5334. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5335. }
  5336. else {
  5337. #define REGEX0 "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"
  5338. #define REGEX1 "^[+-]{0,1}(inf)(inity){0,1}$"
  5339. /* better regex? */
  5340. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE) {
  5341. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX1, sizeof(REGEX1)-1, 1) == FAILURE) {
  5342. err = 1;
  5343. } else {
  5344. ZVAL_STRING(&new_val, Z_STRVAL_P(val));
  5345. php_pgsql_add_quotes(&new_val, 1);
  5346. }
  5347. }
  5348. else {
  5349. ZVAL_STRING(&new_val, Z_STRVAL_P(val));
  5350. }
  5351. #undef REGEX0
  5352. #undef REGEX1
  5353. }
  5354. break;
  5355. case IS_LONG:
  5356. ZVAL_LONG(&new_val, Z_LVAL_P(val));
  5357. break;
  5358. case IS_DOUBLE:
  5359. ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
  5360. break;
  5361. case IS_NULL:
  5362. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5363. break;
  5364. default:
  5365. err = 1;
  5366. }
  5367. PGSQL_CONV_CHECK_IGNORE();
  5368. if (err) {
  5369. php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5370. }
  5371. break;
  5372. /* Exotic types are handled as string also.
  5373. Please feel free to add more valitions. Invalid query fails
  5374. at execution anyway. */
  5375. case PG_TEXT:
  5376. case PG_CHAR:
  5377. case PG_VARCHAR:
  5378. /* bit */
  5379. case PG_BIT:
  5380. case PG_VARBIT:
  5381. /* geometric */
  5382. case PG_LINE:
  5383. case PG_LSEG:
  5384. case PG_POINT:
  5385. case PG_BOX:
  5386. case PG_PATH:
  5387. case PG_POLYGON:
  5388. case PG_CIRCLE:
  5389. /* unknown. JSON, Array etc */
  5390. case PG_UNKNOWN:
  5391. switch (Z_TYPE_P(val)) {
  5392. case IS_STRING:
  5393. if (Z_STRLEN_P(val) == 0) {
  5394. if (opt & PGSQL_CONV_FORCE_NULL) {
  5395. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5396. } else {
  5397. ZVAL_STRINGL(&new_val, "''", sizeof("''")-1);
  5398. }
  5399. }
  5400. else {
  5401. zend_string *str;
  5402. /* PostgreSQL ignores \0 */
  5403. str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
  5404. /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
  5405. ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
  5406. str = zend_string_truncate(str, ZSTR_LEN(str), 0);
  5407. ZVAL_NEW_STR(&new_val, str);
  5408. php_pgsql_add_quotes(&new_val, 1);
  5409. }
  5410. break;
  5411. case IS_LONG:
  5412. ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val)));
  5413. break;
  5414. case IS_DOUBLE:
  5415. ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
  5416. convert_to_string_ex(&new_val);
  5417. break;
  5418. case IS_NULL:
  5419. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5420. break;
  5421. default:
  5422. err = 1;
  5423. }
  5424. PGSQL_CONV_CHECK_IGNORE();
  5425. if (err) {
  5426. php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5427. }
  5428. break;
  5429. case PG_UNIX_TIME:
  5430. case PG_UNIX_TIME_INTERVAL:
  5431. /* these are the actallay a integer */
  5432. switch (Z_TYPE_P(val)) {
  5433. case IS_STRING:
  5434. if (Z_STRLEN_P(val) == 0) {
  5435. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5436. }
  5437. else {
  5438. /* better regex? */
  5439. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^[0-9]+$", sizeof("^[0-9]+$")-1, 0) == FAILURE) {
  5440. err = 1;
  5441. }
  5442. else {
  5443. ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5444. convert_to_long_ex(&new_val);
  5445. }
  5446. }
  5447. break;
  5448. case IS_DOUBLE:
  5449. ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
  5450. convert_to_long_ex(&new_val);
  5451. break;
  5452. case IS_LONG:
  5453. ZVAL_LONG(&new_val, Z_LVAL_P(val));
  5454. break;
  5455. case IS_NULL:
  5456. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5457. break;
  5458. default:
  5459. err = 1;
  5460. }
  5461. PGSQL_CONV_CHECK_IGNORE();
  5462. if (err) {
  5463. php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5464. }
  5465. break;
  5466. case PG_CIDR:
  5467. case PG_INET:
  5468. switch (Z_TYPE_P(val)) {
  5469. case IS_STRING:
  5470. if (Z_STRLEN_P(val) == 0) {
  5471. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5472. }
  5473. else {
  5474. #define REGEX0 "^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\\/[0-9]{1,3})?$"
  5475. #define REGEX1 "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\\/[0-9]{1,3})?$"
  5476. /* The inet type holds an IPv4 or IPv6 host address, and optionally its subnet, all in one field. See more in the doc.
  5477. The regex might still be not perfect, but catches the most of IP variants. We might decide to remove the regex
  5478. at all though and let the server side to handle it.*/
  5479. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE
  5480. && php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX1, sizeof(REGEX1)-1, 0) == FAILURE) {
  5481. err = 1;
  5482. }
  5483. else {
  5484. ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5485. php_pgsql_add_quotes(&new_val, 1);
  5486. }
  5487. #undef REGEX0
  5488. #undef REGEX1
  5489. }
  5490. break;
  5491. case IS_NULL:
  5492. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5493. break;
  5494. default:
  5495. err = 1;
  5496. }
  5497. PGSQL_CONV_CHECK_IGNORE();
  5498. if (err) {
  5499. php_error_docref(NULL, E_NOTICE, "Expects NULL or IPv4 or IPv6 address string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5500. }
  5501. break;
  5502. case PG_TIME_WITH_TIMEZONE:
  5503. case PG_TIMESTAMP:
  5504. case PG_TIMESTAMP_WITH_TIMEZONE:
  5505. switch(Z_TYPE_P(val)) {
  5506. case IS_STRING:
  5507. if (Z_STRLEN_P(val) == 0) {
  5508. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5509. } else if (!strcasecmp(Z_STRVAL_P(val), "now()")) {
  5510. ZVAL_STRINGL(&new_val, "NOW()", sizeof("NOW()")-1);
  5511. } else {
  5512. #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})(([ \\t]+|T)(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$"
  5513. /* better regex? */
  5514. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
  5515. err = 1;
  5516. } else {
  5517. ZVAL_STRING(&new_val, Z_STRVAL_P(val));
  5518. php_pgsql_add_quotes(&new_val, 1);
  5519. }
  5520. #undef REGEX0
  5521. }
  5522. break;
  5523. case IS_NULL:
  5524. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5525. break;
  5526. default:
  5527. err = 1;
  5528. }
  5529. PGSQL_CONV_CHECK_IGNORE();
  5530. if (err) {
  5531. php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5532. }
  5533. break;
  5534. case PG_DATE:
  5535. switch(Z_TYPE_P(val)) {
  5536. case IS_STRING:
  5537. if (Z_STRLEN_P(val) == 0) {
  5538. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5539. }
  5540. else {
  5541. #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$"
  5542. /* FIXME: better regex must be used */
  5543. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
  5544. err = 1;
  5545. }
  5546. else {
  5547. ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5548. php_pgsql_add_quotes(&new_val, 1);
  5549. }
  5550. #undef REGEX0
  5551. }
  5552. break;
  5553. case IS_NULL:
  5554. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5555. break;
  5556. default:
  5557. err = 1;
  5558. }
  5559. PGSQL_CONV_CHECK_IGNORE();
  5560. if (err) {
  5561. php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5562. }
  5563. break;
  5564. case PG_TIME:
  5565. switch(Z_TYPE_P(val)) {
  5566. case IS_STRING:
  5567. if (Z_STRLEN_P(val) == 0) {
  5568. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5569. }
  5570. else {
  5571. #define REGEX0 "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}){0,1}$"
  5572. /* FIXME: better regex must be used */
  5573. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
  5574. err = 1;
  5575. }
  5576. else {
  5577. ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5578. php_pgsql_add_quotes(&new_val, 1);
  5579. }
  5580. #undef REGEX0
  5581. }
  5582. break;
  5583. case IS_NULL:
  5584. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5585. break;
  5586. default:
  5587. err = 1;
  5588. }
  5589. PGSQL_CONV_CHECK_IGNORE();
  5590. if (err) {
  5591. php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5592. }
  5593. break;
  5594. case PG_INTERVAL:
  5595. switch(Z_TYPE_P(val)) {
  5596. case IS_STRING:
  5597. if (Z_STRLEN_P(val) == 0) {
  5598. ZVAL_STRING(&new_val, "NULL");
  5599. }
  5600. else {
  5601. /* From the Postgres docs:
  5602. interval values can be written with the following syntax:
  5603. [@] quantity unit [quantity unit...] [direction]
  5604. Where: quantity is a number (possibly signed); unit is second, minute, hour,
  5605. day, week, month, year, decade, century, millennium, or abbreviations or
  5606. plurals of these units [note not *all* abbreviations] ; direction can be
  5607. ago or empty. The at sign (@) is optional noise.
  5608. ...
  5609. Quantities of days, hours, minutes, and seconds can be specified without explicit
  5610. unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
  5611. sec'.
  5612. */
  5613. #define REGEX0 \
  5614. "^(@?[ \\t]+)?(" \
  5615. /* Textual time units and their abbreviations: */ \
  5616. "(([-+]?[ \\t]+)?" \
  5617. "[0-9]+(\\.[0-9]*)?[ \\t]*" \
  5618. "(millenniums|millennia|millennium|mil|mils|" \
  5619. "centuries|century|cent|c|" \
  5620. "decades|decade|dec|decs|" \
  5621. "years|year|y|" \
  5622. "months|month|mon|" \
  5623. "weeks|week|w|" \
  5624. "days|day|d|" \
  5625. "hours|hour|hr|hrs|h|" \
  5626. "minutes|minute|mins|min|m|" \
  5627. "seconds|second|secs|sec|s))+|" \
  5628. /* Textual time units plus (dd)* hh[:mm[:ss]] */ \
  5629. "((([-+]?[ \\t]+)?" \
  5630. "[0-9]+(\\.[0-9]*)?[ \\t]*" \
  5631. "(millenniums|millennia|millennium|mil|mils|" \
  5632. "centuries|century|cent|c|" \
  5633. "decades|decade|dec|decs|" \
  5634. "years|year|y|" \
  5635. "months|month|mon|" \
  5636. "weeks|week|w|" \
  5637. "days|day|d))+" \
  5638. "([-+]?[ \\t]+" \
  5639. "([0-9]+[ \\t]+)+" /* dd */ \
  5640. "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */ \
  5641. ")?))" \
  5642. "([ \\t]+ago)?$"
  5643. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
  5644. err = 1;
  5645. }
  5646. else {
  5647. ZVAL_STRING(&new_val, Z_STRVAL_P(val));
  5648. php_pgsql_add_quotes(&new_val, 1);
  5649. }
  5650. #undef REGEX0
  5651. }
  5652. break;
  5653. case IS_NULL:
  5654. ZVAL_STRING(&new_val, "NULL");
  5655. break;
  5656. default:
  5657. err = 1;
  5658. }
  5659. PGSQL_CONV_CHECK_IGNORE();
  5660. if (err) {
  5661. php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5662. }
  5663. break;
  5664. #ifdef HAVE_PQESCAPE
  5665. case PG_BYTEA:
  5666. switch (Z_TYPE_P(val)) {
  5667. case IS_STRING:
  5668. if (Z_STRLEN_P(val) == 0) {
  5669. ZVAL_STRING(&new_val, "NULL");
  5670. }
  5671. else {
  5672. unsigned char *tmp;
  5673. size_t to_len;
  5674. smart_str s = {0};
  5675. #ifdef HAVE_PQESCAPE_BYTEA_CONN
  5676. tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val), &to_len);
  5677. #else
  5678. tmp = PQescapeBytea(Z_STRVAL_P(val), (unsigned char *)Z_STRLEN_P(val), &to_len);
  5679. #endif
  5680. ZVAL_STRINGL(&new_val, (char *)tmp, to_len - 1); /* PQescapeBytea's to_len includes additional '\0' */
  5681. PQfreemem(tmp);
  5682. php_pgsql_add_quotes(&new_val, 1);
  5683. smart_str_appendl(&s, Z_STRVAL(new_val), Z_STRLEN(new_val));
  5684. smart_str_0(&s);
  5685. zval_ptr_dtor(&new_val);
  5686. ZVAL_NEW_STR(&new_val, s.s);
  5687. }
  5688. break;
  5689. case IS_LONG:
  5690. ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val)));
  5691. break;
  5692. case IS_DOUBLE:
  5693. ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
  5694. convert_to_string_ex(&new_val);
  5695. break;
  5696. case IS_NULL:
  5697. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5698. break;
  5699. default:
  5700. err = 1;
  5701. }
  5702. PGSQL_CONV_CHECK_IGNORE();
  5703. if (err) {
  5704. php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5705. }
  5706. break;
  5707. #endif
  5708. case PG_MACADDR:
  5709. switch(Z_TYPE_P(val)) {
  5710. case IS_STRING:
  5711. if (Z_STRLEN_P(val) == 0) {
  5712. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5713. }
  5714. else {
  5715. #define REGEX0 "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$"
  5716. if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
  5717. err = 1;
  5718. }
  5719. else {
  5720. ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5721. php_pgsql_add_quotes(&new_val, 1);
  5722. }
  5723. #undef REGEX0
  5724. }
  5725. break;
  5726. case IS_NULL:
  5727. ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
  5728. break;
  5729. default:
  5730. err = 1;
  5731. }
  5732. PGSQL_CONV_CHECK_IGNORE();
  5733. if (err) {
  5734. php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
  5735. }
  5736. break;
  5737. default:
  5738. /* should not happen */
  5739. php_error_docref(NULL, E_NOTICE, "Unknown or system data type '%s' for '%s'. Report error", Z_STRVAL_P(type), ZSTR_VAL(field));
  5740. err = 1;
  5741. break;
  5742. } /* switch */
  5743. if (err) {
  5744. zval_ptr_dtor(&new_val);
  5745. break; /* break out for() */
  5746. }
  5747. /* If field is NULL and HAS DEFAULT, should be skipped */
  5748. if (!skip_field) {
  5749. if (_php_pgsql_detect_identifier_escape(ZSTR_VAL(field), ZSTR_LEN(field)) == SUCCESS) {
  5750. zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
  5751. } else {
  5752. char *escaped = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
  5753. add_assoc_zval(result, escaped, &new_val);
  5754. PGSQLfree(escaped);
  5755. }
  5756. }
  5757. } ZEND_HASH_FOREACH_END(); /* for */
  5758. zval_ptr_dtor(&meta);
  5759. if (err) {
  5760. /* shouldn't destroy & free zval here */
  5761. return FAILURE;
  5762. }
  5763. return SUCCESS;
  5764. }
  5765. /* }}} */
  5766. /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
  5767. Check and convert values for PostgreSQL SQL statement */
  5768. PHP_FUNCTION(pg_convert)
  5769. {
  5770. zval *pgsql_link, *values;
  5771. char *table_name;
  5772. size_t table_name_len;
  5773. zend_ulong option = 0;
  5774. PGconn *pg_link;
  5775. if (zend_parse_parameters(ZEND_NUM_ARGS(),
  5776. "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
  5777. RETURN_THROWS();
  5778. }
  5779. if (option & ~PGSQL_CONV_OPTS) {
  5780. php_error_docref(NULL, E_WARNING, "Invalid option is specified");
  5781. RETURN_FALSE;
  5782. }
  5783. if (!table_name_len) {
  5784. php_error_docref(NULL, E_NOTICE, "Table name is invalid");
  5785. RETURN_FALSE;
  5786. }
  5787. if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  5788. RETURN_THROWS();
  5789. }
  5790. if (php_pgsql_flush_query(pg_link)) {
  5791. php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
  5792. }
  5793. array_init(return_value);
  5794. if (php_pgsql_convert(pg_link, table_name, values, return_value, option) == FAILURE) {
  5795. zend_array_destroy(Z_ARR_P(return_value));
  5796. RETURN_FALSE;
  5797. }
  5798. }
  5799. /* }}} */
  5800. static int do_exec(smart_str *querystr, ExecStatusType expect, PGconn *pg_link, zend_ulong opt) /* {{{ */
  5801. {
  5802. if (opt & PGSQL_DML_ASYNC) {
  5803. if (PQsendQuery(pg_link, ZSTR_VAL(querystr->s))) {
  5804. return 0;
  5805. }
  5806. }
  5807. else {
  5808. PGresult *pg_result;
  5809. pg_result = PQexec(pg_link, ZSTR_VAL(querystr->s));
  5810. if (PQresultStatus(pg_result) == expect) {
  5811. PQclear(pg_result);
  5812. return 0;
  5813. } else {
  5814. php_error_docref(NULL, E_WARNING, "%s", PQresultErrorMessage(pg_result));
  5815. PQclear(pg_result);
  5816. }
  5817. }
  5818. return -1;
  5819. }
  5820. /* }}} */
  5821. static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
  5822. {
  5823. size_t table_len = strlen(table);
  5824. /* schema.table should be "schema"."table" */
  5825. const char *dot = memchr(table, '.', table_len);
  5826. size_t len = dot ? dot - table : table_len;
  5827. if (_php_pgsql_detect_identifier_escape(table, len) == SUCCESS) {
  5828. smart_str_appendl(querystr, table, len);
  5829. } else {
  5830. char *escaped = PGSQLescapeIdentifier(pg_link, table, len);
  5831. smart_str_appends(querystr, escaped);
  5832. PGSQLfree(escaped);
  5833. }
  5834. if (dot) {
  5835. const char *after_dot = dot + 1;
  5836. len = table_len - len - 1;
  5837. /* "schema"."table" format */
  5838. if (_php_pgsql_detect_identifier_escape(after_dot, len) == SUCCESS) {
  5839. smart_str_appendc(querystr, '.');
  5840. smart_str_appendl(querystr, after_dot, len);
  5841. } else {
  5842. char *escaped = PGSQLescapeIdentifier(pg_link, after_dot, len);
  5843. smart_str_appendc(querystr, '.');
  5844. smart_str_appends(querystr, escaped);
  5845. PGSQLfree(escaped);
  5846. }
  5847. }
  5848. }
  5849. /* }}} */
  5850. /* {{{ php_pgsql_insert
  5851. */
  5852. PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, zend_ulong opt, zend_string **sql)
  5853. {
  5854. zval *val, converted;
  5855. char buf[256];
  5856. char *tmp;
  5857. smart_str querystr = {0};
  5858. int ret = FAILURE;
  5859. zend_string *fld;
  5860. assert(pg_link != NULL);
  5861. assert(table != NULL);
  5862. assert(Z_TYPE_P(var_array) == IS_ARRAY);
  5863. ZVAL_UNDEF(&converted);
  5864. if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
  5865. smart_str_appends(&querystr, "INSERT INTO ");
  5866. build_tablename(&querystr, pg_link, table);
  5867. smart_str_appends(&querystr, " DEFAULT VALUES");
  5868. goto no_values;
  5869. }
  5870. /* convert input array if needed */
  5871. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  5872. array_init(&converted);
  5873. if (php_pgsql_convert(pg_link, table, var_array, &converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
  5874. goto cleanup;
  5875. }
  5876. var_array = &converted;
  5877. }
  5878. smart_str_appends(&querystr, "INSERT INTO ");
  5879. build_tablename(&querystr, pg_link, table);
  5880. smart_str_appends(&querystr, " (");
  5881. ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
  5882. if (fld == NULL) {
  5883. php_error_docref(NULL, E_NOTICE, "Expects associative array for values to be inserted");
  5884. goto cleanup;
  5885. }
  5886. if (opt & PGSQL_DML_ESCAPE) {
  5887. tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
  5888. smart_str_appends(&querystr, tmp);
  5889. PGSQLfree(tmp);
  5890. } else {
  5891. smart_str_appendl(&querystr, ZSTR_VAL(fld), ZSTR_LEN(fld));
  5892. }
  5893. smart_str_appendc(&querystr, ',');
  5894. } ZEND_HASH_FOREACH_END();
  5895. ZSTR_LEN(querystr.s)--;
  5896. smart_str_appends(&querystr, ") VALUES (");
  5897. /* make values string */
  5898. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
  5899. /* we can avoid the key_type check here, because we tested it in the other loop */
  5900. switch (Z_TYPE_P(val)) {
  5901. case IS_STRING:
  5902. if (opt & PGSQL_DML_ESCAPE) {
  5903. size_t new_len;
  5904. char *tmp;
  5905. tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
  5906. new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
  5907. smart_str_appendc(&querystr, '\'');
  5908. smart_str_appendl(&querystr, tmp, new_len);
  5909. smart_str_appendc(&querystr, '\'');
  5910. efree(tmp);
  5911. } else {
  5912. smart_str_appendl(&querystr, Z_STRVAL_P(val), Z_STRLEN_P(val));
  5913. }
  5914. break;
  5915. case IS_LONG:
  5916. smart_str_append_long(&querystr, Z_LVAL_P(val));
  5917. break;
  5918. case IS_DOUBLE:
  5919. smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)));
  5920. break;
  5921. case IS_NULL:
  5922. smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1);
  5923. break;
  5924. default:
  5925. php_error_docref(NULL, E_WARNING, "Expects scaler values. type = %d", Z_TYPE_P(val));
  5926. goto cleanup;
  5927. break;
  5928. }
  5929. smart_str_appendc(&querystr, ',');
  5930. } ZEND_HASH_FOREACH_END();
  5931. /* Remove the trailing "," */
  5932. ZSTR_LEN(querystr.s)--;
  5933. smart_str_appends(&querystr, ");");
  5934. no_values:
  5935. smart_str_0(&querystr);
  5936. if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
  5937. do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS)) == 0) {
  5938. ret = SUCCESS;
  5939. }
  5940. else if (opt & PGSQL_DML_STRING) {
  5941. ret = SUCCESS;
  5942. }
  5943. cleanup:
  5944. zval_ptr_dtor(&converted);
  5945. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  5946. *sql = querystr.s;
  5947. }
  5948. else {
  5949. smart_str_free(&querystr);
  5950. }
  5951. return ret;
  5952. }
  5953. /* }}} */
  5954. /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
  5955. Insert values (filed=>value) to table */
  5956. PHP_FUNCTION(pg_insert)
  5957. {
  5958. zval *pgsql_link, *values;
  5959. char *table;
  5960. size_t table_len;
  5961. zend_ulong option = PGSQL_DML_EXEC, return_sql;
  5962. PGconn *pg_link;
  5963. PGresult *pg_result;
  5964. ExecStatusType status;
  5965. zend_string *sql = NULL;
  5966. int argc = ZEND_NUM_ARGS();
  5967. if (zend_parse_parameters(argc, "rsa|l",
  5968. &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
  5969. RETURN_THROWS();
  5970. }
  5971. if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  5972. php_error_docref(NULL, E_WARNING, "Invalid option is specified");
  5973. RETURN_FALSE;
  5974. }
  5975. if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  5976. RETURN_THROWS();
  5977. }
  5978. if (php_pgsql_flush_query(pg_link)) {
  5979. php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
  5980. }
  5981. return_sql = option & PGSQL_DML_STRING;
  5982. if (option & PGSQL_DML_EXEC) {
  5983. /* return resource when executed */
  5984. option = option & ~PGSQL_DML_EXEC;
  5985. if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql) == FAILURE) {
  5986. RETURN_FALSE;
  5987. }
  5988. pg_result = PQexec(pg_link, ZSTR_VAL(sql));
  5989. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pg_link) != CONNECTION_OK) {
  5990. PQclear(pg_result);
  5991. PQreset(pg_link);
  5992. pg_result = PQexec(pg_link, ZSTR_VAL(sql));
  5993. }
  5994. efree(sql);
  5995. if (pg_result) {
  5996. status = PQresultStatus(pg_result);
  5997. } else {
  5998. status = (ExecStatusType) PQstatus(pg_link);
  5999. }
  6000. switch (status) {
  6001. case PGRES_EMPTY_QUERY:
  6002. case PGRES_BAD_RESPONSE:
  6003. case PGRES_NONFATAL_ERROR:
  6004. case PGRES_FATAL_ERROR:
  6005. PHP_PQ_ERROR("Query failed: %s", pg_link);
  6006. PQclear(pg_result);
  6007. RETURN_FALSE;
  6008. break;
  6009. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  6010. default:
  6011. if (pg_result) {
  6012. pgsql_result_handle *pgsql_handle = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  6013. pgsql_handle->conn = pg_link;
  6014. pgsql_handle->result = pg_result;
  6015. pgsql_handle->row = 0;
  6016. RETURN_RES(zend_register_resource(pgsql_handle, le_result));
  6017. } else {
  6018. PQclear(pg_result);
  6019. RETURN_FALSE;
  6020. }
  6021. break;
  6022. }
  6023. } else if (php_pgsql_insert(pg_link, table, values, option, &sql) == FAILURE) {
  6024. RETURN_FALSE;
  6025. }
  6026. if (return_sql) {
  6027. RETURN_STR(sql);
  6028. return;
  6029. }
  6030. RETURN_TRUE;
  6031. }
  6032. /* }}} */
  6033. static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len, zend_ulong opt) /* {{{ */
  6034. {
  6035. zend_string *fld;
  6036. zval *val;
  6037. ZEND_HASH_FOREACH_STR_KEY_VAL(ht, fld, val) {
  6038. if (fld == NULL) {
  6039. php_error_docref(NULL, E_NOTICE, "Expects associative array for values to be inserted");
  6040. return -1;
  6041. }
  6042. if (opt & PGSQL_DML_ESCAPE) {
  6043. char *tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
  6044. smart_str_appends(querystr, tmp);
  6045. PGSQLfree(tmp);
  6046. } else {
  6047. smart_str_appendl(querystr, ZSTR_VAL(fld), ZSTR_LEN(fld));
  6048. }
  6049. if (where_cond && (Z_TYPE_P(val) == IS_TRUE || Z_TYPE_P(val) == IS_FALSE || (Z_TYPE_P(val) == IS_STRING && !strcmp(Z_STRVAL_P(val), "NULL")))) {
  6050. smart_str_appends(querystr, " IS ");
  6051. } else {
  6052. smart_str_appendc(querystr, '=');
  6053. }
  6054. switch (Z_TYPE_P(val)) {
  6055. case IS_STRING:
  6056. if (opt & PGSQL_DML_ESCAPE) {
  6057. char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
  6058. size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
  6059. smart_str_appendc(querystr, '\'');
  6060. smart_str_appendl(querystr, tmp, new_len);
  6061. smart_str_appendc(querystr, '\'');
  6062. efree(tmp);
  6063. } else {
  6064. smart_str_appendl(querystr, Z_STRVAL_P(val), Z_STRLEN_P(val));
  6065. }
  6066. break;
  6067. case IS_LONG:
  6068. smart_str_append_long(querystr, Z_LVAL_P(val));
  6069. break;
  6070. case IS_DOUBLE: {
  6071. char buf[256];
  6072. smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)), sizeof(buf) - 1));
  6073. }
  6074. break;
  6075. case IS_NULL:
  6076. smart_str_appendl(querystr, "NULL", sizeof("NULL")-1);
  6077. break;
  6078. default:
  6079. php_error_docref(NULL, E_WARNING, "Expects scaler values. type=%d", Z_TYPE_P(val));
  6080. return -1;
  6081. }
  6082. smart_str_appendl(querystr, pad, pad_len);
  6083. } ZEND_HASH_FOREACH_END();
  6084. if (querystr->s) {
  6085. ZSTR_LEN(querystr->s) -= pad_len;
  6086. }
  6087. return 0;
  6088. }
  6089. /* }}} */
  6090. /* {{{ php_pgsql_update
  6091. */
  6092. PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var_array, zval *ids_array, zend_ulong opt, zend_string **sql)
  6093. {
  6094. zval var_converted, ids_converted;
  6095. smart_str querystr = {0};
  6096. int ret = FAILURE;
  6097. assert(pg_link != NULL);
  6098. assert(table != NULL);
  6099. assert(Z_TYPE_P(var_array) == IS_ARRAY);
  6100. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  6101. assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
  6102. if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
  6103. || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
  6104. return FAILURE;
  6105. }
  6106. ZVAL_UNDEF(&var_converted);
  6107. ZVAL_UNDEF(&ids_converted);
  6108. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  6109. array_init(&var_converted);
  6110. if (php_pgsql_convert(pg_link, table, var_array, &var_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
  6111. goto cleanup;
  6112. }
  6113. var_array = &var_converted;
  6114. array_init(&ids_converted);
  6115. if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
  6116. goto cleanup;
  6117. }
  6118. ids_array = &ids_converted;
  6119. }
  6120. smart_str_appends(&querystr, "UPDATE ");
  6121. build_tablename(&querystr, pg_link, table);
  6122. smart_str_appends(&querystr, " SET ");
  6123. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
  6124. goto cleanup;
  6125. smart_str_appends(&querystr, " WHERE ");
  6126. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
  6127. goto cleanup;
  6128. smart_str_appendc(&querystr, ';');
  6129. smart_str_0(&querystr);
  6130. if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt) == 0) {
  6131. ret = SUCCESS;
  6132. } else if (opt & PGSQL_DML_STRING) {
  6133. ret = SUCCESS;
  6134. }
  6135. cleanup:
  6136. zval_ptr_dtor(&var_converted);
  6137. zval_ptr_dtor(&ids_converted);
  6138. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  6139. *sql = querystr.s;
  6140. }
  6141. else {
  6142. smart_str_free(&querystr);
  6143. }
  6144. return ret;
  6145. }
  6146. /* }}} */
  6147. /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
  6148. Update table using values (field=>value) and ids (id=>value) */
  6149. PHP_FUNCTION(pg_update)
  6150. {
  6151. zval *pgsql_link, *values, *ids;
  6152. char *table;
  6153. size_t table_len;
  6154. zend_ulong option = PGSQL_DML_EXEC;
  6155. PGconn *pg_link;
  6156. zend_string *sql = NULL;
  6157. int argc = ZEND_NUM_ARGS();
  6158. if (zend_parse_parameters(argc, "rsaa|l",
  6159. &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
  6160. RETURN_THROWS();
  6161. }
  6162. if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  6163. php_error_docref(NULL, E_WARNING, "Invalid option is specified");
  6164. RETURN_FALSE;
  6165. }
  6166. if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  6167. RETURN_THROWS();
  6168. }
  6169. if (php_pgsql_flush_query(pg_link)) {
  6170. php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
  6171. }
  6172. if (php_pgsql_update(pg_link, table, values, ids, option, &sql) == FAILURE) {
  6173. RETURN_FALSE;
  6174. }
  6175. if (option & PGSQL_DML_STRING) {
  6176. RETURN_STR(sql);
  6177. }
  6178. RETURN_TRUE;
  6179. }
  6180. /* }}} */
  6181. /* {{{ php_pgsql_delete
  6182. */
  6183. PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, zend_ulong opt, zend_string **sql)
  6184. {
  6185. zval ids_converted;
  6186. smart_str querystr = {0};
  6187. int ret = FAILURE;
  6188. assert(pg_link != NULL);
  6189. assert(table != NULL);
  6190. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  6191. assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
  6192. if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
  6193. return FAILURE;
  6194. }
  6195. ZVAL_UNDEF(&ids_converted);
  6196. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  6197. array_init(&ids_converted);
  6198. if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
  6199. goto cleanup;
  6200. }
  6201. ids_array = &ids_converted;
  6202. }
  6203. smart_str_appends(&querystr, "DELETE FROM ");
  6204. build_tablename(&querystr, pg_link, table);
  6205. smart_str_appends(&querystr, " WHERE ");
  6206. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
  6207. goto cleanup;
  6208. smart_str_appendc(&querystr, ';');
  6209. smart_str_0(&querystr);
  6210. if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt) == 0) {
  6211. ret = SUCCESS;
  6212. } else if (opt & PGSQL_DML_STRING) {
  6213. ret = SUCCESS;
  6214. }
  6215. cleanup:
  6216. zval_ptr_dtor(&ids_converted);
  6217. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  6218. *sql = querystr.s;
  6219. }
  6220. else {
  6221. smart_str_free(&querystr);
  6222. }
  6223. return ret;
  6224. }
  6225. /* }}} */
  6226. /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
  6227. Delete records has ids (id=>value) */
  6228. PHP_FUNCTION(pg_delete)
  6229. {
  6230. zval *pgsql_link, *ids;
  6231. char *table;
  6232. size_t table_len;
  6233. zend_ulong option = PGSQL_DML_EXEC;
  6234. PGconn *pg_link;
  6235. zend_string *sql;
  6236. int argc = ZEND_NUM_ARGS();
  6237. if (zend_parse_parameters(argc, "rsa|l",
  6238. &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
  6239. RETURN_THROWS();
  6240. }
  6241. if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  6242. php_error_docref(NULL, E_WARNING, "Invalid option is specified");
  6243. RETURN_FALSE;
  6244. }
  6245. if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  6246. RETURN_THROWS();
  6247. }
  6248. if (php_pgsql_flush_query(pg_link)) {
  6249. php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
  6250. }
  6251. if (php_pgsql_delete(pg_link, table, ids, option, &sql) == FAILURE) {
  6252. RETURN_FALSE;
  6253. }
  6254. if (option & PGSQL_DML_STRING) {
  6255. RETURN_STR(sql);
  6256. }
  6257. RETURN_TRUE;
  6258. }
  6259. /* }}} */
  6260. /* {{{ php_pgsql_result2array
  6261. */
  6262. PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array, long result_type)
  6263. {
  6264. zval row;
  6265. char *field_name;
  6266. size_t num_fields;
  6267. int pg_numrows, pg_row;
  6268. uint32_t i;
  6269. assert(Z_TYPE_P(ret_array) == IS_ARRAY);
  6270. if ((pg_numrows = PQntuples(pg_result)) <= 0) {
  6271. return FAILURE;
  6272. }
  6273. for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
  6274. array_init(&row);
  6275. for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
  6276. field_name = PQfname(pg_result, i);
  6277. if (PQgetisnull(pg_result, pg_row, i)) {
  6278. if (result_type & PGSQL_ASSOC) {
  6279. add_assoc_null(&row, field_name);
  6280. }
  6281. if (result_type & PGSQL_NUM) {
  6282. add_next_index_null(&row);
  6283. }
  6284. } else {
  6285. char *element = PQgetvalue(pg_result, pg_row, i);
  6286. if (element) {
  6287. const size_t element_len = strlen(element);
  6288. if (result_type & PGSQL_ASSOC) {
  6289. add_assoc_stringl(&row, field_name, element, element_len);
  6290. }
  6291. if (result_type & PGSQL_NUM) {
  6292. add_next_index_stringl(&row, element, element_len);
  6293. }
  6294. }
  6295. }
  6296. }
  6297. add_index_zval(ret_array, pg_row, &row);
  6298. }
  6299. return SUCCESS;
  6300. }
  6301. /* }}} */
  6302. /* {{{ php_pgsql_select
  6303. */
  6304. PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, zend_ulong opt, long result_type, zend_string **sql)
  6305. {
  6306. zval ids_converted;
  6307. smart_str querystr = {0};
  6308. int ret = FAILURE;
  6309. PGresult *pg_result;
  6310. assert(pg_link != NULL);
  6311. assert(table != NULL);
  6312. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  6313. assert(Z_TYPE_P(ret_array) == IS_ARRAY);
  6314. assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
  6315. if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
  6316. return FAILURE;
  6317. }
  6318. ZVAL_UNDEF(&ids_converted);
  6319. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  6320. array_init(&ids_converted);
  6321. if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
  6322. goto cleanup;
  6323. }
  6324. ids_array = &ids_converted;
  6325. }
  6326. smart_str_appends(&querystr, "SELECT * FROM ");
  6327. build_tablename(&querystr, pg_link, table);
  6328. smart_str_appends(&querystr, " WHERE ");
  6329. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
  6330. goto cleanup;
  6331. smart_str_appendc(&querystr, ';');
  6332. smart_str_0(&querystr);
  6333. pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
  6334. if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
  6335. ret = php_pgsql_result2array(pg_result, ret_array, result_type);
  6336. } else {
  6337. php_error_docref(NULL, E_NOTICE, "Failed to execute '%s'", ZSTR_VAL(querystr.s));
  6338. }
  6339. PQclear(pg_result);
  6340. cleanup:
  6341. zval_ptr_dtor(&ids_converted);
  6342. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  6343. *sql = querystr.s;
  6344. }
  6345. else {
  6346. smart_str_free(&querystr);
  6347. }
  6348. return ret;
  6349. }
  6350. /* }}} */
  6351. /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options [, int result_type])
  6352. Select records that has ids (id=>value) */
  6353. PHP_FUNCTION(pg_select)
  6354. {
  6355. zval *pgsql_link, *ids;
  6356. char *table;
  6357. size_t table_len;
  6358. zend_ulong option = PGSQL_DML_EXEC;
  6359. long result_type = PGSQL_ASSOC;
  6360. PGconn *pg_link;
  6361. zend_string *sql = NULL;
  6362. int argc = ZEND_NUM_ARGS();
  6363. if (zend_parse_parameters(argc, "rsa|l",
  6364. &pgsql_link, &table, &table_len, &ids, &option, &result_type) == FAILURE) {
  6365. RETURN_THROWS();
  6366. }
  6367. if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  6368. php_error_docref(NULL, E_WARNING, "Invalid option is specified");
  6369. RETURN_FALSE;
  6370. }
  6371. if (!(result_type & PGSQL_BOTH)) {
  6372. php_error_docref(NULL, E_WARNING, "Invalid result type");
  6373. RETURN_FALSE;
  6374. }
  6375. if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
  6376. RETURN_THROWS();
  6377. }
  6378. if (php_pgsql_flush_query(pg_link)) {
  6379. php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
  6380. }
  6381. array_init(return_value);
  6382. if (php_pgsql_select(pg_link, table, ids, return_value, option, result_type, &sql) == FAILURE) {
  6383. zval_ptr_dtor(return_value);
  6384. RETURN_FALSE;
  6385. }
  6386. if (option & PGSQL_DML_STRING) {
  6387. zval_ptr_dtor(return_value);
  6388. RETURN_STR(sql);
  6389. }
  6390. return;
  6391. }
  6392. /* }}} */
  6393. #endif