You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7126 lines
199 KiB

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