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.

4576 lines
124 KiB

25 years ago
25 years ago
27 years ago
27 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
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
25 years ago
25 years ago
25 years ago
25 years ago
26 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
26 years ago
25 years ago
24 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
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
25 years ago
25 years ago
25 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 4 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2002 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.02 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://www.php.net/license/2_02.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. +----------------------------------------------------------------------+
  20. */
  21. /* $Id$ */
  22. #include <stdlib.h>
  23. #define PHP_PGSQL_PRIVATE 1
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include "php.h"
  28. #include "php_ini.h"
  29. #include "ext/standard/php_standard.h"
  30. #include "php_pgsql.h"
  31. #include "php_globals.h"
  32. #if HAVE_PGSQL
  33. #ifndef InvalidOid
  34. #define InvalidOid ((Oid) 0)
  35. #endif
  36. #define PGSQL_ASSOC 1<<0
  37. #define PGSQL_NUM 1<<1
  38. #define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
  39. #define PGSQL_STATUS_LONG 1
  40. #define PGSQL_STATUS_STRING 2
  41. #if HAVE_PQSETNONBLOCKING
  42. #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
  43. #else
  44. #define PQ_SETNONBLOCKING(pg_link, flag) 0
  45. #endif
  46. #define CHECK_DEFAULT_LINK(x) if (x == -1) { php_error(E_WARNING, "%s() no PostgreSQL link opened yet", get_active_function_name(TSRMLS_C)); }
  47. /* {{{ pgsql_functions[]
  48. */
  49. function_entry pgsql_functions[] = {
  50. /* connection functions */
  51. PHP_FE(pg_connect, NULL)
  52. PHP_FE(pg_pconnect, NULL)
  53. PHP_FE(pg_close, NULL)
  54. PHP_FE(pg_connection_status, NULL)
  55. PHP_FE(pg_connection_busy, NULL)
  56. PHP_FE(pg_connection_reset, NULL)
  57. PHP_FE(pg_host, NULL)
  58. PHP_FE(pg_dbname, NULL)
  59. PHP_FE(pg_port, NULL)
  60. PHP_FE(pg_tty, NULL)
  61. PHP_FE(pg_options, NULL)
  62. /* query functions */
  63. PHP_FE(pg_query, NULL)
  64. PHP_FE(pg_send_query, NULL)
  65. PHP_FE(pg_cancel_query, NULL)
  66. /* result functions */
  67. PHP_FE(pg_fetch_result, NULL)
  68. PHP_FE(pg_fetch_row, NULL)
  69. PHP_FE(pg_fetch_array, NULL)
  70. PHP_FE(pg_fetch_object, NULL)
  71. PHP_FE(pg_affected_rows,NULL)
  72. PHP_FE(pg_get_result, NULL)
  73. PHP_FE(pg_result_status,NULL)
  74. PHP_FE(pg_free_result, NULL)
  75. PHP_FE(pg_last_oid, NULL)
  76. PHP_FE(pg_num_rows, NULL)
  77. PHP_FE(pg_num_fields, NULL)
  78. PHP_FE(pg_field_name, NULL)
  79. PHP_FE(pg_field_num, NULL)
  80. PHP_FE(pg_field_size, NULL)
  81. PHP_FE(pg_field_type, NULL)
  82. PHP_FE(pg_field_prtlen, NULL)
  83. PHP_FE(pg_field_is_null,NULL)
  84. /* error message functions */
  85. PHP_FE(pg_result_error, NULL)
  86. PHP_FE(pg_last_error, NULL)
  87. PHP_FE(pg_last_notice, NULL)
  88. /* copy functions */
  89. PHP_FE(pg_put_line, NULL)
  90. PHP_FE(pg_end_copy, NULL)
  91. PHP_FE(pg_copy_to, NULL)
  92. PHP_FE(pg_copy_from, NULL)
  93. /* debug functions */
  94. PHP_FE(pg_trace, NULL)
  95. PHP_FE(pg_untrace, NULL)
  96. /* large object functions */
  97. PHP_FE(pg_lo_create, NULL)
  98. PHP_FE(pg_lo_unlink, NULL)
  99. PHP_FE(pg_lo_open, NULL)
  100. PHP_FE(pg_lo_close, NULL)
  101. PHP_FE(pg_lo_read, NULL)
  102. PHP_FE(pg_lo_write, NULL)
  103. PHP_FE(pg_lo_read_all, NULL)
  104. PHP_FE(pg_lo_import, NULL)
  105. PHP_FE(pg_lo_export, NULL)
  106. PHP_FE(pg_lo_seek, NULL)
  107. PHP_FE(pg_lo_tell, NULL)
  108. /* utility functions */
  109. #if HAVE_PQESCAPE
  110. PHP_FE(pg_escape_string,NULL)
  111. PHP_FE(pg_escape_bytea, NULL)
  112. #endif
  113. #if HAVE_PQCLIENTENCODING
  114. PHP_FE(pg_client_encoding, NULL)
  115. PHP_FE(pg_set_client_encoding, NULL)
  116. #endif
  117. /* misc function */
  118. PHP_FE(pg_metadata, NULL)
  119. PHP_FE(pg_convert, NULL)
  120. PHP_FE(pg_insert, NULL)
  121. PHP_FE(pg_update, NULL)
  122. PHP_FE(pg_delete, NULL)
  123. PHP_FE(pg_select, NULL)
  124. /* aliases for downwards compatibility */
  125. PHP_FALIAS(pg_exec, pg_query, NULL)
  126. PHP_FALIAS(pg_getlastoid, pg_last_oid, NULL)
  127. PHP_FALIAS(pg_cmdtuples, pg_affected_rows, NULL)
  128. PHP_FALIAS(pg_errormessage, pg_last_error, NULL)
  129. PHP_FALIAS(pg_numrows, pg_num_rows, NULL)
  130. PHP_FALIAS(pg_numfields, pg_num_fields, NULL)
  131. PHP_FALIAS(pg_fieldname, pg_field_name, NULL)
  132. PHP_FALIAS(pg_fieldsize, pg_field_size, NULL)
  133. PHP_FALIAS(pg_fieldtype, pg_field_type, NULL)
  134. PHP_FALIAS(pg_fieldnum, pg_field_num, NULL)
  135. PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, NULL)
  136. PHP_FALIAS(pg_fieldisnull, pg_field_is_null, NULL)
  137. PHP_FALIAS(pg_freeresult, pg_free_result, NULL)
  138. PHP_FALIAS(pg_result, pg_fetch_result, NULL)
  139. PHP_FALIAS(pg_loreadall, pg_lo_read_all, NULL)
  140. PHP_FALIAS(pg_locreate, pg_lo_create, NULL)
  141. PHP_FALIAS(pg_lounlink, pg_lo_unlink, NULL)
  142. PHP_FALIAS(pg_loopen, pg_lo_open, NULL)
  143. PHP_FALIAS(pg_loclose, pg_lo_close, NULL)
  144. PHP_FALIAS(pg_loread, pg_lo_read, NULL)
  145. PHP_FALIAS(pg_lowrite, pg_lo_write, NULL)
  146. PHP_FALIAS(pg_loimport, pg_lo_import, NULL)
  147. PHP_FALIAS(pg_loexport, pg_lo_export, NULL)
  148. #if HAVE_PQCLIENTENCODING
  149. PHP_FALIAS(pg_clientencoding, pg_client_encoding, NULL)
  150. PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, NULL)
  151. #endif
  152. {NULL, NULL, NULL}
  153. };
  154. /* }}} */
  155. /* {{{ pgsql_module_entry
  156. */
  157. zend_module_entry pgsql_module_entry = {
  158. STANDARD_MODULE_HEADER,
  159. "pgsql",
  160. pgsql_functions,
  161. PHP_MINIT(pgsql),
  162. PHP_MSHUTDOWN(pgsql),
  163. PHP_RINIT(pgsql),
  164. PHP_RSHUTDOWN(pgsql),
  165. PHP_MINFO(pgsql),
  166. NO_VERSION_YET,
  167. STANDARD_MODULE_PROPERTIES
  168. };
  169. /* }}} */
  170. #ifdef COMPILE_DL_PGSQL
  171. ZEND_GET_MODULE(pgsql)
  172. #endif
  173. static int le_link, le_plink, le_result, le_lofp, le_string;
  174. #ifdef ZTS
  175. int pgsql_globals_id;
  176. #else
  177. php_pgsql_globals pgsql_globals;
  178. #endif
  179. /* {{{ php_pgsql_set_default_link
  180. */
  181. static void php_pgsql_set_default_link(int id TSRMLS_DC)
  182. {
  183. zend_list_addref(id);
  184. if (PGG(default_link) != -1) {
  185. zend_list_delete(PGG(default_link));
  186. }
  187. PGG(default_link) = id;
  188. }
  189. /* }}} */
  190. /* {{{ _close_pgsql_link
  191. */
  192. static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  193. {
  194. PGconn *link = (PGconn *)rsrc->ptr;
  195. PGresult *res;
  196. while ((res = PQgetResult(link))) {
  197. PQclear(res);
  198. }
  199. PQfinish(link);
  200. PGG(num_links)--;
  201. }
  202. /* }}} */
  203. /* {{{ _close_pgsql_plink
  204. */
  205. static void _close_pgsql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  206. {
  207. PGconn *link = (PGconn *)rsrc->ptr;
  208. PGresult *res;
  209. while ((res = PQgetResult(link))) {
  210. PQclear(res);
  211. }
  212. PQfinish(link);
  213. PGG(num_persistent)--;
  214. PGG(num_links)--;
  215. }
  216. /* }}} */
  217. /* {{{ _php_pgsql_notice_handler
  218. */
  219. static void _php_pgsql_notice_handler(void *resource_id, const char *message)
  220. {
  221. php_pgsql_notice *notice;
  222. TSRMLS_FETCH();
  223. if (! PGG(ignore_notices)) {
  224. if (PGG(log_notices)) {
  225. php_log_err((char *) message TSRMLS_CC);
  226. }
  227. notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice));
  228. notice->len = strlen(message);
  229. notice->message = estrndup(message, notice->len);
  230. zend_hash_index_update(&PGG(notices), *(int *)resource_id, (void **)&notice, sizeof(php_pgsql_notice *), NULL);
  231. }
  232. }
  233. /* }}} */
  234. #define PHP_PGSQL_NOTICE_PTR_DTOR (void (*)(void *))_php_pgsql_notice_ptr_dtor
  235. /* {{{ _php_pgsql_notice_dtor
  236. */
  237. static void _php_pgsql_notice_ptr_dtor(void **ptr)
  238. {
  239. php_pgsql_notice *notice = (php_pgsql_notice *)*ptr;
  240. efree(notice->message);
  241. efree(notice);
  242. }
  243. /* }}} */
  244. /* {{{ _rollback_transactions
  245. */
  246. static int _rollback_transactions(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  247. {
  248. PGconn *link;
  249. PGresult *res;
  250. int orig;
  251. if (Z_TYPE_P(rsrc) != le_plink)
  252. return 0;
  253. link = (PGconn *) rsrc->ptr;
  254. if (PQ_SETNONBLOCKING(link, 0)) {
  255. php_error(E_NOTICE,"PostgreSQL cannot set connection to blocking mode");
  256. return -1;
  257. }
  258. while ((res = PQgetResult(link))) {
  259. PQclear(res);
  260. }
  261. orig = PGG(ignore_notices);
  262. PGG(ignore_notices) = 1;
  263. res = PQexec(link,"BEGIN;ROLLBACK;");
  264. PQclear(res);
  265. PGG(ignore_notices) = orig;
  266. return 0;
  267. }
  268. /* }}} */
  269. /* {{{ _free_ptr
  270. */
  271. static void _free_ptr(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  272. {
  273. pgLofp *lofp = (pgLofp *)rsrc->ptr;
  274. efree(lofp);
  275. }
  276. /* }}} */
  277. /* {{{ _free_result
  278. */
  279. static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  280. {
  281. pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
  282. PQclear(pg_result->result);
  283. efree(pg_result);
  284. }
  285. /* }}} */
  286. /* {{{ PHP_INI
  287. */
  288. PHP_INI_BEGIN()
  289. STD_PHP_INI_BOOLEAN("pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, php_pgsql_globals, pgsql_globals)
  290. STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateInt, max_persistent, php_pgsql_globals, pgsql_globals, display_link_numbers)
  291. STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateInt, max_links, php_pgsql_globals, pgsql_globals, display_link_numbers)
  292. STD_PHP_INI_BOOLEAN("pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, php_pgsql_globals, pgsql_globals)
  293. STD_PHP_INI_BOOLEAN("pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, php_pgsql_globals, pgsql_globals)
  294. STD_PHP_INI_BOOLEAN("pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, php_pgsql_globals, pgsql_globals)
  295. PHP_INI_END()
  296. /* }}} */
  297. /* {{{ php_pgsql_init_globals
  298. */
  299. static void php_pgsql_init_globals(php_pgsql_globals *pgsql_globals_p TSRMLS_DC)
  300. {
  301. PGG(num_persistent) = 0;
  302. /* Initilize notice message hash at MINIT only */
  303. zend_hash_init_ex(&PGG(notices), 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0);
  304. }
  305. /* }}} */
  306. /* {{{ PHP_MINIT_FUNCTION
  307. */
  308. PHP_MINIT_FUNCTION(pgsql)
  309. {
  310. #ifdef ZTS
  311. ts_allocate_id(&pgsql_globals_id, sizeof(php_pgsql_globals), (ts_allocate_ctor) php_pgsql_init_globals, NULL);
  312. #else
  313. php_pgsql_init_globals(&pgsql_globals TSRMLS_CC);
  314. #endif
  315. REGISTER_INI_ENTRIES();
  316. le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
  317. le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
  318. le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
  319. le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
  320. le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
  321. /* For pg_fetch_array() */
  322. REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
  323. REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
  324. REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
  325. /* For pg_connection_status() */
  326. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
  327. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
  328. /* For lo_seek() */
  329. REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
  330. REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
  331. REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
  332. /* For pg_result_status() return value type */
  333. REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
  334. REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
  335. /* For pg_result_status() return value */
  336. REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
  337. REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
  338. REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
  339. REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
  340. REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
  341. REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
  342. REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
  343. REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
  344. return SUCCESS;
  345. }
  346. /* }}} */
  347. /* {{{ PHP_MSHUTDOWN_FUNCTION
  348. */
  349. PHP_MSHUTDOWN_FUNCTION(pgsql)
  350. {
  351. UNREGISTER_INI_ENTRIES();
  352. return SUCCESS;
  353. }
  354. /* }}} */
  355. /* {{{ PHP_RINIT_FUNCTION
  356. */
  357. PHP_RINIT_FUNCTION(pgsql)
  358. {
  359. PGG(default_link)=-1;
  360. PGG(num_links) = PGG(num_persistent);
  361. return SUCCESS;
  362. }
  363. /* }}} */
  364. /* {{{ PHP_RSHUTDOWN_FUNCTION
  365. */
  366. PHP_RSHUTDOWN_FUNCTION(pgsql)
  367. {
  368. /* clean up notice messages */
  369. zend_hash_clean(&PGG(notices));
  370. /* clean up persistent connection */
  371. zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions TSRMLS_CC);
  372. return SUCCESS;
  373. }
  374. /* }}} */
  375. /* {{{ PHP_MINFO_FUNCTION
  376. */
  377. PHP_MINFO_FUNCTION(pgsql)
  378. {
  379. char buf[256];
  380. php_info_print_table_start();
  381. php_info_print_table_header(2, "PostgreSQL Support", "enabled");
  382. #if HAVE_PG_CONFIG_H
  383. php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
  384. #ifdef MULTIBYTE
  385. php_info_print_table_row(2, "Multibyte charater support", "enabled");
  386. #else
  387. php_info_print_table_row(2, "Multibyte charater support", "disabled");
  388. #endif
  389. #ifdef USE_SSL
  390. php_info_print_table_row(2, "SSL support", "enabled");
  391. #else
  392. php_info_print_table_row(2, "SSL support", "disabled");
  393. #endif
  394. #endif /* HAVE_PG_CONFIG_H */
  395. sprintf(buf, "%ld", PGG(num_persistent));
  396. php_info_print_table_row(2, "Active Persistent Links", buf);
  397. sprintf(buf, "%ld", PGG(num_links));
  398. php_info_print_table_row(2, "Active Links", buf);
  399. php_info_print_table_end();
  400. DISPLAY_INI_ENTRIES();
  401. }
  402. /* }}} */
  403. /* {{{ php_pgsql_do_connect
  404. */
  405. static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
  406. {
  407. char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
  408. char *hashed_details;
  409. int hashed_details_length;
  410. PGconn *pgsql;
  411. switch(ZEND_NUM_ARGS()) {
  412. case 1: { /* new style, using connection string */
  413. zval **yyconnstring;
  414. if (zend_get_parameters_ex(1, &yyconnstring) == FAILURE) {
  415. RETURN_FALSE;
  416. }
  417. convert_to_string_ex(yyconnstring);
  418. connstring = Z_STRVAL_PP(yyconnstring);
  419. hashed_details_length = Z_STRLEN_PP(yyconnstring)+5+1;
  420. hashed_details = (char *) emalloc(hashed_details_length+1);
  421. sprintf(hashed_details, "pgsql_%s", connstring); /* SAFE */
  422. }
  423. break;
  424. case 3: { /* host, port, dbname */
  425. zval **yyhost, **yyport, **yydbname;
  426. if (zend_get_parameters_ex(3, &yyhost, &yyport, &yydbname) == FAILURE) {
  427. RETURN_FALSE;
  428. }
  429. convert_to_string_ex(yyhost);
  430. convert_to_string_ex(yyport);
  431. convert_to_string_ex(yydbname);
  432. host = Z_STRVAL_PP(yyhost);
  433. port = Z_STRVAL_PP(yyport);
  434. dbname = Z_STRVAL_PP(yydbname);
  435. options=tty=NULL;
  436. hashed_details_length = Z_STRLEN_PP(yyhost) + Z_STRLEN_PP(yyport) + Z_STRLEN_PP(yydbname) + 5 + 5;
  437. hashed_details = (char *) emalloc(hashed_details_length+1);
  438. sprintf(hashed_details, "pgsql_%s_%s___%s", host, port, dbname); /* SAFE */
  439. }
  440. break;
  441. case 4: { /* host, port, options, dbname */
  442. zval **yyhost, **yyport, **yyoptions, **yydbname;
  443. if (zend_get_parameters_ex(4, &yyhost, &yyport, &yyoptions, &yydbname) == FAILURE) {
  444. RETURN_FALSE;
  445. }
  446. convert_to_string_ex(yyhost);
  447. convert_to_string_ex(yyport);
  448. convert_to_string_ex(yyoptions);
  449. convert_to_string_ex(yydbname);
  450. host = Z_STRVAL_PP(yyhost);
  451. port = Z_STRVAL_PP(yyport);
  452. options = Z_STRVAL_PP(yyoptions);
  453. dbname = Z_STRVAL_PP(yydbname);
  454. tty=NULL;
  455. hashed_details_length = Z_STRLEN_PP(yyhost) + Z_STRLEN_PP(yyport) + Z_STRLEN_PP(yyoptions) + Z_STRLEN_PP(yydbname) + 5 + 5;
  456. hashed_details = (char *) emalloc(hashed_details_length+1);
  457. sprintf(hashed_details, "pgsql_%s_%s_%s__%s", host, port, options, dbname); /* SAFE */
  458. }
  459. break;
  460. case 5: { /* host, port, options, tty, dbname */
  461. zval **yyhost, **yyport, **yyoptions, **yytty, **yydbname;
  462. if (zend_get_parameters_ex(5, &yyhost, &yyport, &yyoptions, &yytty, &yydbname) == FAILURE) {
  463. RETURN_FALSE;
  464. }
  465. convert_to_string_ex(yyhost);
  466. convert_to_string_ex(yyport);
  467. convert_to_string_ex(yyoptions);
  468. convert_to_string_ex(yytty);
  469. convert_to_string_ex(yydbname);
  470. host = Z_STRVAL_PP(yyhost);
  471. port = Z_STRVAL_PP(yyport);
  472. options = Z_STRVAL_PP(yyoptions);
  473. tty = Z_STRVAL_PP(yytty);
  474. dbname = Z_STRVAL_PP(yydbname);
  475. hashed_details_length = Z_STRLEN_PP(yyhost) + Z_STRLEN_PP(yyport) + Z_STRLEN_PP(yyoptions) + Z_STRLEN_PP(yytty) + Z_STRLEN_PP(yydbname) + 5 + 5;
  476. hashed_details = (char *) emalloc(hashed_details_length+1);
  477. sprintf(hashed_details, "pgsql_%s_%s_%s_%s_%s", host, port, options, tty, dbname); /* SAFE */
  478. }
  479. break;
  480. default:
  481. WRONG_PARAM_COUNT;
  482. break;
  483. }
  484. if (persistent && PGG(allow_persistent)) {
  485. list_entry *le;
  486. /* try to find if we already have this link in our persistent list */
  487. if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) { /* we don't */
  488. list_entry new_le;
  489. if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
  490. php_error(E_WARNING,"%s() cannot create new link. Too many open links (%d)",
  491. get_active_function_name(TSRMLS_C), PGG(num_links));
  492. efree(hashed_details);
  493. RETURN_FALSE;
  494. }
  495. if (PGG(max_persistent)!=-1 && PGG(num_persistent)>=PGG(max_persistent)) {
  496. php_error(E_WARNING,"%s() cannot create new link. Too many open persistent links (%d)",
  497. get_active_function_name(TSRMLS_C), PGG(num_persistent));
  498. efree(hashed_details);
  499. RETURN_FALSE;
  500. }
  501. /* create the link */
  502. if (connstring) {
  503. pgsql=PQconnectdb(connstring);
  504. } else {
  505. pgsql=PQsetdb(host,port,options,tty,dbname);
  506. }
  507. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  508. php_error(E_WARNING,"%s() unable to connect to PostgreSQL server: %s",
  509. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  510. if (pgsql) {
  511. PQfinish(pgsql);
  512. }
  513. efree(hashed_details);
  514. RETURN_FALSE;
  515. }
  516. /* hash it up */
  517. Z_TYPE(new_le) = le_plink;
  518. new_le.ptr = pgsql;
  519. if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(list_entry), NULL)==FAILURE) {
  520. efree(hashed_details);
  521. RETURN_FALSE;
  522. }
  523. PGG(num_links)++;
  524. PGG(num_persistent)++;
  525. } else { /* we do */
  526. if (Z_TYPE_P(le) != le_plink) {
  527. RETURN_FALSE;
  528. }
  529. /* ensure that the link did not die */
  530. if (PGG(auto_reset_persistent)) {
  531. /* need to send & get something from backend to
  532. make sure we catch CONNECTION_BAD everytime */
  533. PGresult *pg_result;
  534. pg_result = PQexec(le->ptr, "select 1");
  535. PQclear(pg_result);
  536. }
  537. if (PQstatus(le->ptr)==CONNECTION_BAD) { /* the link died */
  538. if (le->ptr == NULL) {
  539. if (connstring) {
  540. le->ptr=PQconnectdb(connstring);
  541. } else {
  542. le->ptr=PQsetdb(host,port,options,tty,dbname);
  543. }
  544. }
  545. else {
  546. PQreset(le->ptr);
  547. }
  548. if (le->ptr==NULL || PQstatus(le->ptr)==CONNECTION_BAD) {
  549. php_error(E_WARNING,"%s() PostgreSQL link lost, unable to reconnect",
  550. get_active_function_name(TSRMLS_C));
  551. zend_hash_del(&EG(persistent_list),hashed_details,hashed_details_length+1);
  552. efree(hashed_details);
  553. RETURN_FALSE;
  554. }
  555. }
  556. pgsql = (PGconn *) le->ptr;
  557. }
  558. ZEND_REGISTER_RESOURCE(return_value, pgsql, le_plink);
  559. } else {
  560. list_entry *index_ptr,new_index_ptr;
  561. /* first we check the hash for the hashed_details key. if it exists,
  562. * it should point us to the right offset where the actual pgsql link sits.
  563. * if it doesn't, open a new pgsql link, add it to the resource list,
  564. * and add a pointer to it with hashed_details as the key.
  565. */
  566. if (zend_hash_find(&EG(regular_list),hashed_details,hashed_details_length+1,(void **) &index_ptr)==SUCCESS) {
  567. int type,link;
  568. void *ptr;
  569. if (Z_TYPE_P(index_ptr) != le_index_ptr) {
  570. RETURN_FALSE;
  571. }
  572. link = (int) (long) index_ptr->ptr;
  573. ptr = zend_list_find(link,&type); /* check if the link is still there */
  574. if (ptr && (type==le_link || type==le_plink)) {
  575. Z_LVAL_P(return_value) = link;
  576. zend_list_addref(link);
  577. php_pgsql_set_default_link(link TSRMLS_CC);
  578. Z_TYPE_P(return_value) = IS_RESOURCE;
  579. efree(hashed_details);
  580. return;
  581. } else {
  582. zend_hash_del(&EG(regular_list),hashed_details,hashed_details_length+1);
  583. }
  584. }
  585. if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
  586. php_error(E_WARNING,"%s() cannot create new link. Too many open links (%d)",
  587. get_active_function_name(TSRMLS_C), PGG(num_links));
  588. efree(hashed_details);
  589. RETURN_FALSE;
  590. }
  591. if (connstring) {
  592. pgsql = PQconnectdb(connstring);
  593. } else {
  594. pgsql = PQsetdb(host,port,options,tty,dbname);
  595. }
  596. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  597. php_error(E_WARNING,"%s() unable to connect to PostgreSQL server: %s",
  598. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  599. efree(hashed_details);
  600. RETURN_FALSE;
  601. }
  602. /* add it to the list */
  603. ZEND_REGISTER_RESOURCE(return_value, pgsql, le_link);
  604. /* add it to the hash */
  605. new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
  606. Z_TYPE(new_index_ptr) = le_index_ptr;
  607. if (zend_hash_update(&EG(regular_list),hashed_details,hashed_details_length+1,(void *) &new_index_ptr, sizeof(list_entry), NULL)==FAILURE) {
  608. efree(hashed_details);
  609. RETURN_FALSE;
  610. }
  611. PGG(num_links)++;
  612. }
  613. /* set notice processer */
  614. if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
  615. PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void *)&Z_RESVAL_P(return_value));
  616. }
  617. efree(hashed_details);
  618. php_pgsql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
  619. }
  620. /* }}} */
  621. #if 0
  622. /* {{{ php_pgsql_get_default_link
  623. */
  624. static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
  625. {
  626. if (PGG(default_link)==-1) { /* no link opened yet, implicitly open one */
  627. ht = 0;
  628. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
  629. }
  630. return PGG(default_link);
  631. }
  632. /* }}} */
  633. #endif
  634. /* {{{ proto resource pg_connect([string connection_string] | [string host, string port [, string options [, string tty,]] string database)
  635. Open a PostgreSQL connection */
  636. PHP_FUNCTION(pg_connect)
  637. {
  638. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
  639. }
  640. /* }}} */
  641. /* {{{ proto resource pg_pconnect([string connection_string] | [string host, string port [, string options [, string tty,]] string database)
  642. Open a persistent PostgreSQL connection */
  643. PHP_FUNCTION(pg_pconnect)
  644. {
  645. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
  646. }
  647. /* }}} */
  648. /* {{{ proto bool pg_close([resource connection])
  649. Close a PostgreSQL connection */
  650. PHP_FUNCTION(pg_close)
  651. {
  652. zval **pgsql_link = NULL;
  653. int id;
  654. PGconn *pgsql;
  655. switch (ZEND_NUM_ARGS()) {
  656. case 0:
  657. id = PGG(default_link);
  658. CHECK_DEFAULT_LINK(id);
  659. break;
  660. case 1:
  661. if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
  662. RETURN_FALSE;
  663. }
  664. id = -1;
  665. break;
  666. default:
  667. WRONG_PARAM_COUNT;
  668. break;
  669. }
  670. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  671. if (id==-1) { /* explicit resource number */
  672. zend_list_delete(Z_RESVAL_PP(pgsql_link));
  673. }
  674. if (id!=-1
  675. || (pgsql_link && Z_RESVAL_PP(pgsql_link)==PGG(default_link))) {
  676. zend_list_delete(PGG(default_link));
  677. PGG(default_link) = -1;
  678. }
  679. RETURN_TRUE;
  680. }
  681. /* }}} */
  682. #define PHP_PG_DBNAME 1
  683. #define PHP_PG_ERROR_MESSAGE 2
  684. #define PHP_PG_OPTIONS 3
  685. #define PHP_PG_PORT 4
  686. #define PHP_PG_TTY 5
  687. #define PHP_PG_HOST 6
  688. /* {{{ php_pgsql_get_link_info
  689. */
  690. static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  691. {
  692. zval **pgsql_link = NULL;
  693. int id = -1;
  694. PGconn *pgsql;
  695. switch(ZEND_NUM_ARGS()) {
  696. case 0:
  697. id = PGG(default_link);
  698. CHECK_DEFAULT_LINK(id);
  699. break;
  700. case 1:
  701. if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
  702. RETURN_FALSE;
  703. }
  704. break;
  705. default:
  706. WRONG_PARAM_COUNT;
  707. break;
  708. }
  709. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  710. switch(entry_type) {
  711. case PHP_PG_DBNAME:
  712. Z_STRVAL_P(return_value) = PQdb(pgsql);
  713. break;
  714. case PHP_PG_ERROR_MESSAGE:
  715. Z_STRVAL_P(return_value) = PQerrorMessage(pgsql);
  716. break;
  717. case PHP_PG_OPTIONS:
  718. Z_STRVAL_P(return_value) = PQoptions(pgsql);
  719. break;
  720. case PHP_PG_PORT:
  721. Z_STRVAL_P(return_value) = PQport(pgsql);
  722. break;
  723. case PHP_PG_TTY:
  724. Z_STRVAL_P(return_value) = PQtty(pgsql);
  725. break;
  726. case PHP_PG_HOST:
  727. Z_STRVAL_P(return_value) = PQhost(pgsql);
  728. break;
  729. default:
  730. RETURN_FALSE;
  731. }
  732. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  733. Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
  734. Z_TYPE_P(return_value) = IS_STRING;
  735. }
  736. /* }}} */
  737. /* {{{ proto string pg_dbname([resource connection])
  738. Get the database name */
  739. PHP_FUNCTION(pg_dbname)
  740. {
  741. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
  742. }
  743. /* }}} */
  744. /* {{{ proto string pg_last_error([resource connection])
  745. Get the error message string */
  746. PHP_FUNCTION(pg_last_error)
  747. {
  748. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
  749. }
  750. /* }}} */
  751. /* {{{ proto string pg_options([resource connection])
  752. Get the options associated with the connection */
  753. PHP_FUNCTION(pg_options)
  754. {
  755. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
  756. }
  757. /* }}} */
  758. /* {{{ proto int pg_port([resource connection])
  759. Return the port number associated with the connection */
  760. PHP_FUNCTION(pg_port)
  761. {
  762. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
  763. }
  764. /* }}} */
  765. /* {{{ proto string pg_tty([resource connection])
  766. Return the tty name associated with the connection */
  767. PHP_FUNCTION(pg_tty)
  768. {
  769. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
  770. }
  771. /* }}} */
  772. /* {{{ proto string pg_host([resource connection])
  773. Returns the host name associated with the connection */
  774. PHP_FUNCTION(pg_host)
  775. {
  776. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
  777. }
  778. /* }}} */
  779. /* {{{ proto resource pg_query([resource connection,] string query)
  780. Execute a query */
  781. PHP_FUNCTION(pg_query)
  782. {
  783. zval **query, **pgsql_link = NULL;
  784. int id = -1;
  785. int leftover = 0;
  786. PGconn *pgsql;
  787. PGresult *pgsql_result;
  788. ExecStatusType status;
  789. pgsql_result_handle *pg_result;
  790. switch(ZEND_NUM_ARGS()) {
  791. case 1:
  792. if (zend_get_parameters_ex(1, &query)==FAILURE) {
  793. RETURN_FALSE;
  794. }
  795. id = PGG(default_link);
  796. CHECK_DEFAULT_LINK(id);
  797. break;
  798. case 2:
  799. if (zend_get_parameters_ex(2, &pgsql_link, &query)==FAILURE) {
  800. RETURN_FALSE;
  801. }
  802. break;
  803. default:
  804. WRONG_PARAM_COUNT;
  805. break;
  806. }
  807. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  808. convert_to_string_ex(query);
  809. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  810. php_error(E_NOTICE,"%s() cannot set connection to blocking mode",
  811. get_active_function_name(TSRMLS_C));
  812. RETURN_FALSE;
  813. }
  814. while ((pgsql_result = PQgetResult(pgsql))) {
  815. PQclear(pgsql_result);
  816. leftover = 1;
  817. }
  818. if (leftover) {
  819. php_error(E_NOTICE,"%s() found results on this connection. Use pg_get_result() to get results",
  820. get_active_function_name(TSRMLS_C));
  821. }
  822. pgsql_result = PQexec(pgsql, Z_STRVAL_PP(query));
  823. if (pgsql_result) {
  824. status = PQresultStatus(pgsql_result);
  825. } else {
  826. status = (ExecStatusType) PQstatus(pgsql);
  827. }
  828. switch (status) {
  829. case PGRES_EMPTY_QUERY:
  830. case PGRES_BAD_RESPONSE:
  831. case PGRES_NONFATAL_ERROR:
  832. case PGRES_FATAL_ERROR:
  833. php_error(E_WARNING, "%s() query failed: %s",
  834. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  835. RETURN_FALSE;
  836. break;
  837. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  838. default:
  839. if (pgsql_result) {
  840. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  841. pg_result->conn = pgsql;
  842. pg_result->result = pgsql_result;
  843. pg_result->row = -1;
  844. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  845. } else {
  846. RETURN_FALSE;
  847. }
  848. break;
  849. }
  850. }
  851. /* }}} */
  852. #define PHP_PG_NUM_ROWS 1
  853. #define PHP_PG_NUM_FIELDS 2
  854. #define PHP_PG_CMD_TUPLES 3
  855. /* {{{ php_pgsql_get_result_info
  856. */
  857. static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  858. {
  859. zval **result;
  860. PGresult *pgsql_result;
  861. pgsql_result_handle *pg_result;
  862. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result)==FAILURE) {
  863. WRONG_PARAM_COUNT;
  864. }
  865. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  866. pgsql_result = pg_result->result;
  867. switch (entry_type) {
  868. case PHP_PG_NUM_ROWS:
  869. Z_LVAL_P(return_value) = PQntuples(pgsql_result);
  870. break;
  871. case PHP_PG_NUM_FIELDS:
  872. Z_LVAL_P(return_value) = PQnfields(pgsql_result);
  873. break;
  874. case PHP_PG_CMD_TUPLES:
  875. #if HAVE_PQCMDTUPLES
  876. Z_LVAL_P(return_value) = atoi(PQcmdTuples(pgsql_result));
  877. #else
  878. php_error(E_WARNING,"This compilation does not support %s()",
  879. get_active_function_name(TSRMLS_C));
  880. Z_LVAL_P(return_value) = 0;
  881. #endif
  882. break;
  883. default:
  884. RETURN_FALSE;
  885. }
  886. Z_TYPE_P(return_value) = IS_LONG;
  887. }
  888. /* }}} */
  889. /* {{{ proto int pg_num_rows(resource result)
  890. Return the number of rows in the result */
  891. PHP_FUNCTION(pg_num_rows)
  892. {
  893. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
  894. }
  895. /* }}} */
  896. /* {{{ proto int pg_num_fields(resource result)
  897. Return the number of fields in the result */
  898. PHP_FUNCTION(pg_num_fields)
  899. {
  900. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
  901. }
  902. /* }}} */
  903. /* {{{ proto int pg_affected_rows(resource result)
  904. Returns the number of affected tuples */
  905. PHP_FUNCTION(pg_affected_rows)
  906. {
  907. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
  908. }
  909. /* }}} */
  910. /* {{{ proto string pg_last_notice(resource connection)
  911. Returns the last notice set by the backend */
  912. PHP_FUNCTION(pg_last_notice)
  913. {
  914. zval *pgsql_link;
  915. PGconn *pg_link;
  916. int id = -1;
  917. php_pgsql_notice **notice;
  918. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
  919. &pgsql_link) == FAILURE) {
  920. return;
  921. }
  922. /* Just to check if user passed valid resoruce */
  923. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  924. if (zend_hash_index_find(&PGG(notices), Z_RESVAL_P(pgsql_link), (void **)&notice) == FAILURE) {
  925. RETURN_FALSE;
  926. }
  927. RETURN_STRINGL((*notice)->message, (*notice)->len, 1);
  928. }
  929. /* }}} */
  930. /* {{{ get_field_name
  931. */
  932. static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list TSRMLS_DC)
  933. {
  934. PGresult *result;
  935. char hashed_oid_key[32];
  936. list_entry *field_type;
  937. char *ret=NULL;
  938. /* try to lookup the type in the resource list */
  939. snprintf(hashed_oid_key,31,"pgsql_oid_%d",(int) oid);
  940. hashed_oid_key[31]=0;
  941. if (zend_hash_find(list,hashed_oid_key,strlen(hashed_oid_key)+1,(void **) &field_type)==SUCCESS) {
  942. ret = estrdup((char *)field_type->ptr);
  943. } else { /* hash all oid's */
  944. int i,num_rows;
  945. int oid_offset,name_offset;
  946. char *tmp_oid, *tmp_name;
  947. list_entry new_oid_entry;
  948. if ((result = PQexec(pgsql,"select oid,typname from pg_type")) == NULL) {
  949. return empty_string;
  950. }
  951. num_rows = PQntuples(result);
  952. oid_offset = PQfnumber(result,"oid");
  953. name_offset = PQfnumber(result,"typname");
  954. for (i=0; i<num_rows; i++) {
  955. if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
  956. continue;
  957. }
  958. snprintf(hashed_oid_key,31,"pgsql_oid_%s",tmp_oid);
  959. if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
  960. continue;
  961. }
  962. Z_TYPE(new_oid_entry) = le_string;
  963. new_oid_entry.ptr = estrdup(tmp_name);
  964. zend_hash_update(list,hashed_oid_key,strlen(hashed_oid_key)+1,(void *) &new_oid_entry, sizeof(list_entry), NULL);
  965. if (!ret && atoi(tmp_oid)==oid) {
  966. ret = estrdup(tmp_name);
  967. }
  968. }
  969. }
  970. return ret;
  971. }
  972. /* }}} */
  973. #define PHP_PG_FIELD_NAME 1
  974. #define PHP_PG_FIELD_SIZE 2
  975. #define PHP_PG_FIELD_TYPE 3
  976. /* {{{ php_pgsql_get_field_info
  977. */
  978. static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  979. {
  980. zval **result, **field;
  981. PGresult *pgsql_result;
  982. pgsql_result_handle *pg_result;
  983. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE) {
  984. WRONG_PARAM_COUNT;
  985. }
  986. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  987. pgsql_result = pg_result->result;
  988. convert_to_long_ex(field);
  989. if (Z_LVAL_PP(field) < 0 || Z_LVAL_PP(field) >= PQnfields(pgsql_result)) {
  990. php_error(E_WARNING,"%s() bad field offset specified",
  991. get_active_function_name(TSRMLS_C));
  992. RETURN_FALSE;
  993. }
  994. switch (entry_type) {
  995. case PHP_PG_FIELD_NAME:
  996. Z_STRVAL_P(return_value) = PQfname(pgsql_result, Z_LVAL_PP(field));
  997. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  998. Z_STRVAL_P(return_value) = estrndup(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value));
  999. Z_TYPE_P(return_value) = IS_STRING;
  1000. break;
  1001. case PHP_PG_FIELD_SIZE:
  1002. Z_LVAL_P(return_value) = PQfsize(pgsql_result, Z_LVAL_PP(field));
  1003. Z_TYPE_P(return_value) = IS_LONG;
  1004. break;
  1005. case PHP_PG_FIELD_TYPE:
  1006. Z_STRVAL_P(return_value) = get_field_name(pg_result->conn, PQftype(pgsql_result, Z_LVAL_PP(field)), &EG(regular_list) TSRMLS_CC);
  1007. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  1008. Z_TYPE_P(return_value) = IS_STRING;
  1009. break;
  1010. default:
  1011. RETURN_FALSE;
  1012. }
  1013. }
  1014. /* }}} */
  1015. /* {{{ proto string pg_field_name(resource result, int field_number)
  1016. Returns the name of the field */
  1017. PHP_FUNCTION(pg_field_name)
  1018. {
  1019. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
  1020. }
  1021. /* }}} */
  1022. /* {{{ proto int pg_field_size(resource result, int field_number)
  1023. Returns the internal size of the field */
  1024. PHP_FUNCTION(pg_field_size)
  1025. {
  1026. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
  1027. }
  1028. /* }}} */
  1029. /* {{{ proto string pg_field_type(resource result, int field_number)
  1030. Returns the type name for the given field */
  1031. PHP_FUNCTION(pg_field_type)
  1032. {
  1033. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
  1034. }
  1035. /* }}} */
  1036. /* {{{ proto int pg_field_num(resource result, string field_name)
  1037. Returns the field number of the named field */
  1038. PHP_FUNCTION(pg_field_num)
  1039. {
  1040. zval **result, **field;
  1041. PGresult *pgsql_result;
  1042. pgsql_result_handle *pg_result;
  1043. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE) {
  1044. WRONG_PARAM_COUNT;
  1045. }
  1046. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  1047. pgsql_result = pg_result->result;
  1048. convert_to_string_ex(field);
  1049. Z_LVAL_P(return_value) = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
  1050. Z_TYPE_P(return_value) = IS_LONG;
  1051. }
  1052. /* }}} */
  1053. /* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
  1054. Returns values from a result identifier */
  1055. PHP_FUNCTION(pg_fetch_result)
  1056. {
  1057. zval **result, **row, **field=NULL;
  1058. PGresult *pgsql_result;
  1059. pgsql_result_handle *pg_result;
  1060. int field_offset, pgsql_row;
  1061. if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row, &field)==FAILURE) &&
  1062. (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE)) {
  1063. WRONG_PARAM_COUNT;
  1064. }
  1065. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  1066. pgsql_result = pg_result->result;
  1067. if (ZEND_NUM_ARGS() == 2) {
  1068. if (pg_result->row < 0)
  1069. pg_result->row = 0;
  1070. pgsql_row = pg_result->row;
  1071. if (pgsql_row >= PQntuples(pgsql_result)) {
  1072. RETURN_FALSE;
  1073. }
  1074. } else {
  1075. convert_to_long_ex(row);
  1076. pgsql_row = Z_LVAL_PP(row);
  1077. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  1078. php_error(E_WARNING,"%s() unable to jump to row %d on PostgreSQL result index %d",
  1079. get_active_function_name(TSRMLS_C), Z_LVAL_PP(row), Z_LVAL_PP(result));
  1080. RETURN_FALSE;
  1081. }
  1082. }
  1083. switch(Z_TYPE_PP(field)) {
  1084. case IS_STRING:
  1085. field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
  1086. break;
  1087. default:
  1088. convert_to_long_ex(field);
  1089. field_offset = Z_LVAL_PP(field);
  1090. break;
  1091. }
  1092. if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) {
  1093. php_error(E_WARNING,"%s() bad column offset specified",
  1094. get_active_function_name(TSRMLS_C));
  1095. RETURN_FALSE;
  1096. }
  1097. if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
  1098. Z_TYPE_P(return_value) = IS_NULL;
  1099. } else {
  1100. Z_STRVAL_P(return_value) = PQgetvalue(pgsql_result, pgsql_row, field_offset);
  1101. Z_STRLEN_P(return_value) = (Z_STRVAL_P(return_value) ? strlen(Z_STRVAL_P(return_value)) : 0);
  1102. Z_STRVAL_P(return_value) = safe_estrndup(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value));
  1103. Z_TYPE_P(return_value) = IS_STRING;
  1104. }
  1105. }
  1106. /* }}} */
  1107. /* {{{ void php_pgsql_fetch_hash */
  1108. static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
  1109. {
  1110. zval **result, **row, **arg3;
  1111. PGresult *pgsql_result;
  1112. pgsql_result_handle *pg_result;
  1113. int i, num_fields, pgsql_row;
  1114. char *element, *field_name;
  1115. uint element_len;
  1116. switch (ZEND_NUM_ARGS()) {
  1117. case 1:
  1118. if (zend_get_parameters_ex(1, &result) == FAILURE) {
  1119. RETURN_FALSE;
  1120. }
  1121. if (!result_type) {
  1122. result_type = PGSQL_BOTH;
  1123. }
  1124. break;
  1125. case 2:
  1126. if (zend_get_parameters_ex(2, &result, &row) == FAILURE) {
  1127. RETURN_FALSE;
  1128. }
  1129. if (!result_type) {
  1130. result_type = PGSQL_BOTH;
  1131. }
  1132. break;
  1133. case 3:
  1134. if (zend_get_parameters_ex(3, &result, &row, &arg3) == FAILURE) {
  1135. RETURN_FALSE;
  1136. }
  1137. convert_to_long_ex(arg3);
  1138. result_type = Z_LVAL_PP(arg3);
  1139. break;
  1140. default:
  1141. WRONG_PARAM_COUNT;
  1142. break;
  1143. }
  1144. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  1145. pgsql_result = pg_result->result;
  1146. if (ZEND_NUM_ARGS() == 1) {
  1147. pg_result->row++;
  1148. pgsql_row = pg_result->row;
  1149. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  1150. RETURN_FALSE;
  1151. }
  1152. } else {
  1153. if (Z_TYPE_PP(row) != IS_NULL) {
  1154. convert_to_long_ex(row);
  1155. pgsql_row = Z_LVAL_PP(row);
  1156. pg_result->row = pgsql_row;
  1157. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  1158. php_error(E_WARNING, "%s() unable to jump to row %d on PostgreSQL result index %d",
  1159. get_active_function_name(TSRMLS_C), Z_LVAL_PP(row), Z_LVAL_PP(result));
  1160. RETURN_FALSE;
  1161. }
  1162. } else {
  1163. /* If 2nd param is NULL, ignore it and use the normal way of accessing the next row */
  1164. pg_result->row++;
  1165. pgsql_row = pg_result->row;
  1166. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  1167. RETURN_FALSE;
  1168. }
  1169. }
  1170. }
  1171. array_init(return_value);
  1172. for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
  1173. if (PQgetisnull(pgsql_result, pgsql_row, i)) {
  1174. if (result_type & PGSQL_NUM) {
  1175. add_index_null(return_value, i);
  1176. }
  1177. if (result_type & PGSQL_ASSOC) {
  1178. field_name = PQfname(pgsql_result, i);
  1179. add_assoc_null(return_value, field_name);
  1180. }
  1181. } else {
  1182. element = PQgetvalue(pgsql_result, pgsql_row, i);
  1183. element_len = (element ? strlen(element) : 0);
  1184. if (element) {
  1185. char *data;
  1186. int data_len;
  1187. int should_copy=0;
  1188. if (PG(magic_quotes_runtime)) {
  1189. data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
  1190. } else {
  1191. data = safe_estrndup(element, element_len);
  1192. data_len = element_len;
  1193. }
  1194. if (result_type & PGSQL_NUM) {
  1195. add_index_stringl(return_value, i, data, data_len, should_copy);
  1196. should_copy=1;
  1197. }
  1198. if (result_type & PGSQL_ASSOC) {
  1199. field_name = PQfname(pgsql_result, i);
  1200. add_assoc_stringl(return_value, field_name, data, data_len, should_copy);
  1201. }
  1202. }
  1203. }
  1204. }
  1205. }
  1206. /* }}} */
  1207. /* {{{ proto array pg_fetch_row(resource result [, int row])
  1208. Get a row as an enumerated array */
  1209. PHP_FUNCTION(pg_fetch_row)
  1210. {
  1211. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM);
  1212. }
  1213. /* }}} */
  1214. /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
  1215. Fetch a row as an array */
  1216. PHP_FUNCTION(pg_fetch_array)
  1217. {
  1218. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  1219. }
  1220. /* }}} */
  1221. /* {{{ proto object pg_fetch_object(resource result [, int row [, int result_type]])
  1222. Fetch a row as an object */
  1223. PHP_FUNCTION(pg_fetch_object)
  1224. {
  1225. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  1226. if (Z_TYPE_P(return_value)==IS_ARRAY) {
  1227. object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
  1228. }
  1229. }
  1230. /* }}} */
  1231. #define PHP_PG_DATA_LENGTH 1
  1232. #define PHP_PG_DATA_ISNULL 2
  1233. /* {{{ php_pgsql_data_info
  1234. */
  1235. static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  1236. {
  1237. zval **result, **row, **field;
  1238. PGresult *pgsql_result;
  1239. pgsql_result_handle *pg_result;
  1240. int field_offset, pgsql_row;
  1241. if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row, &field)==FAILURE) &&
  1242. (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE)) {
  1243. WRONG_PARAM_COUNT;
  1244. }
  1245. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  1246. pgsql_result = pg_result->result;
  1247. if (ZEND_NUM_ARGS() == 2) {
  1248. if (pg_result->row < 0)
  1249. pg_result->row = 0;
  1250. pgsql_row = pg_result->row;
  1251. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  1252. RETURN_FALSE;
  1253. }
  1254. } else {
  1255. convert_to_long_ex(row);
  1256. pgsql_row = Z_LVAL_PP(row);
  1257. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  1258. php_error(E_WARNING,"%s() unable to jump to row %d on PostgreSQL result index %d",
  1259. get_active_function_name(TSRMLS_C), Z_LVAL_PP(row), Z_LVAL_PP(result));
  1260. RETURN_FALSE;
  1261. }
  1262. }
  1263. switch(Z_TYPE_PP(field)) {
  1264. case IS_STRING:
  1265. convert_to_string_ex(field);
  1266. field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
  1267. break;
  1268. default:
  1269. convert_to_long_ex(field);
  1270. field_offset = Z_LVAL_PP(field);
  1271. break;
  1272. }
  1273. if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
  1274. php_error(E_WARNING, "%s() bad column offset specified",
  1275. get_active_function_name(TSRMLS_C));
  1276. RETURN_FALSE;
  1277. }
  1278. switch (entry_type) {
  1279. case PHP_PG_DATA_LENGTH:
  1280. Z_LVAL_P(return_value) = PQgetlength(pgsql_result, pgsql_row, field_offset);
  1281. break;
  1282. case PHP_PG_DATA_ISNULL:
  1283. Z_LVAL_P(return_value) = PQgetisnull(pgsql_result, pgsql_row, field_offset);
  1284. break;
  1285. }
  1286. Z_TYPE_P(return_value) = IS_LONG;
  1287. }
  1288. /* }}} */
  1289. /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
  1290. Returns the printed length */
  1291. PHP_FUNCTION(pg_field_prtlen)
  1292. {
  1293. php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
  1294. }
  1295. /* }}} */
  1296. /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
  1297. Test if a field is NULL */
  1298. PHP_FUNCTION(pg_field_is_null)
  1299. {
  1300. php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
  1301. }
  1302. /* }}} */
  1303. /* {{{ proto bool pg_free_result(resource result)
  1304. Free result memory */
  1305. PHP_FUNCTION(pg_free_result)
  1306. {
  1307. zval **result;
  1308. pgsql_result_handle *pg_result;
  1309. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result)==FAILURE) {
  1310. WRONG_PARAM_COUNT;
  1311. }
  1312. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  1313. if (Z_LVAL_PP(result) == 0) {
  1314. RETURN_FALSE;
  1315. }
  1316. zend_list_delete(Z_LVAL_PP(result));
  1317. RETURN_TRUE;
  1318. }
  1319. /* }}} */
  1320. /* {{{ proto int pg_last_oid(resource result)
  1321. Returns the last object identifier */
  1322. PHP_FUNCTION(pg_last_oid)
  1323. {
  1324. zval **result;
  1325. PGresult *pgsql_result;
  1326. pgsql_result_handle *pg_result;
  1327. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result)==FAILURE) {
  1328. WRONG_PARAM_COUNT;
  1329. }
  1330. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
  1331. pgsql_result = pg_result->result;
  1332. #ifdef HAVE_PQOIDVALUE
  1333. Z_LVAL_P(return_value) = (int) PQoidValue(pgsql_result);
  1334. if (Z_LVAL_P(return_value) == InvalidOid) {
  1335. RETURN_FALSE;
  1336. } else {
  1337. Z_TYPE_P(return_value) = IS_LONG;
  1338. }
  1339. #else
  1340. Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
  1341. if (Z_STRVAL_P(return_value)) {
  1342. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  1343. Z_STRVAL_P(return_value) = estrndup(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
  1344. Z_TYPE_P(return_value) = IS_STRING;
  1345. } else {
  1346. Z_STRVAL_P(return_value) = empty_string;
  1347. }
  1348. #endif
  1349. }
  1350. /* }}} */
  1351. /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
  1352. Enable tracing a PostgreSQL connection */
  1353. PHP_FUNCTION(pg_trace)
  1354. {
  1355. zval **z_filename, **z_mode, **z_pgsql_link = NULL;
  1356. int id = -1;
  1357. PGconn *pgsql;
  1358. char *mode = "w";
  1359. FILE *fp = NULL;
  1360. php_stream *stream;
  1361. id = PGG(default_link);
  1362. switch (ZEND_NUM_ARGS()) {
  1363. case 1:
  1364. if (zend_get_parameters_ex(1, &z_filename)==FAILURE) {
  1365. RETURN_FALSE;
  1366. }
  1367. CHECK_DEFAULT_LINK(id);
  1368. break;
  1369. case 2:
  1370. if (zend_get_parameters_ex(2, &z_filename, &z_mode)==FAILURE) {
  1371. RETURN_FALSE;
  1372. }
  1373. CHECK_DEFAULT_LINK(id);
  1374. convert_to_string_ex(z_mode);
  1375. mode = Z_STRVAL_PP(z_mode);
  1376. break;
  1377. case 3:
  1378. if (zend_get_parameters_ex(3, &z_filename, &z_mode, &z_pgsql_link)==FAILURE) {
  1379. RETURN_FALSE;
  1380. }
  1381. convert_to_string_ex(z_mode);
  1382. mode = Z_STRVAL_PP(z_mode);
  1383. break;
  1384. default:
  1385. ZEND_WRONG_PARAM_COUNT();
  1386. break;
  1387. }
  1388. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, z_pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1389. convert_to_string_ex(z_filename);
  1390. stream = php_stream_open_wrapper(Z_STRVAL_PP(z_filename), mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
  1391. if (!stream) {
  1392. RETURN_FALSE;
  1393. }
  1394. if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)fp, REPORT_ERRORS)) {
  1395. php_stream_close(stream);
  1396. RETURN_FALSE;
  1397. }
  1398. php_stream_auto_cleanup(stream);
  1399. PQtrace(pgsql, fp);
  1400. RETURN_TRUE;
  1401. }
  1402. /* }}} */
  1403. /* {{{ proto bool pg_untrace([resource connection])
  1404. Disable tracing of a PostgreSQL connection */
  1405. PHP_FUNCTION(pg_untrace)
  1406. {
  1407. zval **pgsql_link = NULL;
  1408. int id = -1;
  1409. PGconn *pgsql;
  1410. switch (ZEND_NUM_ARGS()) {
  1411. case 0:
  1412. id = PGG(default_link);
  1413. CHECK_DEFAULT_LINK(id);
  1414. break;
  1415. case 1:
  1416. if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
  1417. RETURN_FALSE;
  1418. }
  1419. break;
  1420. default:
  1421. ZEND_WRONG_PARAM_COUNT();
  1422. break;
  1423. }
  1424. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1425. PQuntrace(pgsql);
  1426. RETURN_TRUE;
  1427. }
  1428. /* }}} */
  1429. /* {{{ proto int pg_lo_create(resource connection)
  1430. Create a large object */
  1431. PHP_FUNCTION(pg_lo_create)
  1432. {
  1433. zval **pgsql_link = NULL;
  1434. PGconn *pgsql;
  1435. Oid pgsql_oid;
  1436. int id = -1;
  1437. switch(ZEND_NUM_ARGS()) {
  1438. case 0:
  1439. id = PGG(default_link);
  1440. CHECK_DEFAULT_LINK(id);
  1441. break;
  1442. case 1:
  1443. if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
  1444. RETURN_FALSE;
  1445. }
  1446. break;
  1447. default:
  1448. WRONG_PARAM_COUNT;
  1449. break;
  1450. }
  1451. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1452. /* XXX: Archive modes not supported until I get some more data. Don't think anybody's
  1453. using it anyway. I believe it's also somehow related to the 'time travel' feature of
  1454. PostgreSQL, that's on the list of features to be removed... Create modes not supported.
  1455. What's the use of an object that can be only written to, but not read from, and vice
  1456. versa? Beats me... And the access type (r/w) must be specified again when opening
  1457. the object, probably (?) overrides this. (Jouni)
  1458. */
  1459. if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE))==0) {
  1460. php_error(E_WARNING, "%s() unable to create PostgreSQL large object",
  1461. get_active_function_name(TSRMLS_C));
  1462. RETURN_FALSE;
  1463. }
  1464. Z_LVAL_P(return_value) = pgsql_oid;
  1465. Z_TYPE_P(return_value) = IS_LONG;
  1466. }
  1467. /* }}} */
  1468. /* {{{ proto bool pg_lo_unlink([resource connection,] int large_object_oid)
  1469. Delete a large object */
  1470. PHP_FUNCTION(pg_lo_unlink)
  1471. {
  1472. zval **pgsql_link = NULL, **oid;
  1473. PGconn *pgsql;
  1474. Oid pgsql_oid;
  1475. int id = -1;
  1476. switch(ZEND_NUM_ARGS()) {
  1477. case 1:
  1478. if (zend_get_parameters_ex(1, &oid)==FAILURE) {
  1479. RETURN_FALSE;
  1480. }
  1481. convert_to_long_ex(oid);
  1482. pgsql_oid = Z_LVAL_PP(oid);
  1483. id = PGG(default_link);
  1484. CHECK_DEFAULT_LINK(id);
  1485. break;
  1486. case 2:
  1487. if (zend_get_parameters_ex(2, &pgsql_link, &oid)==FAILURE) {
  1488. RETURN_FALSE;
  1489. }
  1490. convert_to_long_ex(oid);
  1491. pgsql_oid = Z_LVAL_PP(oid);
  1492. break;
  1493. default:
  1494. WRONG_PARAM_COUNT;
  1495. break;
  1496. }
  1497. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1498. if (lo_unlink(pgsql, pgsql_oid) == -1) {
  1499. php_error(E_WARNING, "%s() unable to delete PostgreSQL large object %d",
  1500. get_active_function_name(TSRMLS_C), (int) pgsql_oid);
  1501. RETURN_FALSE;
  1502. }
  1503. RETURN_TRUE;
  1504. }
  1505. /* }}} */
  1506. /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
  1507. Open a large object and return fd */
  1508. PHP_FUNCTION(pg_lo_open)
  1509. {
  1510. zval **pgsql_link = NULL, **oid, **mode;
  1511. PGconn *pgsql;
  1512. Oid pgsql_oid;
  1513. int id = -1, pgsql_mode=0, pgsql_lofd;
  1514. int create=0;
  1515. char *mode_string=NULL;
  1516. pgLofp *pgsql_lofp;
  1517. switch(ZEND_NUM_ARGS()) {
  1518. case 2:
  1519. if (zend_get_parameters_ex(2, &oid, &mode)==FAILURE) {
  1520. RETURN_FALSE;
  1521. }
  1522. convert_to_long_ex(oid);
  1523. pgsql_oid = Z_LVAL_PP(oid);
  1524. convert_to_string_ex(mode);
  1525. mode_string = Z_STRVAL_PP(mode);
  1526. id = PGG(default_link);
  1527. CHECK_DEFAULT_LINK(id);
  1528. break;
  1529. case 3:
  1530. if (zend_get_parameters_ex(3, &pgsql_link, &oid, &mode)==FAILURE) {
  1531. RETURN_FALSE;
  1532. }
  1533. convert_to_long_ex(oid);
  1534. pgsql_oid = Z_LVAL_PP(oid);
  1535. convert_to_string_ex(mode);
  1536. mode_string = Z_STRVAL_PP(mode);
  1537. break;
  1538. default:
  1539. WRONG_PARAM_COUNT;
  1540. break;
  1541. }
  1542. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1543. /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
  1544. faster to type. Unfortunately, doesn't behave the same way as fopen()...
  1545. (Jouni)
  1546. */
  1547. if (strchr(mode_string, 'r') == mode_string) {
  1548. pgsql_mode |= INV_READ;
  1549. if (strchr(mode_string, '+') == mode_string+1) {
  1550. pgsql_mode |= INV_WRITE;
  1551. }
  1552. }
  1553. if (strchr(mode_string, 'w') == mode_string) {
  1554. pgsql_mode |= INV_WRITE;
  1555. create = 1;
  1556. if (strchr(mode_string, '+') == mode_string+1) {
  1557. pgsql_mode |= INV_READ;
  1558. }
  1559. }
  1560. pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
  1561. if ((pgsql_lofd = lo_open(pgsql, pgsql_oid, pgsql_mode)) == -1) {
  1562. if (create) {
  1563. if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
  1564. efree(pgsql_lofp);
  1565. php_error(E_WARNING, "%s() unable to create PostgreSQL large object",
  1566. get_active_function_name(TSRMLS_C));
  1567. RETURN_FALSE;
  1568. } else {
  1569. if ((pgsql_lofd = lo_open(pgsql, pgsql_oid, pgsql_mode)) == -1) {
  1570. if (lo_unlink(pgsql, pgsql_oid) == -1) {
  1571. efree(pgsql_lofp);
  1572. php_error(E_WARNING, "%s() Something's really messed up!!! Your database is badly corrupted in a way NOT related to PHP",
  1573. get_active_function_name(TSRMLS_C));
  1574. RETURN_FALSE;
  1575. }
  1576. efree(pgsql_lofp);
  1577. php_error(E_WARNING, "%s() unable to open PostgreSQL large object",
  1578. get_active_function_name(TSRMLS_C));
  1579. RETURN_FALSE;
  1580. } else {
  1581. pgsql_lofp->conn = pgsql;
  1582. pgsql_lofp->lofd = pgsql_lofd;
  1583. Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp);
  1584. Z_TYPE_P(return_value) = IS_LONG;
  1585. }
  1586. }
  1587. } else {
  1588. efree(pgsql_lofp);
  1589. php_error(E_WARNING,"%s() unable to open PostgreSQL large object",
  1590. get_active_function_name(TSRMLS_C));
  1591. RETURN_FALSE;
  1592. }
  1593. } else {
  1594. pgsql_lofp->conn = pgsql;
  1595. pgsql_lofp->lofd = pgsql_lofd;
  1596. ZEND_REGISTER_RESOURCE(return_value, pgsql_lofp, le_lofp);
  1597. /*
  1598. Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp);
  1599. Z_TYPE_P(return_value) = IS_LONG;
  1600. */
  1601. }
  1602. }
  1603. /* }}} */
  1604. /* {{{ proto bool pg_lo_close(resource large_object)
  1605. Close a large object */
  1606. PHP_FUNCTION(pg_lo_close)
  1607. {
  1608. zval **pgsql_lofp;
  1609. pgLofp *pgsql;
  1610. switch(ZEND_NUM_ARGS()) {
  1611. case 1:
  1612. if (zend_get_parameters_ex(1, &pgsql_lofp)==FAILURE) {
  1613. RETURN_FALSE;
  1614. }
  1615. break;
  1616. default:
  1617. WRONG_PARAM_COUNT;
  1618. break;
  1619. }
  1620. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_lofp, -1, "PostgreSQL large object", le_lofp);
  1621. if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
  1622. php_error(E_WARNING, "%s() unable to close PostgreSQL large object descriptor %d",
  1623. get_active_function_name(TSRMLS_C), pgsql->lofd);
  1624. RETVAL_FALSE;
  1625. } else {
  1626. RETVAL_TRUE;
  1627. }
  1628. zend_list_delete(Z_LVAL_PP(pgsql_lofp));
  1629. return;
  1630. }
  1631. /* }}} */
  1632. /* {{{ proto string pg_lo_read(resource large_object [, int len])
  1633. Read a large object */
  1634. PHP_FUNCTION(pg_lo_read)
  1635. {
  1636. zval **pgsql_id, **len;
  1637. int buf_len = 1024, nbytes;
  1638. char *buf;
  1639. pgLofp *pgsql;
  1640. if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
  1641. zend_get_parameters_ex(ZEND_NUM_ARGS(), &pgsql_id, &len) == FAILURE) {
  1642. WRONG_PARAM_COUNT;
  1643. }
  1644. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_id, -1, "PostgreSQL large object", le_lofp);
  1645. if (ZEND_NUM_ARGS() > 1) {
  1646. convert_to_long_ex(len);
  1647. buf_len = Z_LVAL_PP(len);
  1648. }
  1649. buf = (char *) emalloc(sizeof(char)*(buf_len+1));
  1650. if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) {
  1651. efree(buf);
  1652. RETURN_FALSE;
  1653. }
  1654. buf[nbytes] = 0;
  1655. RETURN_STRINGL(buf, nbytes, 0);
  1656. }
  1657. /* }}} */
  1658. /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
  1659. Write a large object */
  1660. PHP_FUNCTION(pg_lo_write)
  1661. {
  1662. zval **pgsql_id, **str, **z_len;
  1663. int nbytes;
  1664. int len;
  1665. pgLofp *pgsql;
  1666. int argc = ZEND_NUM_ARGS();
  1667. if (argc < 2 || argc > 3 ||
  1668. zend_get_parameters_ex(argc, &pgsql_id, &str, &z_len) == FAILURE) {
  1669. WRONG_PARAM_COUNT;
  1670. }
  1671. convert_to_string_ex(str);
  1672. if (argc > 2) {
  1673. convert_to_long_ex(z_len);
  1674. len = Z_LVAL_PP(z_len);
  1675. }
  1676. else {
  1677. len = Z_STRLEN_PP(str);
  1678. }
  1679. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_id, -1, "PostgreSQL large object", le_lofp);
  1680. if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, Z_STRVAL_PP(str), len)) == -1) {
  1681. RETURN_FALSE;
  1682. }
  1683. RETURN_LONG(nbytes);
  1684. }
  1685. /* }}} */
  1686. /* {{{ proto int pg_lo_read_all(resource large_object)
  1687. Read a large object and send straight to browser */
  1688. PHP_FUNCTION(pg_lo_read_all)
  1689. {
  1690. zval **pgsql_id;
  1691. int i, tbytes;
  1692. volatile int nbytes;
  1693. char buf[8192];
  1694. pgLofp *pgsql;
  1695. int output=1;
  1696. switch(ZEND_NUM_ARGS()) {
  1697. case 1:
  1698. if (zend_get_parameters_ex(1, &pgsql_id)==FAILURE) {
  1699. RETURN_FALSE;
  1700. }
  1701. break;
  1702. default:
  1703. WRONG_PARAM_COUNT;
  1704. break;
  1705. }
  1706. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_id, -1, "PostgreSQL large object", le_lofp);
  1707. tbytes = 0;
  1708. while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, 8192))>0) {
  1709. for(i=0; i<nbytes; i++) {
  1710. if (output) { (void) PUTC(buf[i]); }
  1711. }
  1712. tbytes += i;
  1713. }
  1714. RETURN_LONG(tbytes);
  1715. }
  1716. /* }}} */
  1717. /* {{{ proto int pg_lo_import([resource connection, ] string filename)
  1718. Import large object direct from filesystem */
  1719. PHP_FUNCTION(pg_lo_import)
  1720. {
  1721. zval *pgsql_link = NULL;
  1722. char *file_in;
  1723. int id = -1, name_len;
  1724. int argc = ZEND_NUM_ARGS();
  1725. PGconn *pgsql;
  1726. Oid oid;
  1727. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  1728. "rs", &pgsql_link, &file_in, &name_len) == SUCCESS) {
  1729. ;
  1730. }
  1731. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  1732. "s", &file_in, &name_len) == SUCCESS) {
  1733. id = PGG(default_link);
  1734. CHECK_DEFAULT_LINK(id);
  1735. }
  1736. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  1737. "rs", &pgsql_link, &file_in, &name_len) == SUCCESS) {
  1738. php_error(E_NOTICE, "Old API for %s() is used.", get_active_function_name(TSRMLS_C));
  1739. }
  1740. else {
  1741. WRONG_PARAM_COUNT;
  1742. }
  1743. if (PG(safe_mode) &&(!php_checkuid(file_in, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
  1744. RETURN_FALSE;
  1745. }
  1746. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1747. oid = lo_import(pgsql, file_in);
  1748. if (oid > 0) {
  1749. RETURN_LONG((int)oid);
  1750. } else {
  1751. RETURN_FALSE;
  1752. }
  1753. }
  1754. /* }}} */
  1755. /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
  1756. Export large object direct to filesystem */
  1757. PHP_FUNCTION(pg_lo_export)
  1758. {
  1759. zval *pgsql_link = NULL;
  1760. char *file_out;
  1761. int id = -1, name_len, oid_id;
  1762. int argc = ZEND_NUM_ARGS();
  1763. Oid oid;
  1764. PGconn *pgsql;
  1765. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  1766. "rls", &pgsql_link, &oid_id, &file_out, &name_len) == SUCCESS) {
  1767. ;
  1768. }
  1769. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  1770. "ls", &oid_id, &file_out, &name_len) == SUCCESS) {
  1771. id = PGG(default_link);
  1772. CHECK_DEFAULT_LINK(id);
  1773. }
  1774. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  1775. "lsr", &oid_id, &file_out, &name_len, &pgsql_link) == SUCCESS) {
  1776. php_error(E_NOTICE, "Old API for %s() is used.", get_active_function_name(TSRMLS_C));
  1777. }
  1778. else {
  1779. WRONG_PARAM_COUNT;
  1780. }
  1781. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1782. oid = (Oid) oid_id;
  1783. if (lo_export(pgsql, oid, file_out)) {
  1784. RETURN_TRUE;
  1785. } else {
  1786. RETURN_FALSE;
  1787. }
  1788. }
  1789. /* }}} */
  1790. /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
  1791. Seeks position of large object */
  1792. PHP_FUNCTION(pg_lo_seek)
  1793. {
  1794. zval *pgsql_id = NULL;
  1795. int offset = 0, whence = SEEK_CUR;
  1796. pgLofp *pgsql;
  1797. int argc = ZEND_NUM_ARGS();
  1798. if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
  1799. return;
  1800. }
  1801. if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
  1802. php_error(E_WARNING, "Invalid whence parameter for %s()",
  1803. get_active_function_name(TSRMLS_C));
  1804. return;
  1805. }
  1806. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  1807. if (lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence )) {
  1808. RETURN_TRUE;
  1809. } else {
  1810. RETURN_FALSE;
  1811. }
  1812. }
  1813. /* }}} */
  1814. /* {{{ proto int pg_lo_tell(resource large_object)
  1815. Returns current position of large object */
  1816. PHP_FUNCTION(pg_lo_tell)
  1817. {
  1818. zval *pgsql_id = NULL;
  1819. int offset = 0;
  1820. pgLofp *pgsql;
  1821. int argc = ZEND_NUM_ARGS();
  1822. if (zend_parse_parameters(argc TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
  1823. return;
  1824. }
  1825. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  1826. offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
  1827. RETURN_LONG(offset);
  1828. }
  1829. /* }}} */
  1830. #ifdef HAVE_PQCLIENTENCODING
  1831. /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
  1832. Set client encoding */
  1833. PHP_FUNCTION(pg_set_client_encoding)
  1834. {
  1835. zval **encoding, **pgsql_link = NULL;
  1836. int id = -1;
  1837. PGconn *pgsql;
  1838. switch(ZEND_NUM_ARGS()) {
  1839. case 1:
  1840. if (zend_get_parameters_ex(1, &encoding)==FAILURE) {
  1841. RETURN_FALSE;
  1842. }
  1843. id = PGG(default_link);
  1844. CHECK_DEFAULT_LINK(id);
  1845. break;
  1846. case 2:
  1847. if (zend_get_parameters_ex(2, &pgsql_link, &encoding)==FAILURE) {
  1848. RETURN_FALSE;
  1849. }
  1850. break;
  1851. default:
  1852. WRONG_PARAM_COUNT;
  1853. break;
  1854. }
  1855. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1856. convert_to_string_ex(encoding);
  1857. Z_LVAL_P(return_value) = PQsetClientEncoding(pgsql, Z_STRVAL_PP(encoding));
  1858. Z_TYPE_P(return_value) = IS_LONG;
  1859. }
  1860. /* }}} */
  1861. /* {{{ proto string pg_client_encoding([resource connection])
  1862. Get the current client encoding */
  1863. PHP_FUNCTION(pg_client_encoding)
  1864. {
  1865. zval **pgsql_link = NULL;
  1866. int id = -1;
  1867. PGconn *pgsql;
  1868. switch(ZEND_NUM_ARGS()) {
  1869. case 0:
  1870. id = PGG(default_link);
  1871. CHECK_DEFAULT_LINK(id);
  1872. break;
  1873. case 1:
  1874. if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
  1875. RETURN_FALSE;
  1876. }
  1877. break;
  1878. default:
  1879. WRONG_PARAM_COUNT;
  1880. break;
  1881. }
  1882. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1883. /* Just do the same as found in PostgreSQL sources... */
  1884. #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
  1885. #define pg_encoding_to_char(x) "SQL_ASCII"
  1886. #endif
  1887. Z_STRVAL_P(return_value)
  1888. = (char *) pg_encoding_to_char(PQclientEncoding(pgsql));
  1889. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  1890. Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
  1891. Z_TYPE_P(return_value) = IS_STRING;
  1892. }
  1893. /* }}} */
  1894. #endif
  1895. #define COPYBUFSIZ 8192
  1896. /* {{{ proto bool pg_end_copy([resource connection])
  1897. Sync with backend. Completes the Copy command */
  1898. PHP_FUNCTION(pg_end_copy)
  1899. {
  1900. zval **pgsql_link = NULL;
  1901. int id = -1;
  1902. PGconn *pgsql;
  1903. int result = 0;
  1904. switch(ZEND_NUM_ARGS()) {
  1905. case 0:
  1906. id = PGG(default_link);
  1907. CHECK_DEFAULT_LINK(id);
  1908. break;
  1909. case 1:
  1910. if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
  1911. RETURN_FALSE;
  1912. }
  1913. break;
  1914. default:
  1915. WRONG_PARAM_COUNT;
  1916. break;
  1917. }
  1918. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1919. result = PQendcopy(pgsql);
  1920. if (result!=0) {
  1921. php_error(E_WARNING, "%s() PostgreSQL query failed: %s",
  1922. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  1923. RETURN_FALSE;
  1924. }
  1925. RETURN_TRUE;
  1926. }
  1927. /* }}} */
  1928. /* {{{ proto bool pg_put_line([resource connection,] string query)
  1929. Send null-terminated string to backend server*/
  1930. PHP_FUNCTION(pg_put_line)
  1931. {
  1932. zval **query, **pgsql_link = NULL;
  1933. int id = -1;
  1934. PGconn *pgsql;
  1935. int result = 0;
  1936. switch(ZEND_NUM_ARGS()) {
  1937. case 1:
  1938. if (zend_get_parameters_ex(1, &query)==FAILURE) {
  1939. RETURN_FALSE;
  1940. }
  1941. id = PGG(default_link);
  1942. CHECK_DEFAULT_LINK(id);
  1943. break;
  1944. case 2:
  1945. if (zend_get_parameters_ex(2, &pgsql_link, &query)==FAILURE) {
  1946. RETURN_FALSE;
  1947. }
  1948. break;
  1949. default:
  1950. WRONG_PARAM_COUNT;
  1951. break;
  1952. }
  1953. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1954. convert_to_string_ex(query);
  1955. result = PQputline(pgsql, Z_STRVAL_PP(query));
  1956. if (result==EOF) {
  1957. php_error(E_WARNING, "%s() PostgreSQL query failed: %s",
  1958. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  1959. RETURN_FALSE;
  1960. }
  1961. RETURN_TRUE;
  1962. }
  1963. /* }}} */
  1964. /* {{{ proto array pg_copy_to(int connection, string table_name [, string delimiter [, string null_as]])
  1965. Copy table to array */
  1966. PHP_FUNCTION(pg_copy_to)
  1967. {
  1968. zval *pgsql_link;
  1969. char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
  1970. int table_name_len, pg_delim_len, pg_null_as_len;
  1971. char *query;
  1972. char *query_template = "COPY \"\" TO STDOUT DELIMITERS ':' WITH NULL AS ''";
  1973. int id = -1;
  1974. PGconn *pgsql;
  1975. PGresult *pgsql_result;
  1976. ExecStatusType status;
  1977. int copydone = 0;
  1978. char copybuf[COPYBUFSIZ];
  1979. char *csv = (char *)NULL;
  1980. int ret;
  1981. int argc = ZEND_NUM_ARGS();
  1982. if (zend_parse_parameters(argc TSRMLS_CC, "rs|ss",
  1983. &pgsql_link, &table_name, &table_name_len,
  1984. &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
  1985. return;
  1986. }
  1987. if (!pg_delim) {
  1988. pg_delim = "\t";
  1989. }
  1990. if (!pg_null_as) {
  1991. pg_null_as = safe_estrdup("\\\\N");
  1992. }
  1993. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1994. query = (char *)emalloc(strlen(query_template) + strlen(table_name) + strlen(pg_null_as) + 1);
  1995. sprintf(query, "COPY \"%s\" TO STDOUT DELIMITERS '%s' WITH NULL AS '%s'",
  1996. table_name, pg_delim, pg_null_as);
  1997. while ((pgsql_result = PQgetResult(pgsql))) {
  1998. PQclear(pgsql_result);
  1999. }
  2000. pgsql_result = PQexec(pgsql, query);
  2001. efree(pg_null_as);
  2002. efree(query);
  2003. if (pgsql_result) {
  2004. status = PQresultStatus(pgsql_result);
  2005. } else {
  2006. status = (ExecStatusType) PQstatus(pgsql);
  2007. }
  2008. switch (status) {
  2009. case PGRES_COPY_OUT:
  2010. if (pgsql_result) {
  2011. PQclear(pgsql_result);
  2012. if (array_init(return_value) == FAILURE) {
  2013. RETURN_FALSE;
  2014. }
  2015. while (!copydone)
  2016. {
  2017. if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
  2018. php_error(E_WARNING, "%s() query failed: %s",
  2019. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  2020. RETURN_FALSE;
  2021. }
  2022. if (copybuf[0] == '\\' &&
  2023. copybuf[1] == '.' &&
  2024. copybuf[2] == '\0')
  2025. {
  2026. copydone = 1;
  2027. }
  2028. else
  2029. {
  2030. if (csv == (char *)NULL) {
  2031. csv = estrdup(copybuf);
  2032. } else {
  2033. csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
  2034. strcat(csv, copybuf);
  2035. }
  2036. switch (ret)
  2037. {
  2038. case EOF:
  2039. copydone = 1;
  2040. case 0:
  2041. add_next_index_string(return_value, csv, 1);
  2042. efree(csv);
  2043. csv = (char *)NULL;
  2044. break;
  2045. case 1:
  2046. break;
  2047. }
  2048. }
  2049. }
  2050. if (PQendcopy(pgsql)) {
  2051. php_error(E_WARNING, "%s() query failed: %s",
  2052. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  2053. RETURN_FALSE;
  2054. }
  2055. while ((pgsql_result = PQgetResult(pgsql))) {
  2056. PQclear(pgsql_result);
  2057. }
  2058. } else {
  2059. PQclear(pgsql_result);
  2060. RETURN_FALSE;
  2061. }
  2062. break;
  2063. default:
  2064. PQclear(pgsql_result);
  2065. php_error(E_WARNING, "%s() query failed: %s",
  2066. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  2067. RETURN_FALSE;
  2068. break;
  2069. }
  2070. }
  2071. /* }}} */
  2072. /* {{{ proto bool pg_copy_from(int connection, string table_name , array rows [, string delimiter [, string null_as]])
  2073. Copy table from array */
  2074. PHP_FUNCTION(pg_copy_from)
  2075. {
  2076. zval *pgsql_link = NULL, *pg_rows;
  2077. zval **tmp;
  2078. char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
  2079. int table_name_len, pg_delim_len, pg_null_as_len;
  2080. char *query;
  2081. char *query_template = "COPY \"\" FROM STDIN DELIMITERS ':' WITH NULL AS ''";
  2082. HashPosition pos;
  2083. int id = -1;
  2084. PGconn *pgsql;
  2085. PGresult *pgsql_result;
  2086. ExecStatusType status;
  2087. int argc = ZEND_NUM_ARGS();
  2088. if (zend_parse_parameters(argc TSRMLS_CC, "rs/a|ss",
  2089. &pgsql_link, &table_name, &table_name_len, &pg_rows,
  2090. &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
  2091. return;
  2092. }
  2093. if (!pg_delim) {
  2094. pg_delim = "\t";
  2095. }
  2096. if (!pg_null_as) {
  2097. pg_null_as = safe_estrdup("\\\\N");
  2098. }
  2099. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2100. query = (char *)emalloc(strlen(query_template) + strlen(table_name) + strlen(pg_null_as) + 1);
  2101. sprintf(query, "COPY \"%s\" FROM STDIN DELIMITERS '%s' WITH NULL AS '%s'",
  2102. table_name, pg_delim, pg_null_as);
  2103. while ((pgsql_result = PQgetResult(pgsql))) {
  2104. PQclear(pgsql_result);
  2105. }
  2106. pgsql_result = PQexec(pgsql, query);
  2107. efree(pg_null_as);
  2108. efree(query);
  2109. if (pgsql_result) {
  2110. status = PQresultStatus(pgsql_result);
  2111. } else {
  2112. status = (ExecStatusType) PQstatus(pgsql);
  2113. }
  2114. switch (status) {
  2115. case PGRES_COPY_IN:
  2116. if (pgsql_result) {
  2117. PQclear(pgsql_result);
  2118. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
  2119. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
  2120. convert_to_string_ex(tmp);
  2121. query = (char *)emalloc(Z_STRLEN_PP(tmp) +2);
  2122. strcpy(query, Z_STRVAL_PP(tmp));
  2123. if(*(query+Z_STRLEN_PP(tmp)-1) != '\n') strcat(query, "\n");
  2124. if (PQputline(pgsql, query)) {
  2125. efree(query);
  2126. php_error(E_WARNING, "%s() query failed: %s",
  2127. get_active_function_name, PQerrorMessage(pgsql));
  2128. RETURN_FALSE;
  2129. }
  2130. efree(query);
  2131. zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
  2132. }
  2133. if (PQputline(pgsql, "\\.\n")) {
  2134. php_error(E_WARNING, "%s() query failed: %s",
  2135. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  2136. RETURN_FALSE;
  2137. }
  2138. if (PQendcopy(pgsql)) {
  2139. php_error(E_WARNING, "%s() query failed: %s",
  2140. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  2141. RETURN_FALSE;
  2142. }
  2143. while ((pgsql_result = PQgetResult(pgsql))) {
  2144. PQclear(pgsql_result);
  2145. }
  2146. } else {
  2147. PQclear(pgsql_result);
  2148. RETURN_FALSE;
  2149. }
  2150. RETURN_TRUE;
  2151. break;
  2152. default:
  2153. PQclear(pgsql_result);
  2154. php_error(E_WARNING, "%s() query failed: %s",
  2155. get_active_function_name(TSRMLS_C), PQerrorMessage(pgsql));
  2156. RETURN_FALSE;
  2157. break;
  2158. }
  2159. }
  2160. /* }}} */
  2161. #ifdef HAVE_PQESCAPE
  2162. /* {{{ proto string pg_escape_string(string data)
  2163. Escape string for text/char type */
  2164. PHP_FUNCTION(pg_escape_string)
  2165. {
  2166. char *from = NULL, *to = NULL;
  2167. size_t from_len, to_len;
  2168. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
  2169. &from, &from_len) == FAILURE) {
  2170. return;
  2171. }
  2172. to = (char *)emalloc(from_len*2+1);
  2173. to_len = (int)PQescapeString(to, from, from_len);
  2174. RETURN_STRINGL(to, to_len, 0);
  2175. }
  2176. /* }}} */
  2177. /* {{{ proto string pg_escape_bytea(string data)
  2178. Escape binary for bytea type */
  2179. PHP_FUNCTION(pg_escape_bytea)
  2180. {
  2181. char *from = NULL, *to = NULL;
  2182. size_t from_len, to_len;
  2183. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
  2184. &from, &from_len) == FAILURE) {
  2185. return;
  2186. }
  2187. to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
  2188. RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes addtional '\0' */
  2189. free(to);
  2190. }
  2191. /* }}} */
  2192. #endif
  2193. /* {{{ proto string pg_result_error(resource result)
  2194. Get error message associated with result */
  2195. PHP_FUNCTION(pg_result_error)
  2196. {
  2197. zval *result;
  2198. PGresult *pgsql_result;
  2199. pgsql_result_handle *pg_result;
  2200. char *err = NULL;
  2201. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
  2202. &result) == FAILURE) {
  2203. return;
  2204. }
  2205. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2206. pgsql_result = pg_result->result;
  2207. if (!pgsql_result) {
  2208. RETURN_FALSE;
  2209. }
  2210. err = (char *)PQresultErrorMessage(pgsql_result);
  2211. RETURN_STRING(err,1);
  2212. }
  2213. /* }}} */
  2214. /* {{{ proto int pg_connection_status(resource connnection)
  2215. Get connection status */
  2216. PHP_FUNCTION(pg_connection_status)
  2217. {
  2218. zval *pgsql_link = NULL;
  2219. int id = -1;
  2220. PGconn *pgsql;
  2221. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
  2222. &pgsql_link) == FAILURE) {
  2223. return;
  2224. }
  2225. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2226. RETURN_LONG(PQstatus(pgsql));
  2227. }
  2228. /* }}} */
  2229. /* {{{ proto bool pg_connection_reset(resource connection)
  2230. Reset connection (reconnect) */
  2231. PHP_FUNCTION(pg_connection_reset)
  2232. {
  2233. zval *pgsql_link;
  2234. int id = -1;
  2235. PGconn *pgsql;
  2236. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
  2237. &pgsql_link) == FAILURE) {
  2238. return;
  2239. }
  2240. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2241. PQreset(pgsql);
  2242. if (PQstatus(pgsql) == CONNECTION_BAD) {
  2243. RETURN_FALSE;
  2244. }
  2245. RETURN_TRUE;
  2246. }
  2247. /* }}} */
  2248. #define PHP_PG_ASYNC_IS_BUSY 1
  2249. #define PHP_PG_ASYNC_REQUEST_CANCEL 2
  2250. /* {{{ php_pgsql_flush_query
  2251. */
  2252. static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC)
  2253. {
  2254. PGresult *res;
  2255. int leftover = 0;
  2256. if (PQsetnonblocking(pgsql, 1)) {
  2257. php_error(E_NOTICE,"%s() cannot set connection to nonblocking mode",
  2258. get_active_function_name(TSRMLS_C));
  2259. return -1;
  2260. }
  2261. while ((res = PQgetResult(pgsql))) {
  2262. PQclear(res);
  2263. leftover++;
  2264. }
  2265. PQsetnonblocking(pgsql, 0);
  2266. return leftover;
  2267. }
  2268. /* }}} */
  2269. /* {{{ php_pgsql_do_async
  2270. */
  2271. static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  2272. {
  2273. zval *pgsql_link;
  2274. int id = -1;
  2275. PGconn *pgsql;
  2276. PGresult *pgsql_result;
  2277. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
  2278. &pgsql_link) == FAILURE) {
  2279. return;
  2280. }
  2281. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2282. if (PQ_SETNONBLOCKING(pgsql, 1)) {
  2283. php_error(E_NOTICE,"%s() cannot set connection to nonblocking mode",
  2284. get_active_function_name(TSRMLS_C));
  2285. RETURN_FALSE;
  2286. }
  2287. switch(entry_type) {
  2288. case PHP_PG_ASYNC_IS_BUSY:
  2289. PQconsumeInput(pgsql);
  2290. Z_LVAL_P(return_value) = PQisBusy(pgsql);
  2291. Z_TYPE_P(return_value) = IS_LONG;
  2292. break;
  2293. case PHP_PG_ASYNC_REQUEST_CANCEL:
  2294. Z_LVAL_P(return_value) = PQrequestCancel(pgsql);
  2295. Z_TYPE_P(return_value) = IS_LONG;
  2296. while ((pgsql_result = PQgetResult(pgsql))) {
  2297. PQclear(pgsql_result);
  2298. }
  2299. break;
  2300. default:
  2301. php_error(E_ERROR,"%s() PostgreSQL module error. Report this error",
  2302. get_active_function_name(TSRMLS_C));
  2303. break;
  2304. }
  2305. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  2306. php_error(E_NOTICE,"%s() cannot set connection to blocking mode",
  2307. get_active_function_name(TSRMLS_C));
  2308. }
  2309. convert_to_boolean_ex(&return_value);
  2310. }
  2311. /* }}} */
  2312. /* {{{ proto bool pg_cancel_query(resource connection)
  2313. Cancel request */
  2314. PHP_FUNCTION(pg_cancel_query)
  2315. {
  2316. php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
  2317. }
  2318. /* }}} */
  2319. /* {{{ proto bool pg_connection_busy(resource connection)
  2320. Get connection is busy or not */
  2321. PHP_FUNCTION(pg_connection_busy)
  2322. {
  2323. php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
  2324. }
  2325. /* }}} */
  2326. /* {{{ proto bool pg_send_query(resource connection, string qeury)
  2327. Send asynchronous query */
  2328. PHP_FUNCTION(pg_send_query)
  2329. {
  2330. zval *pgsql_link;
  2331. char *query;
  2332. int len;
  2333. int id = -1;
  2334. PGconn *pgsql;
  2335. PGresult *res;
  2336. int leftover = 0;
  2337. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
  2338. &pgsql_link, &query, &len) == FAILURE) {
  2339. return;
  2340. }
  2341. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2342. if (PQ_SETNONBLOCKING(pgsql, 1)) {
  2343. php_error(E_NOTICE,"%s() cannot set connection to nonblocking mode",
  2344. get_active_function_name(TSRMLS_C));
  2345. RETURN_FALSE;
  2346. }
  2347. while ((res = PQgetResult(pgsql))) {
  2348. PQclear(res);
  2349. leftover = 1;
  2350. }
  2351. if (leftover) {
  2352. php_error(E_NOTICE,"%s() - There are results on this connection. Call pg_get_result() until it returns FALSE",
  2353. get_active_function_name(TSRMLS_C));
  2354. }
  2355. if (!PQsendQuery(pgsql, query)) {
  2356. RETURN_FALSE;
  2357. }
  2358. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  2359. php_error(E_NOTICE,"%s() cannot set connection to blocking mode",
  2360. get_active_function_name(TSRMLS_C));
  2361. }
  2362. RETURN_TRUE;
  2363. }
  2364. /* }}} */
  2365. /* {{{ proto resource pg_get_result([resource connection])
  2366. Get asynchronous query result */
  2367. PHP_FUNCTION(pg_get_result)
  2368. {
  2369. zval *pgsql_link;
  2370. int id = -1;
  2371. PGconn *pgsql;
  2372. PGresult *pgsql_result;
  2373. pgsql_result_handle *pg_result;
  2374. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
  2375. &pgsql_link) == FAILURE) {
  2376. return;
  2377. }
  2378. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2379. pgsql_result = PQgetResult(pgsql);
  2380. if (!pgsql_result) {
  2381. /* no result */
  2382. RETURN_FALSE;
  2383. }
  2384. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  2385. pg_result->conn = pgsql;
  2386. pg_result->result = pgsql_result;
  2387. pg_result->row = -1;
  2388. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  2389. }
  2390. /* }}} */
  2391. /* {{{ proto int pg_result_status(resource result[, long result_type])
  2392. Get status of query result */
  2393. PHP_FUNCTION(pg_result_status)
  2394. {
  2395. zval *result;
  2396. long result_type = PGSQL_STATUS_LONG;
  2397. ExecStatusType status;
  2398. PGresult *pgsql_result;
  2399. pgsql_result_handle *pg_result;
  2400. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
  2401. &result, &result_type) == FAILURE) {
  2402. return;
  2403. }
  2404. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2405. pgsql_result = pg_result->result;
  2406. if (result_type == PGSQL_STATUS_LONG) {
  2407. status = PQresultStatus(pgsql_result);
  2408. RETURN_LONG((int)status);
  2409. }
  2410. else if (result_type == PGSQL_STATUS_STRING) {
  2411. RETURN_STRING(PQcmdStatus(pgsql_result), 1);
  2412. }
  2413. else {
  2414. php_error(E_WARNING, "%s() expects optional 2nd parameter to be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING",
  2415. get_active_function_name(TSRMLS_C));
  2416. RETURN_FALSE;
  2417. }
  2418. }
  2419. /* }}} */
  2420. #define QUERY_BUF_SIZE (1023)
  2421. /* {{{ php_pgsql_metadata
  2422. */
  2423. PHPAPI int php_pgsql_metadata(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC)
  2424. {
  2425. PGresult *pg_result;
  2426. char query_buf[QUERY_BUF_SIZE+1], *tmp_name;
  2427. char *query_tpl =
  2428. "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef "
  2429. "FROM pg_class as c, pg_attribute a, pg_type t "
  2430. "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '%s' AND a.atttypid = t.oid "
  2431. "ORDER BY a.attnum;";
  2432. size_t new_len;
  2433. int i, num_rows;
  2434. zval *elem;
  2435. tmp_name = php_addslashes((char *)table_name, strlen(table_name), &new_len, 0 TSRMLS_CC);
  2436. snprintf(query_buf, QUERY_BUF_SIZE, query_tpl, tmp_name);
  2437. efree(tmp_name);
  2438. pg_result = PQexec(pg_link, query_buf);
  2439. if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
  2440. php_error(E_NOTICE, "%s() failed to query metadata for '%s' table %s",
  2441. get_active_function_name(TSRMLS_C), table_name, query_buf);
  2442. PQclear(pg_result);
  2443. return FAILURE;
  2444. }
  2445. for (i = 0; i < num_rows; i++) {
  2446. char *name;
  2447. MAKE_STD_ZVAL(elem);
  2448. array_init(elem);
  2449. add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
  2450. add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
  2451. add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
  2452. if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
  2453. add_assoc_bool(elem, "not null", 1);
  2454. }
  2455. else {
  2456. add_assoc_bool(elem, "not null", 0);
  2457. }
  2458. if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
  2459. add_assoc_bool(elem, "default", 1);
  2460. }
  2461. else {
  2462. add_assoc_bool(elem, "default", 0);
  2463. }
  2464. name = PQgetvalue(pg_result,i,0);
  2465. add_assoc_zval(meta, name, elem);
  2466. }
  2467. return SUCCESS;
  2468. }
  2469. /* }}} */
  2470. /* {{{ proto array pg_metadata(resource db, string table)
  2471. Get metadata */
  2472. PHP_FUNCTION(pg_metadata)
  2473. {
  2474. zval *pgsql_link;
  2475. char *table_name;
  2476. uint table_name_len;
  2477. PGconn *pgsql;
  2478. int id = -1;
  2479. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
  2480. &pgsql_link, &table_name, &table_name_len) == FAILURE) {
  2481. return;
  2482. }
  2483. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2484. array_init(return_value);
  2485. if (php_pgsql_metadata(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
  2486. zval_dtor(return_value); /* destroy array */
  2487. RETURN_FALSE;
  2488. }
  2489. }
  2490. /* }}} */
  2491. /* {{{ php_pgsql_get_data_type
  2492. */
  2493. static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
  2494. {
  2495. /* This is stupid way to do. I'll fix it when I decied how to support
  2496. user defined types. (Yasuo) */
  2497. /* boolean */
  2498. if (!strcmp(type_name, "boolean"))
  2499. return PG_BOOL;
  2500. /* object id */
  2501. if (!strcmp(type_name, "oid"))
  2502. return PG_OID;
  2503. /* integer */
  2504. if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
  2505. return PG_INT2;
  2506. if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
  2507. return PG_INT4;
  2508. if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
  2509. return PG_INT8;
  2510. /* real and other */
  2511. if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
  2512. return PG_FLOAT4;
  2513. if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
  2514. return PG_FLOAT8;
  2515. if (!strcmp(type_name, "numeric"))
  2516. return PG_NUMERIC;
  2517. if (!strcmp(type_name, "money"))
  2518. return PG_MONEY;
  2519. /* character */
  2520. if (!strcmp(type_name, "text"))
  2521. return PG_TEXT;
  2522. if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
  2523. return PG_CHAR;
  2524. if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
  2525. return PG_VARCHAR;
  2526. /* time and interval */
  2527. if (!strcmp(type_name, "abstime"))
  2528. return PG_UNIX_TIME;
  2529. if (!strcmp(type_name, "reltime"))
  2530. return PG_UNIX_TIME_INTERVAL;
  2531. if (!strcmp(type_name, "tinterval"))
  2532. return PG_UNIX_TIME_INTERVAL;
  2533. if (!strcmp(type_name, "date"))
  2534. return PG_DATE;
  2535. if (!strcmp(type_name, "time"))
  2536. return PG_TIME;
  2537. if (!strcmp(type_name, "timestamp") || !strcmp(type_name, "time with time zone"))
  2538. return PG_TIME_WITH_TIMEZONE;
  2539. if (!strcmp(type_name, "timestamp with time zone"))
  2540. return PG_TIMESTAMP_WITH_TIMEZONE;
  2541. if (!strcmp(type_name, "interval"))
  2542. return PG_INTERVAL;
  2543. /* binary */
  2544. if (!strcmp(type_name, "bytea"))
  2545. return PG_BYTEA;
  2546. /* network */
  2547. if (!strcmp(type_name, "cidr"))
  2548. return PG_CIDR;
  2549. if (!strcmp(type_name, "inet"))
  2550. return PG_INET;
  2551. if (!strcmp(type_name, "macaddr"))
  2552. return PG_MACADDR;
  2553. /* bit */
  2554. if (!strcmp(type_name, "bit"))
  2555. return PG_BIT;
  2556. if (!strcmp(type_name, "bit varying"))
  2557. return PG_VARBIT;
  2558. /* geometoric */
  2559. if (!strcmp(type_name, "line"))
  2560. return PG_LINE;
  2561. if (!strcmp(type_name, "lseg"))
  2562. return PG_LSEG;
  2563. if (!strcmp(type_name, "box"))
  2564. return PG_BOX;
  2565. if (!strcmp(type_name, "path"))
  2566. return PG_PATH;
  2567. if (!strcmp(type_name, "point"))
  2568. return PG_POINT;
  2569. if (!strcmp(type_name, "polygon"))
  2570. return PG_POLYGON;
  2571. if (!strcmp(type_name, "circle"))
  2572. return PG_CIRCLE;
  2573. return PG_UNKNOWN;
  2574. }
  2575. /* }}} */
  2576. /* {{{ php_pgsql_convert_match
  2577. * test field value with regular expression specified.
  2578. */
  2579. static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC)
  2580. {
  2581. regex_t re;
  2582. regmatch_t *subs;
  2583. int regopt = REG_EXTENDED;
  2584. int regerr, ret = SUCCESS;
  2585. if (icase) {
  2586. regopt |= REG_ICASE;
  2587. }
  2588. regerr = regcomp(&re, regex, regopt);
  2589. if (regerr) {
  2590. php_error(E_WARNING, "%s() cannot compile regex",
  2591. get_active_function_name(TSRMLS_C));
  2592. regfree(&re);
  2593. return FAILURE;
  2594. }
  2595. subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
  2596. if (!subs) {
  2597. php_error(E_WARNING, "%s() cannot allocate memory",
  2598. get_active_function_name(TSRMLS_C));
  2599. regfree(&re);
  2600. return FAILURE;
  2601. }
  2602. regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
  2603. if (regerr == REG_NOMATCH) {
  2604. #ifdef PHP_DEBUG
  2605. php_error(E_NOTICE, "%s(): '%s' does not match with '%s'",
  2606. get_active_function_name(TSRMLS_C), str, regex);
  2607. #endif
  2608. ret = FAILURE;
  2609. }
  2610. else if (regerr) {
  2611. php_error(E_WARNING, "%s() cannot exec regex",
  2612. get_active_function_name(TSRMLS_C));
  2613. ret = FAILURE;
  2614. }
  2615. regfree(&re);
  2616. efree(subs);
  2617. return ret;
  2618. }
  2619. /* }}} */
  2620. /* {{{ php_pgsql_convert_add_quote
  2621. * add quotes around string.
  2622. */
  2623. static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
  2624. {
  2625. char *dist;
  2626. assert(Z_TYPE_P(src) == IS_STRING);
  2627. assert(should_free == 1 || should_free == 0);
  2628. dist = (char *)emalloc(Z_STRLEN_P(src)+3);
  2629. memcpy(dist+1, Z_STRVAL_P(src), Z_STRLEN_P(src));
  2630. dist[0] = '\'';
  2631. dist[Z_STRLEN_P(src)+1] = '\'';
  2632. dist[Z_STRLEN_P(src)+2] = '\0';
  2633. Z_STRLEN_P(src) += 2;
  2634. if (should_free) {
  2635. efree(Z_STRVAL_P(src));
  2636. }
  2637. Z_STRVAL_P(src) = dist;
  2638. return SUCCESS;
  2639. }
  2640. /* }}} */
  2641. /* {{{ php_pgsql_convert
  2642. * check and convert array values (fieldname=>vlaue pair) for sql
  2643. */
  2644. PHPAPI int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result TSRMLS_DC)
  2645. {
  2646. HashPosition pos;
  2647. char *field = NULL;
  2648. uint field_len = -1;
  2649. ulong num_idx = -1;
  2650. zval *meta, **def, **type, **val, *new_val;
  2651. int new_len, key_type, err = 0;
  2652. assert(pg_link != NULL);
  2653. assert(Z_TYPE_P(values) == IS_ARRAY);
  2654. assert(Z_TYPE_P(result) == IS_ARRAY);
  2655. if (!table_name) {
  2656. return FAILURE;
  2657. }
  2658. MAKE_STD_ZVAL(meta);
  2659. if (array_init(meta) == FAILURE) {
  2660. zval_dtor(meta);
  2661. FREE_ZVAL(meta);
  2662. return FAILURE;
  2663. }
  2664. if (php_pgsql_metadata(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
  2665. zval_dtor(meta);
  2666. FREE_ZVAL(meta);
  2667. return FAILURE;
  2668. }
  2669. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
  2670. zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
  2671. zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
  2672. if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == FAILURE) {
  2673. php_error(E_WARNING, "%s() failed to get array key type",
  2674. get_active_function_name(TSRMLS_C));
  2675. err = 1;
  2676. }
  2677. if (!err && key_type == HASH_KEY_IS_LONG) {
  2678. php_error(E_WARNING, "%s() accepts only string key for values",
  2679. get_active_function_name(TSRMLS_C));
  2680. err = 1;
  2681. }
  2682. if (!err && key_type == HASH_KEY_NON_EXISTANT) {
  2683. php_error(E_WARNING, "%s() accepts only string key for values",
  2684. get_active_function_name(TSRMLS_C));
  2685. err = 1;
  2686. }
  2687. if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
  2688. php_error(E_NOTICE, "%s() Invalid field name (%s) in values",
  2689. get_active_function_name(TSRMLS_C), field);
  2690. err = 1;
  2691. }
  2692. if (!def || zend_hash_find(Z_ARRVAL_PP(def), "type", 5, (void **)&type) == FAILURE) {
  2693. php_error(E_NOTICE, "%s() detected broken meta data",
  2694. get_active_function_name(TSRMLS_C));
  2695. err = 1;
  2696. }
  2697. if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
  2698. Z_TYPE_PP(val) == IS_OBJECT ||
  2699. Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
  2700. php_error(E_NOTICE, "%s() expects scaler values as field values",
  2701. get_active_function_name(TSRMLS_C));
  2702. err = 1;
  2703. }
  2704. if (err) {
  2705. break;
  2706. }
  2707. MAKE_STD_ZVAL(new_val);
  2708. switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type)))
  2709. {
  2710. case PG_BOOL:
  2711. switch (Z_TYPE_PP(val)) {
  2712. case IS_STRING:
  2713. if (Z_STRLEN_PP(val) == 0) {
  2714. ZVAL_STRING(new_val, "NULL", 1);
  2715. }
  2716. else {
  2717. if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
  2718. !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
  2719. !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") ||
  2720. !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") ||
  2721. !strcmp(Z_STRVAL_PP(val), "1")) {
  2722. Z_STRVAL_P(new_val) = estrdup("'t'");
  2723. Z_STRLEN_P(new_val) = 1;
  2724. }
  2725. else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") ||
  2726. !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") ||
  2727. !strcmp(Z_STRVAL_PP(val), "false") || !strcmp(Z_STRVAL_PP(val), "False") ||
  2728. !strcmp(Z_STRVAL_PP(val), "no") || !strcmp(Z_STRVAL_PP(val), "No") ||
  2729. !strcmp(Z_STRVAL_PP(val), "0")) {
  2730. Z_STRVAL_P(new_val) = estrdup("'f'");
  2731. Z_STRLEN_P(new_val) = 1;
  2732. }
  2733. else {
  2734. php_error(E_NOTICE, "%s() detected invalid value (%s) for pgsql %s field (%s)",
  2735. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(val), Z_STRVAL_PP(type), field);
  2736. err = 1;
  2737. }
  2738. }
  2739. break;
  2740. case IS_LONG:
  2741. case IS_BOOL:
  2742. if (Z_LVAL_PP(val)) {
  2743. Z_STRVAL_P(new_val) = estrdup("'t'");
  2744. }
  2745. else {
  2746. Z_STRVAL_P(new_val) = estrdup("'f'");
  2747. }
  2748. Z_STRLEN_P(new_val) = 1;
  2749. break;
  2750. case IS_NULL:
  2751. ZVAL_STRING(new_val, "NULL", 1);
  2752. break;
  2753. default:
  2754. err = 1;
  2755. }
  2756. if (err) {
  2757. php_error(E_NOTICE, "%s() expects string, null, long or boolelan value for pgsql '%s' (%s)",
  2758. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2759. }
  2760. break;
  2761. case PG_OID:
  2762. case PG_INT2:
  2763. case PG_INT4:
  2764. case PG_INT8:
  2765. switch (Z_TYPE_PP(val)) {
  2766. case IS_STRING:
  2767. if (Z_STRLEN_PP(val) == 0) {
  2768. ZVAL_STRING(new_val, "NULL", 1);
  2769. }
  2770. else {
  2771. /* FIXME: better regex must be used */
  2772. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
  2773. err = 1;
  2774. }
  2775. else {
  2776. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  2777. }
  2778. }
  2779. break;
  2780. case IS_DOUBLE:
  2781. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  2782. convert_to_long_ex(&new_val);
  2783. break;
  2784. case IS_LONG:
  2785. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  2786. break;
  2787. case IS_NULL:
  2788. ZVAL_STRING(new_val, "NULL", 1);
  2789. break;
  2790. default:
  2791. err = 1;
  2792. }
  2793. if (err) {
  2794. php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
  2795. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2796. }
  2797. break;
  2798. case PG_NUMERIC:
  2799. case PG_MONEY:
  2800. case PG_FLOAT4:
  2801. case PG_FLOAT8:
  2802. switch (Z_TYPE_PP(val)) {
  2803. case IS_STRING:
  2804. if (Z_STRLEN_PP(val) == 0) {
  2805. ZVAL_STRING(new_val, "NULL", 1);
  2806. }
  2807. else {
  2808. /* FIXME: better regex must be used */
  2809. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)|([+-]{0,1}[0-9]*[\\.][0-9]+)|([+-]{0,1}[0-9]+[\\.][0-9]*)$", 0 TSRMLS_CC) == FAILURE) {
  2810. err = 1;
  2811. }
  2812. else {
  2813. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  2814. }
  2815. }
  2816. break;
  2817. case IS_LONG:
  2818. ZVAL_LONG(new_val, Z_DVAL_PP(val));
  2819. break;
  2820. case IS_DOUBLE:
  2821. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  2822. break;
  2823. case IS_NULL:
  2824. ZVAL_STRING(new_val, "NULL", 1);
  2825. break;
  2826. default:
  2827. err = 1;
  2828. }
  2829. if (err) {
  2830. php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
  2831. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2832. }
  2833. break;
  2834. case PG_TEXT:
  2835. case PG_CHAR:
  2836. case PG_VARCHAR:
  2837. switch (Z_TYPE_PP(val)) {
  2838. case IS_STRING:
  2839. if (Z_STRLEN_PP(val) == 0) {
  2840. ZVAL_STRING(new_val, "NULL", 1);
  2841. }
  2842. else {
  2843. Z_TYPE_P(new_val) = IS_STRING;
  2844. #if HAVE_PQESCAPE
  2845. {
  2846. char *tmp;
  2847. tmp = (char *)emalloc(Z_STRLEN_PP(val)*2+1);
  2848. Z_STRLEN_P(new_val) = (int)PQescapeString(tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  2849. Z_STRVAL_P(new_val) = tmp;
  2850. }
  2851. #else
  2852. Z_STRVAL_P(new_val) = php_addslashes(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &Z_STRLEN_P(new_val), 0 TSRMLS_CC);
  2853. #endif
  2854. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  2855. }
  2856. break;
  2857. case IS_LONG:
  2858. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  2859. convert_to_string_ex(&new_val);
  2860. break;
  2861. case IS_DOUBLE:
  2862. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  2863. convert_to_string_ex(&new_val);
  2864. break;
  2865. case IS_NULL:
  2866. ZVAL_STRING(new_val, "NULL", 1);
  2867. break;
  2868. default:
  2869. err = 1;
  2870. }
  2871. if (err) {
  2872. php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
  2873. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2874. }
  2875. break;
  2876. case PG_UNIX_TIME:
  2877. case PG_UNIX_TIME_INTERVAL:
  2878. /* these are the actallay a integer */
  2879. switch (Z_TYPE_PP(val)) {
  2880. case IS_STRING:
  2881. if (Z_STRLEN_PP(val) == 0) {
  2882. ZVAL_STRING(new_val, "NULL", 1);
  2883. }
  2884. else {
  2885. /* FIXME: Better regex must be used */
  2886. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
  2887. err = 1;
  2888. }
  2889. else {
  2890. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  2891. convert_to_long_ex(&new_val);
  2892. }
  2893. }
  2894. break;
  2895. case IS_DOUBLE:
  2896. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  2897. convert_to_long_ex(&new_val);
  2898. break;
  2899. case IS_LONG:
  2900. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  2901. break;
  2902. case IS_NULL:
  2903. ZVAL_STRING(new_val, "NULL", 1);
  2904. break;
  2905. default:
  2906. err = 1;
  2907. }
  2908. #ifdef PHP_DEBUG
  2909. if (err) {
  2910. php_error(E_NOTICE, "%s() expects string, null, long or double value for '%s' (%s)",
  2911. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2912. }
  2913. #endif
  2914. break;
  2915. case PG_CIDR:
  2916. case PG_INET:
  2917. switch (Z_TYPE_PP(val)) {
  2918. case IS_STRING:
  2919. if (Z_STRLEN_PP(val) == 0) {
  2920. ZVAL_STRING(new_val, "NULL", 1);
  2921. }
  2922. else {
  2923. /* FIXME: Better regex must be used */
  2924. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/[0-9]{1,2}){0,1}$", 0 TSRMLS_CC) == FAILURE) {
  2925. err = 1;
  2926. }
  2927. else {
  2928. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  2929. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  2930. }
  2931. }
  2932. break;
  2933. case IS_NULL:
  2934. ZVAL_STRING(new_val, "NULL", 1);
  2935. break;
  2936. default:
  2937. err = 1;
  2938. }
  2939. if (err) {
  2940. php_error(E_NOTICE, "%s() expects string or null for '%s' (%s)",
  2941. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2942. }
  2943. break;
  2944. case PG_TIME_WITH_TIMEZONE:
  2945. case PG_TIMESTAMP_WITH_TIMEZONE:
  2946. switch(Z_TYPE_PP(val)) {
  2947. case IS_STRING:
  2948. if (Z_STRLEN_PP(val) == 0) {
  2949. ZVAL_STRING(new_val, "NULL", 1);
  2950. }
  2951. else {
  2952. /* FIXME: better regex must be used */
  2953. if (php_pgsql_convert_match(Z_STRVAL_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,1}$", 1 TSRMLS_CC) == FAILURE) {
  2954. err = 1;
  2955. }
  2956. else {
  2957. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  2958. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  2959. }
  2960. }
  2961. break;
  2962. case IS_NULL:
  2963. ZVAL_STRING(new_val, "NULL", 1);
  2964. break;
  2965. default:
  2966. err = 1;
  2967. }
  2968. if (err) {
  2969. php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
  2970. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2971. }
  2972. break;
  2973. case PG_DATE:
  2974. switch(Z_TYPE_PP(val)) {
  2975. case IS_STRING:
  2976. if (Z_STRLEN_PP(val) == 0) {
  2977. ZVAL_STRING(new_val, "NULL", 1);
  2978. }
  2979. else {
  2980. /* FIXME: better regex must be used */
  2981. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1 TSRMLS_CC) == FAILURE) {
  2982. err = 1;
  2983. }
  2984. else {
  2985. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  2986. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  2987. }
  2988. }
  2989. break;
  2990. case IS_NULL:
  2991. ZVAL_STRING(new_val, "NULL", 1);
  2992. break;
  2993. default:
  2994. err = 1;
  2995. }
  2996. if (err) {
  2997. php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
  2998. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  2999. }
  3000. break;
  3001. case PG_TIME:
  3002. switch(Z_TYPE_PP(val)) {
  3003. case IS_STRING:
  3004. if (Z_STRLEN_PP(val) == 0) {
  3005. ZVAL_STRING(new_val, "NULL", 1);
  3006. }
  3007. else {
  3008. /* FIXME: better regex must be used */
  3009. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) {
  3010. err = 1;
  3011. }
  3012. else {
  3013. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  3014. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  3015. }
  3016. }
  3017. break;
  3018. case IS_NULL:
  3019. ZVAL_STRING(new_val, "NULL", 1);
  3020. break;
  3021. default:
  3022. err = 1;
  3023. }
  3024. if (err) {
  3025. php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
  3026. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  3027. }
  3028. break;
  3029. case PG_INTERVAL:
  3030. switch(Z_TYPE_PP(val)) {
  3031. case IS_STRING:
  3032. if (Z_STRLEN_PP(val) == 0) {
  3033. ZVAL_STRING(new_val, "NULL", 1);
  3034. }
  3035. else {
  3036. /* FIXME: better regex must be used */
  3037. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[+-]{0,1}[ \\t]+((second|seconds|minute|minute|hour|hour|day|days|week|weeks|month|monthes|year|years|decade|decades|century|centuries|millennium|millenniums){1,1}[ \\t]+)+([ \\t]+ago){0,1}$", 1 TSRMLS_CC) == FAILURE &&
  3038. php_pgsql_convert_match(Z_STRVAL_PP(val), "^@[ \\t]+[+-]{0,1}[ \\t]+(second|seconds|minute|minute|hour|hour|day|days|week|weeks|month|monthes|year|years|decade|decades|century|centuries|millennium|millenniums){1,1}[ \\t]+)+([ \\t]+ago$", 1 TSRMLS_CC) == FAILURE) {
  3039. err = 1;
  3040. }
  3041. else {
  3042. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  3043. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  3044. }
  3045. }
  3046. break;
  3047. case IS_NULL:
  3048. ZVAL_STRING(new_val, "NULL", 1);
  3049. break;
  3050. default:
  3051. err = 1;
  3052. }
  3053. if (err) {
  3054. php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
  3055. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  3056. }
  3057. break;
  3058. #ifdef HAVE_PQESCAPE
  3059. case PG_BYTEA:
  3060. switch (Z_TYPE_PP(val)) {
  3061. case IS_STRING:
  3062. if (Z_STRLEN_PP(val) == 0) {
  3063. ZVAL_STRING(new_val, "NULL", 1);
  3064. }
  3065. else {
  3066. unsigned char *tmp;
  3067. size_t to_len;
  3068. tmp = PQescapeBytea(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
  3069. Z_TYPE_P(new_val) = IS_STRING;
  3070. Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
  3071. Z_STRVAL_P(new_val) = emalloc(to_len);
  3072. memcpy(Z_STRVAL_P(new_val), tmp, to_len);
  3073. free(tmp);
  3074. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  3075. }
  3076. break;
  3077. case IS_LONG:
  3078. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  3079. convert_to_string_ex(&new_val);
  3080. break;
  3081. case IS_DOUBLE:
  3082. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  3083. convert_to_string_ex(&new_val);
  3084. break;
  3085. case IS_NULL:
  3086. ZVAL_STRING(new_val, "NULL", 1);
  3087. break;
  3088. default:
  3089. err = 1;
  3090. }
  3091. if (err) {
  3092. php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
  3093. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  3094. }
  3095. break;
  3096. #endif
  3097. case PG_MACADDR:
  3098. switch(Z_TYPE_PP(val)) {
  3099. case IS_STRING:
  3100. if (Z_STRLEN_PP(val) == 0) {
  3101. ZVAL_STRING(new_val, "NULL", 1);
  3102. }
  3103. else {
  3104. /* FIXME: better regex must be used */
  3105. if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{2,2}:){5,5}[0-9]{2,2}$", 1 TSRMLS_CC) == FAILURE) {
  3106. err = 1;
  3107. }
  3108. else {
  3109. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  3110. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  3111. }
  3112. }
  3113. break;
  3114. case IS_NULL:
  3115. ZVAL_STRING(new_val, "NULL", 1);
  3116. break;
  3117. default:
  3118. err = 1;
  3119. }
  3120. if (err) {
  3121. php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
  3122. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  3123. }
  3124. break;
  3125. /* bit */
  3126. case PG_BIT:
  3127. case PG_VARBIT:
  3128. /* geometoric */
  3129. case PG_LINE:
  3130. case PG_LSEG:
  3131. case PG_POINT:
  3132. case PG_BOX:
  3133. case PG_PATH:
  3134. case PG_POLYGON:
  3135. case PG_CIRCLE:
  3136. php_error(E_NOTICE, "%s() does not support pgsql '%s' type (%s)",
  3137. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  3138. err = 1;
  3139. break;
  3140. case PG_UNKNOWN:
  3141. default:
  3142. php_error(E_NOTICE, "%s() unknown or system data type '%s' for '%s'",
  3143. get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
  3144. err = 1;
  3145. break;
  3146. } /* switch */
  3147. if (err) {
  3148. zval_dtor(new_val);
  3149. FREE_ZVAL(new_val);
  3150. break;
  3151. }
  3152. field = php_addslashes(field, strlen(field), &new_len, 0 TSRMLS_CC);
  3153. add_assoc_zval(result, field, new_val);
  3154. efree(field);
  3155. } /* for */
  3156. zval_dtor(meta);
  3157. FREE_ZVAL(meta);
  3158. if (err) {
  3159. /* shouldn't destroy & free zval here */
  3160. return FAILURE;
  3161. }
  3162. return SUCCESS;
  3163. }
  3164. /* }}} */
  3165. /* {{{ proto array pg_convert(resource db, string table, array values)
  3166. Check and convert values for PostgreSQL SQL statement */
  3167. PHP_FUNCTION(pg_convert)
  3168. {
  3169. zval *pgsql_link, *values;
  3170. char *table_name;
  3171. size_t table_name_len;
  3172. PGconn *pg_link;
  3173. int id = -1;
  3174. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
  3175. "rsa", &pgsql_link, &table_name, &table_name_len, &values) == FAILURE) {
  3176. return;
  3177. }
  3178. if (!table_name_len) {
  3179. php_error(E_NOTICE, "%s() table name is invalid",
  3180. get_active_function_name(TSRMLS_C));
  3181. RETURN_FALSE;
  3182. }
  3183. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3184. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  3185. php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
  3186. get_active_function_name(TSRMLS_C));
  3187. }
  3188. array_init(return_value);
  3189. if (php_pgsql_convert(pg_link, table_name, values, return_value TSRMLS_CC) == FAILURE) {
  3190. zval_dtor(return_value);
  3191. RETURN_FALSE;
  3192. }
  3193. }
  3194. /* }}} */
  3195. /* {{{ php_pgsql_insert
  3196. */
  3197. PHPAPI int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, zend_bool convert, zend_bool async TSRMLS_DC)
  3198. {
  3199. zval **val, *converted = NULL;
  3200. char *query_tpl = "INSERT INTO %s (%s) VALUES (%s);";
  3201. char *query, *fields, *fields_pos, *values, *values_pos, *fld, buf[256];
  3202. size_t fields_len = 1, values_len = 1;
  3203. int key_type, fld_len, ret = SUCCESS;
  3204. ulong num_idx;
  3205. HashPosition pos;
  3206. assert(pg_link != NULL);
  3207. assert(table != NULL);
  3208. assert(Z_TYPE_P(var_array) == IS_ARRAY);
  3209. assert(convert == 1 || convert == 0);
  3210. assert(async == 1 || async == 0);
  3211. /* convert input array if needed */
  3212. if (convert) {
  3213. MAKE_STD_ZVAL(converted);
  3214. array_init(converted);
  3215. if (php_pgsql_convert(pg_link, table, var_array, converted TSRMLS_CC) == FAILURE) {
  3216. zval_dtor(converted);
  3217. FREE_ZVAL(converted);
  3218. return FAILURE;
  3219. }
  3220. var_array = converted;
  3221. }
  3222. /* compute length */
  3223. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  3224. zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
  3225. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
  3226. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);
  3227. if (key_type == HASH_KEY_IS_LONG) {
  3228. if (convert) {
  3229. zval_dtor(converted);
  3230. FREE_ZVAL(converted);
  3231. }
  3232. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3233. get_active_function_name(TSRMLS_C));
  3234. return FAILURE;
  3235. }
  3236. switch(Z_TYPE_PP(val)) {
  3237. case IS_STRING:
  3238. values_len += Z_STRLEN_PP(val);
  3239. break;
  3240. case IS_LONG:
  3241. values_len += 30;
  3242. break;
  3243. case IS_DOUBLE:
  3244. values_len += 60;
  3245. break;
  3246. default:
  3247. if (convert) {
  3248. zval_dtor(converted);
  3249. FREE_ZVAL(converted);
  3250. }
  3251. php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
  3252. get_active_function_name(TSRMLS_C));
  3253. return FAILURE;
  3254. }
  3255. fields_len += fld_len+1;
  3256. }
  3257. if (fields_len == 1 || values_len == 1) {
  3258. /* there aren't any fields to insert */
  3259. if (convert) {
  3260. zval_dtor(converted);
  3261. FREE_ZVAL(converted);
  3262. }
  3263. return FAILURE;
  3264. }
  3265. fields = (char *)emalloc(fields_len+1);
  3266. if (fields == NULL) {
  3267. if (convert) {
  3268. zval_dtor(converted);
  3269. FREE_ZVAL(converted);
  3270. }
  3271. php_error(E_WARNING, "%s() cannot allocate memory",
  3272. get_active_function_name(TSRMLS_C));
  3273. return FAILURE;
  3274. }
  3275. fields_pos = fields;
  3276. values = (char *)emalloc(values_len+1);
  3277. if (values == NULL) {
  3278. if (convert) {
  3279. zval_dtor(converted);
  3280. FREE_ZVAL(converted);
  3281. }
  3282. efree(fields);
  3283. php_error(E_WARNING, "%s() cannot allocate memory",
  3284. get_active_function_name(TSRMLS_C));
  3285. return FAILURE;
  3286. }
  3287. values_pos = values;
  3288. query = (char *)emalloc(strlen(query_tpl)+strlen(table)+fields_len+values_len+1);
  3289. if (query == NULL) {
  3290. if (convert) {
  3291. zval_dtor(converted);
  3292. FREE_ZVAL(converted);
  3293. }
  3294. efree(fields);
  3295. efree(values);
  3296. php_error(E_WARNING, "%s() cannot allocate memory",
  3297. get_active_function_name(TSRMLS_C));
  3298. return FAILURE;
  3299. }
  3300. /* make fields and values string */
  3301. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  3302. zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
  3303. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
  3304. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);
  3305. if (key_type == HASH_KEY_IS_LONG) {
  3306. if (convert) {
  3307. zval_dtor(converted);
  3308. FREE_ZVAL(converted);
  3309. }
  3310. efree(fields);
  3311. efree(values);
  3312. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3313. get_active_function_name(TSRMLS_C));
  3314. return FAILURE;
  3315. }
  3316. switch(Z_TYPE_PP(val)) {
  3317. case IS_STRING:
  3318. memcpy(values_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  3319. values_pos += Z_STRLEN_PP(val);
  3320. break;
  3321. case IS_LONG:
  3322. sprintf(buf, "%ld", Z_LVAL_PP(val));
  3323. memcpy(values_pos, buf, strlen(buf));
  3324. values_pos += strlen(buf);
  3325. break;
  3326. case IS_DOUBLE:
  3327. sprintf(buf, "%f", Z_DVAL_PP(val));
  3328. memcpy(values_pos, buf, strlen(buf));
  3329. values_pos += strlen(buf);
  3330. break;
  3331. default:
  3332. /* should not happen */
  3333. if (convert) {
  3334. zval_dtor(converted);
  3335. FREE_ZVAL(converted);
  3336. }
  3337. efree(fields);
  3338. efree(values);
  3339. php_error(E_WARNING, "%s(): Report this error to php-dev@lists.php.net",
  3340. get_active_function_name(TSRMLS_C));
  3341. return FAILURE;
  3342. break;
  3343. }
  3344. *values_pos = ',';
  3345. values_pos++;
  3346. memcpy(fields_pos, fld, fld_len-1);
  3347. fields_pos += fld_len-1;
  3348. *fields_pos = ',';
  3349. fields_pos++;
  3350. }
  3351. /* php_log_err(values); */
  3352. values_pos--;
  3353. *values_pos = '\0';
  3354. fields_pos--;
  3355. *fields_pos = '\0';
  3356. if (convert) {
  3357. zval_dtor(converted);
  3358. FREE_ZVAL(converted);
  3359. }
  3360. sprintf(query, query_tpl, table, fields, values);
  3361. efree(fields);
  3362. efree(values);
  3363. /* php_log_err(query); */
  3364. if (async) {
  3365. if (!PQsendQuery(pg_link, query)) {
  3366. ret = FAILURE;
  3367. }
  3368. }
  3369. else {
  3370. PGresult *pg_result;
  3371. pg_result = PQexec(pg_link, query);
  3372. if (PQresultStatus(pg_result) != PGRES_COMMAND_OK) {
  3373. ret = FAILURE;
  3374. php_error(E_NOTICE, "%s() failed to insert '%s'",
  3375. get_active_function_name(TSRMLS_C), query);
  3376. PQclear(pg_result);
  3377. }
  3378. }
  3379. efree(query);
  3380. return ret;
  3381. }
  3382. /* }}} */
  3383. /* {{{ proto bool pg_insert(resource db, string table, array values[, bool convert[, bool async]])
  3384. Insert values (filed=>value) to table */
  3385. PHP_FUNCTION(pg_insert)
  3386. {
  3387. zval *pgsql_link, *values;
  3388. char *table;
  3389. ulong table_len;
  3390. zend_bool convert = 1, async = 1;
  3391. PGconn *pg_link;
  3392. int id = -1, argc = ZEND_NUM_ARGS();
  3393. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|bb",
  3394. &pgsql_link, &table, &table_len, &values, &convert, &async) == FAILURE) {
  3395. return;
  3396. }
  3397. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3398. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  3399. php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
  3400. get_active_function_name(TSRMLS_C));
  3401. }
  3402. if (php_pgsql_insert(pg_link, table, values, convert, async TSRMLS_CC) == FAILURE) {
  3403. RETURN_FALSE;
  3404. }
  3405. RETURN_TRUE;
  3406. }
  3407. /* }}} */
  3408. /* {{{ php_pgsql_update
  3409. */
  3410. PHPAPI int php_pgsql_update(PGconn *pg_link, const char *table, zval *var_array, zval *ids_array, zend_bool convert, zend_bool async TSRMLS_DC)
  3411. {
  3412. zval **val, *var_converted = NULL, *ids_converted = NULL;
  3413. char *query_tpl = "UPDATE %s SET %s WHERE %s;";
  3414. char *query, *values, *values_pos, *ids, *ids_pos, *fld, buf[256];
  3415. size_t fields_len = 1, values_len = 1, idsf_len = 1, idsv_len = 1, fld_len;
  3416. int key_type, ret = SUCCESS;
  3417. ulong num_idx;
  3418. HashPosition pos;
  3419. assert(pg_link != NULL);
  3420. assert(table != NULL);
  3421. assert(Z_TYPE_P(var_array) == IS_ARRAY);
  3422. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  3423. assert(convert == 1 || convert == 0);
  3424. assert(async == 1 || async == 0);
  3425. if (convert) {
  3426. MAKE_STD_ZVAL(var_converted);
  3427. array_init(var_converted);
  3428. if (php_pgsql_convert(pg_link, table, var_array, var_converted TSRMLS_CC) == FAILURE) {
  3429. zval_dtor(var_converted);
  3430. FREE_ZVAL(var_converted);
  3431. return FAILURE;
  3432. }
  3433. var_array = var_converted;
  3434. MAKE_STD_ZVAL(ids_converted);
  3435. array_init(ids_converted);
  3436. if (php_pgsql_convert(pg_link, table, ids_array, ids_converted TSRMLS_CC) == FAILURE) {
  3437. zval_dtor(var_converted);
  3438. FREE_ZVAL(var_converted);
  3439. zval_dtor(ids_converted);
  3440. FREE_ZVAL(ids_converted);
  3441. return FAILURE;
  3442. }
  3443. ids_array = ids_converted;
  3444. }
  3445. /* compute length */
  3446. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  3447. zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
  3448. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
  3449. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);
  3450. if (key_type == HASH_KEY_IS_LONG) {
  3451. if (convert) {
  3452. zval_dtor(var_converted);
  3453. FREE_ZVAL(var_converted);
  3454. }
  3455. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3456. get_active_function_name(TSRMLS_C));
  3457. return FAILURE;
  3458. }
  3459. switch(Z_TYPE_PP(val)) {
  3460. case IS_STRING:
  3461. values_len += Z_STRLEN_PP(val);
  3462. break;
  3463. case IS_LONG:
  3464. values_len += 30;
  3465. break;
  3466. case IS_DOUBLE:
  3467. values_len += 60;
  3468. break;
  3469. default:
  3470. php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
  3471. get_active_function_name(TSRMLS_C));
  3472. if (convert) {
  3473. zval_dtor(var_converted);
  3474. FREE_ZVAL(var_converted);
  3475. }
  3476. break;
  3477. }
  3478. fields_len += fld_len+2; /* field name + '=' + ',' */
  3479. }
  3480. if (fields_len == 1 || values_len == 1) {
  3481. if (convert) {
  3482. zval_dtor(var_converted);
  3483. FREE_ZVAL(var_converted);
  3484. }
  3485. return FAILURE;
  3486. }
  3487. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
  3488. zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
  3489. zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
  3490. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
  3491. if (key_type == HASH_KEY_IS_LONG) {
  3492. if (convert) {
  3493. zval_dtor(var_converted);
  3494. FREE_ZVAL(var_converted);
  3495. zval_dtor(ids_converted);
  3496. FREE_ZVAL(ids_converted);
  3497. }
  3498. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3499. get_active_function_name(TSRMLS_C));
  3500. return FAILURE;
  3501. }
  3502. switch(Z_TYPE_PP(val)) {
  3503. case IS_STRING:
  3504. idsv_len += Z_STRLEN_PP(val);
  3505. break;
  3506. case IS_LONG:
  3507. idsv_len += 30;
  3508. break;
  3509. case IS_DOUBLE:
  3510. idsv_len += 60;
  3511. break;
  3512. default:
  3513. php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
  3514. get_active_function_name(TSRMLS_C));
  3515. if (convert) {
  3516. zval_dtor(var_converted);
  3517. FREE_ZVAL(var_converted);
  3518. zval_dtor(ids_converted);
  3519. FREE_ZVAL(ids_converted);
  3520. }
  3521. return FAILURE;
  3522. }
  3523. idsf_len += fld_len+6; /* field name + '=' + ' AND ' */
  3524. }
  3525. if (fields_len == 1 || values_len == 1 || idsv_len == 1 || idsf_len == 1) {
  3526. if (convert) {
  3527. zval_dtor(var_converted);
  3528. FREE_ZVAL(var_converted);
  3529. zval_dtor(ids_converted);
  3530. FREE_ZVAL(ids_converted);
  3531. }
  3532. return FAILURE;
  3533. }
  3534. values = (char *)emalloc(fields_len + values_len);
  3535. if (values == NULL) {
  3536. if (convert) {
  3537. zval_dtor(var_converted);
  3538. FREE_ZVAL(var_converted);
  3539. zval_dtor(ids_converted);
  3540. FREE_ZVAL(ids_converted);
  3541. }
  3542. php_error(E_WARNING, "%s() cannot allocate memory",
  3543. get_active_function_name(TSRMLS_C));
  3544. return FAILURE;
  3545. }
  3546. values_pos = values;
  3547. ids = (char *)emalloc(idsf_len + idsv_len);
  3548. if (ids == NULL) {
  3549. if (convert) {
  3550. zval_dtor(var_converted);
  3551. FREE_ZVAL(var_converted);
  3552. zval_dtor(ids_converted);
  3553. FREE_ZVAL(ids_converted);
  3554. }
  3555. efree(values);
  3556. php_error(E_WARNING, "%s() cannot allocate memory",
  3557. get_active_function_name(TSRMLS_C));
  3558. return FAILURE;
  3559. }
  3560. ids_pos = ids;
  3561. query = (char *)emalloc(strlen(query_tpl) + strlen(table) + fields_len + values_len + idsf_len + idsv_len);
  3562. if (query == NULL) {
  3563. if (convert) {
  3564. zval_dtor(var_converted);
  3565. FREE_ZVAL(var_converted);
  3566. zval_dtor(ids_converted);
  3567. FREE_ZVAL(ids_converted);
  3568. }
  3569. efree(values);
  3570. efree(ids);
  3571. php_error(E_WARNING, "%s() cannot allocate memory",
  3572. get_active_function_name(TSRMLS_C));
  3573. return FAILURE;
  3574. }
  3575. /* make values and ids string */
  3576. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  3577. zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
  3578. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
  3579. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);
  3580. if (key_type == HASH_KEY_IS_LONG) {
  3581. if (convert) {
  3582. zval_dtor(var_converted);
  3583. FREE_ZVAL(var_converted);
  3584. zval_dtor(ids_converted);
  3585. FREE_ZVAL(ids_converted);
  3586. }
  3587. efree(ids);
  3588. efree(values);
  3589. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3590. get_active_function_name(TSRMLS_C));
  3591. return FAILURE;
  3592. }
  3593. memcpy(values_pos, fld, fld_len-1);
  3594. values_pos += fld_len-1;
  3595. *values_pos = '=';
  3596. values_pos++;
  3597. switch(Z_TYPE_PP(val)) {
  3598. case IS_STRING:
  3599. memcpy(values_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  3600. values_pos += Z_STRLEN_PP(val);
  3601. break;
  3602. case IS_LONG:
  3603. sprintf(buf, "%ld", Z_LVAL_PP(val));
  3604. memcpy(values_pos, buf, strlen(buf));
  3605. values_pos += strlen(buf);
  3606. break;
  3607. case IS_DOUBLE:
  3608. sprintf(buf, "%f", Z_DVAL_PP(val));
  3609. memcpy(values_pos, buf, strlen(buf));
  3610. values_pos += strlen(buf);
  3611. break;
  3612. default:
  3613. /* should not happen */
  3614. php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
  3615. get_active_function_name(TSRMLS_C));
  3616. }
  3617. *values_pos = ',';
  3618. values_pos++;
  3619. }
  3620. values_pos--;
  3621. *values_pos = '\0';
  3622. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
  3623. zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
  3624. zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
  3625. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
  3626. if (key_type == HASH_KEY_IS_LONG) {
  3627. if (convert) {
  3628. zval_dtor(var_converted);
  3629. FREE_ZVAL(var_converted);
  3630. zval_dtor(ids_converted);
  3631. FREE_ZVAL(ids_converted);
  3632. }
  3633. efree(ids);
  3634. efree(values);
  3635. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3636. get_active_function_name(TSRMLS_C));
  3637. return FAILURE;
  3638. }
  3639. memcpy(ids_pos, fld, fld_len-1);
  3640. ids_pos += fld_len-1;
  3641. *ids_pos = '=';
  3642. ids_pos++;
  3643. switch(Z_TYPE_PP(val)) {
  3644. case IS_STRING:
  3645. memcpy(ids_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  3646. ids_pos += Z_STRLEN_PP(val);
  3647. break;
  3648. case IS_LONG:
  3649. sprintf(buf, "%ld", Z_LVAL_PP(val));
  3650. memcpy(ids_pos, buf, strlen(buf));
  3651. ids_pos += strlen(buf);
  3652. break;
  3653. case IS_DOUBLE:
  3654. sprintf(buf, "%f", Z_DVAL_PP(val));
  3655. memcpy(ids_pos, buf, strlen(buf));
  3656. ids_pos += strlen(buf);
  3657. break;
  3658. default:
  3659. /* should not happen */
  3660. php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
  3661. get_active_function_name(TSRMLS_C));
  3662. }
  3663. memcpy(ids_pos, " AND ", 5);
  3664. ids_pos += 5;
  3665. }
  3666. ids_pos -= 5;
  3667. *ids_pos = '\0';
  3668. if (convert) {
  3669. zval_dtor(var_converted);
  3670. FREE_ZVAL(var_converted);
  3671. zval_dtor(ids_converted);
  3672. FREE_ZVAL(ids_converted);
  3673. }
  3674. sprintf(query, query_tpl, table, values, ids);
  3675. efree(ids);
  3676. efree(values);
  3677. if (async) {
  3678. if (!PQsendQuery(pg_link, query)) {
  3679. ret = FAILURE;
  3680. }
  3681. }
  3682. else {
  3683. PGresult *pg_result;
  3684. pg_result = PQexec(pg_link, query);
  3685. if (PQresultStatus(pg_result) != PGRES_COMMAND_OK) {
  3686. ret = FAILURE;
  3687. php_error(E_NOTICE, "%s() failed to update '%s'",
  3688. get_active_function_name(TSRMLS_C), query);
  3689. PQclear(pg_result);
  3690. }
  3691. }
  3692. efree(query);
  3693. return ret;
  3694. }
  3695. /* }}} */
  3696. /* {{{ proto bool pg_update(resource db, string table, array fields, array ids[, bool convert[, bool async]])
  3697. Update table using values (field=>value) and ids (id=>value) */
  3698. PHP_FUNCTION(pg_update)
  3699. {
  3700. zval *pgsql_link, *values, *ids;
  3701. char *table;
  3702. ulong table_len;
  3703. zend_bool convert = 1, async = 1;
  3704. PGconn *pg_link;
  3705. int id = -1, argc = ZEND_NUM_ARGS();
  3706. if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|bb",
  3707. &pgsql_link, &table, &table_len, &values, &ids, &convert, &async) == FAILURE) {
  3708. return;
  3709. }
  3710. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3711. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  3712. php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
  3713. get_active_function_name(TSRMLS_C));
  3714. }
  3715. if (php_pgsql_update(pg_link, table, values, ids, convert, async TSRMLS_CC) == FAILURE) {
  3716. RETURN_FALSE;
  3717. }
  3718. RETURN_TRUE;
  3719. }
  3720. /* }}} */
  3721. /* {{{ php_pgsql_delete
  3722. */
  3723. PHPAPI int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, zend_bool convert, zend_bool async TSRMLS_DC)
  3724. {
  3725. zval **val, *ids_converted = NULL;
  3726. char *query_tpl = "DELETE FROM %s WHERE %s;";
  3727. char *query, *ids, *ids_pos, *fld, buf[256];
  3728. size_t idsf_len = 1, idsv_len = 1, fld_len;
  3729. int key_type, ret = SUCCESS;
  3730. ulong num_idx;
  3731. HashPosition pos;
  3732. assert(pg_link != NULL);
  3733. assert(table != NULL);
  3734. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  3735. assert(convert == 1 || convert == 0);
  3736. assert(async == 1 || async == 0);
  3737. if (convert) {
  3738. MAKE_STD_ZVAL(ids_converted);
  3739. array_init(ids_converted);
  3740. if (php_pgsql_convert(pg_link, table, ids_array, ids_converted TSRMLS_CC) == FAILURE) {
  3741. zval_dtor(ids_converted);
  3742. FREE_ZVAL(ids_converted);
  3743. return FAILURE;
  3744. }
  3745. ids_array = ids_converted;
  3746. }
  3747. /* compute length */
  3748. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
  3749. zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
  3750. zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
  3751. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
  3752. if (key_type == HASH_KEY_IS_LONG) {
  3753. if (convert) {
  3754. zval_dtor(ids_converted);
  3755. FREE_ZVAL(ids_converted);
  3756. }
  3757. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3758. get_active_function_name(TSRMLS_C));
  3759. return FAILURE;
  3760. }
  3761. switch(Z_TYPE_PP(val)) {
  3762. case IS_STRING:
  3763. idsv_len += Z_STRLEN_PP(val);
  3764. break;
  3765. case IS_LONG:
  3766. idsv_len += 30;
  3767. break;
  3768. case IS_DOUBLE:
  3769. idsv_len += 60;
  3770. break;
  3771. default:
  3772. php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
  3773. get_active_function_name(TSRMLS_C));
  3774. if (convert) {
  3775. zval_dtor(ids_converted);
  3776. FREE_ZVAL(ids_converted);
  3777. }
  3778. return FAILURE;
  3779. }
  3780. idsf_len += fld_len+6; /* field name + '=' + ' AND ' */
  3781. }
  3782. if (idsv_len == 1 || idsf_len == 1) {
  3783. if (convert) {
  3784. zval_dtor(ids_converted);
  3785. FREE_ZVAL(ids_converted);
  3786. }
  3787. return FAILURE;
  3788. }
  3789. ids = (char *)emalloc(idsf_len + idsv_len);
  3790. if (ids == NULL) {
  3791. if (convert) {
  3792. zval_dtor(ids_converted);
  3793. FREE_ZVAL(ids_converted);
  3794. }
  3795. php_error(E_WARNING, "%s() cannot allocate memory",
  3796. get_active_function_name(TSRMLS_C));
  3797. return FAILURE;
  3798. }
  3799. ids_pos = ids;
  3800. query = (char *)emalloc(strlen(query_tpl)+strlen(table)+idsf_len+idsv_len);
  3801. if (query == NULL) {
  3802. if (convert) {
  3803. zval_dtor(ids_converted);
  3804. FREE_ZVAL(ids_converted);
  3805. }
  3806. efree(ids);
  3807. php_error(E_WARNING, "%s() cannot allocate memory",
  3808. get_active_function_name(TSRMLS_C));
  3809. return FAILURE;
  3810. }
  3811. /* make values and ids string */
  3812. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
  3813. zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
  3814. zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
  3815. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
  3816. if (key_type == HASH_KEY_IS_LONG) {
  3817. if (convert) {
  3818. zval_dtor(ids_converted);
  3819. FREE_ZVAL(ids_converted);
  3820. }
  3821. efree(ids);
  3822. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3823. get_active_function_name(TSRMLS_C));
  3824. return FAILURE;
  3825. }
  3826. memcpy(ids_pos, fld, fld_len-1);
  3827. ids_pos += fld_len-1;
  3828. *ids_pos = '=';
  3829. ids_pos++;
  3830. switch(Z_TYPE_PP(val)) {
  3831. case IS_STRING:
  3832. memcpy(ids_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  3833. ids_pos += Z_STRLEN_PP(val);
  3834. break;
  3835. case IS_LONG:
  3836. sprintf(buf, "%ld", Z_LVAL_PP(val));
  3837. memcpy(ids_pos, buf, strlen(buf));
  3838. ids_pos += strlen(buf);
  3839. break;
  3840. case IS_DOUBLE:
  3841. sprintf(buf, "%f", Z_DVAL_PP(val));
  3842. memcpy(ids_pos, buf, strlen(buf));
  3843. ids_pos += strlen(buf);
  3844. break;
  3845. default:
  3846. /* should not happen */
  3847. php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
  3848. get_active_function_name(TSRMLS_C));
  3849. }
  3850. memcpy(ids_pos, " AND ", 5);
  3851. ids_pos += 5;
  3852. }
  3853. ids_pos -= 5;
  3854. *ids_pos = '\0';
  3855. if (convert) {
  3856. zval_dtor(ids_converted);
  3857. FREE_ZVAL(ids_converted);
  3858. }
  3859. sprintf(query, query_tpl, table, ids);
  3860. efree(ids);
  3861. if (async) {
  3862. if (!PQsendQuery(pg_link, query)) {
  3863. ret = FAILURE;
  3864. }
  3865. }
  3866. else {
  3867. PGresult *pg_result;
  3868. pg_result = PQexec(pg_link, query);
  3869. if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
  3870. ret = FAILURE;
  3871. php_error(E_NOTICE, "%s() failed to update '%s'",
  3872. get_active_function_name(TSRMLS_C), query);
  3873. PQclear(pg_result);
  3874. }
  3875. }
  3876. efree(query);
  3877. return ret;
  3878. }
  3879. /* }}} */
  3880. /* {{{ proto bool pg_delete(resource db, string table, array ids[, bool convert[, bool async]])
  3881. Delete records has ids (id=>value) */
  3882. PHP_FUNCTION(pg_delete)
  3883. {
  3884. zval *pgsql_link, *ids;
  3885. char *table;
  3886. ulong table_len;
  3887. zend_bool convert = 1, async = 1;
  3888. PGconn *pg_link;
  3889. int id = -1, argc = ZEND_NUM_ARGS();
  3890. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|bb",
  3891. &pgsql_link, &table, &table_len, &ids, &convert, &async) == FAILURE) {
  3892. return;
  3893. }
  3894. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3895. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  3896. php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
  3897. get_active_function_name(TSRMLS_C));
  3898. }
  3899. if (php_pgsql_delete(pg_link, table, ids, convert, async TSRMLS_CC) == FAILURE) {
  3900. RETURN_FALSE;
  3901. }
  3902. RETURN_TRUE;
  3903. }
  3904. /* }}} */
  3905. /* {{{ php_pgsql_result2array
  3906. */
  3907. PHPAPI int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TSRMLS_DC)
  3908. {
  3909. zval *row;
  3910. char *field_name, *element, *data;
  3911. size_t num_fields, element_len, data_len;
  3912. int pg_numrows, pg_row, i;
  3913. assert(Z_TYPE_P(ret_array) == IS_ARRAY);
  3914. if ((pg_numrows = PQntuples(pg_result)) <= 0) {
  3915. return FAILURE;
  3916. }
  3917. for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
  3918. MAKE_STD_ZVAL(row);
  3919. array_init(row);
  3920. add_index_zval(ret_array, pg_row, row);
  3921. for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
  3922. if (PQgetisnull(pg_result, pg_row, i)) {
  3923. field_name = PQfname(pg_result, i);
  3924. add_assoc_null(row, field_name);
  3925. } else {
  3926. element = PQgetvalue(pg_result, pg_row, i);
  3927. element_len = (element ? strlen(element) : 0);
  3928. if (element) {
  3929. if (PG(magic_quotes_runtime)) {
  3930. data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
  3931. } else {
  3932. data = safe_estrndup(element, element_len);
  3933. data_len = element_len;
  3934. }
  3935. field_name = PQfname(pg_result, i);
  3936. add_assoc_stringl(row, field_name, data, data_len, 0);
  3937. }
  3938. }
  3939. }
  3940. }
  3941. return SUCCESS;
  3942. }
  3943. /* }}} */
  3944. /* {{{ php_pgsql_select
  3945. */
  3946. PHPAPI int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, zend_bool convert TSRMLS_DC)
  3947. {
  3948. zval **val, *ids_converted = NULL;
  3949. char *query_tpl = "SELECT * FROM %s WHERE %s;";
  3950. char *query, *ids, *ids_pos, *fld, buf[256];
  3951. size_t idsf_len = 1, idsv_len = 1, fld_len;
  3952. int key_type, ret = SUCCESS;
  3953. PGresult *pg_result;
  3954. ulong num_idx;
  3955. HashPosition pos;
  3956. assert(pg_link != NULL);
  3957. assert(table != NULL);
  3958. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  3959. assert(Z_TYPE_P(ret_array) == IS_ARRAY);
  3960. assert(convert == 1 || convert == 0);
  3961. if (convert) {
  3962. MAKE_STD_ZVAL(ids_converted);
  3963. array_init(ids_converted);
  3964. if (php_pgsql_convert(pg_link, table, ids_array, ids_converted TSRMLS_CC) == FAILURE) {
  3965. zval_dtor(ids_converted);
  3966. FREE_ZVAL(ids_converted);
  3967. return FAILURE;
  3968. }
  3969. ids_array = ids_converted;
  3970. }
  3971. /* compute length */
  3972. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
  3973. zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
  3974. zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
  3975. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
  3976. if (key_type == HASH_KEY_IS_LONG) {
  3977. if (convert) {
  3978. zval_dtor(ids_converted);
  3979. FREE_ZVAL(ids_converted);
  3980. }
  3981. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  3982. get_active_function_name(TSRMLS_C));
  3983. return FAILURE;
  3984. }
  3985. switch(Z_TYPE_PP(val)) {
  3986. case IS_STRING:
  3987. idsv_len += Z_STRLEN_PP(val);
  3988. break;
  3989. case IS_LONG:
  3990. idsv_len += 30;
  3991. break;
  3992. case IS_DOUBLE:
  3993. idsv_len += 60;
  3994. break;
  3995. default:
  3996. php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
  3997. get_active_function_name(TSRMLS_C));
  3998. if (convert) {
  3999. zval_dtor(ids_converted);
  4000. FREE_ZVAL(ids_converted);
  4001. }
  4002. return FAILURE;
  4003. }
  4004. idsf_len += fld_len+6; /* field name + '=' + ' AND ' */
  4005. }
  4006. if (idsv_len == 1 || idsf_len == 1) {
  4007. if (convert) {
  4008. zval_dtor(ids_converted);
  4009. FREE_ZVAL(ids_converted);
  4010. }
  4011. return FAILURE;
  4012. }
  4013. ids = (char *)emalloc(idsf_len + idsv_len);
  4014. if (ids == NULL) {
  4015. if (convert) {
  4016. zval_dtor(ids_converted);
  4017. FREE_ZVAL(ids_converted);
  4018. }
  4019. php_error(E_WARNING, "%s() cannot allocate memory",
  4020. get_active_function_name(TSRMLS_C));
  4021. return FAILURE;
  4022. }
  4023. ids_pos = ids;
  4024. query = (char *)emalloc(strlen(query_tpl)+strlen(table)+idsf_len+idsv_len);
  4025. if (query == NULL) {
  4026. if (convert) {
  4027. zval_dtor(ids_converted);
  4028. FREE_ZVAL(ids_converted);
  4029. }
  4030. efree(ids);
  4031. php_error(E_WARNING, "%s() cannot allocate memory",
  4032. get_active_function_name(TSRMLS_C));
  4033. return FAILURE;
  4034. }
  4035. /* make values and ids string */
  4036. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
  4037. zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
  4038. zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
  4039. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
  4040. if (key_type == HASH_KEY_IS_LONG) {
  4041. if (convert) {
  4042. zval_dtor(ids_converted);
  4043. FREE_ZVAL(ids_converted);
  4044. }
  4045. efree(ids);
  4046. php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
  4047. get_active_function_name(TSRMLS_C));
  4048. return FAILURE;
  4049. }
  4050. memcpy(ids_pos, fld, fld_len-1);
  4051. ids_pos += fld_len-1;
  4052. *ids_pos = '=';
  4053. ids_pos++;
  4054. switch(Z_TYPE_PP(val)) {
  4055. case IS_STRING:
  4056. memcpy(ids_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  4057. ids_pos += Z_STRLEN_PP(val);
  4058. break;
  4059. case IS_LONG:
  4060. sprintf(buf, "%ld", Z_LVAL_PP(val));
  4061. memcpy(ids_pos, buf, strlen(buf));
  4062. ids_pos += strlen(buf);
  4063. break;
  4064. case IS_DOUBLE:
  4065. sprintf(buf, "%f", Z_DVAL_PP(val));
  4066. memcpy(ids_pos, buf, strlen(buf));
  4067. ids_pos += strlen(buf);
  4068. break;
  4069. default:
  4070. /* should not happen */
  4071. php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
  4072. get_active_function_name(TSRMLS_C));
  4073. }
  4074. memcpy(ids_pos, " AND ", 5);
  4075. ids_pos += 5;
  4076. }
  4077. ids_pos -= 5;
  4078. *ids_pos = '\0';
  4079. if (convert) {
  4080. zval_dtor(ids_converted);
  4081. FREE_ZVAL(ids_converted);
  4082. }
  4083. sprintf(query, query_tpl, table, ids);
  4084. efree(ids);
  4085. pg_result = PQexec(pg_link, query);
  4086. if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
  4087. ret = FAILURE;
  4088. php_error(E_NOTICE, "%s() failed to update '%s'",
  4089. get_active_function_name(TSRMLS_C), query);
  4090. PQclear(pg_result);
  4091. }
  4092. efree(query);
  4093. if (ret == SUCCESS) {
  4094. ret = php_pgsql_result2array(pg_result, ret_array TSRMLS_CC);
  4095. }
  4096. return ret;
  4097. }
  4098. /* }}} */
  4099. /* {{{ proto array pg_select(resource db, string table, array ids[, bool convert])
  4100. Select records that has ids (id=>value) */
  4101. PHP_FUNCTION(pg_select)
  4102. {
  4103. zval *pgsql_link, *ids;
  4104. char *table;
  4105. ulong table_len;
  4106. zend_bool convert = 1;
  4107. PGconn *pg_link;
  4108. int id = -1, argc = ZEND_NUM_ARGS();
  4109. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|b",
  4110. &pgsql_link, &table, &table_len, &ids, &convert) == FAILURE) {
  4111. return;
  4112. }
  4113. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4114. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  4115. php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
  4116. get_active_function_name(TSRMLS_C));
  4117. }
  4118. array_init(return_value);
  4119. if (php_pgsql_select(pg_link, table, ids, return_value, convert TSRMLS_CC) == FAILURE) {
  4120. zval_dtor(return_value);
  4121. RETURN_FALSE;
  4122. }
  4123. return;
  4124. }
  4125. /* }}} */
  4126. #endif
  4127. /*
  4128. * Local variables:
  4129. * tab-width: 4
  4130. * c-basic-offset: 4
  4131. * End:
  4132. * vim600: sw=4 ts=4 fdm=marker
  4133. * vim<600: sw=4 ts=4
  4134. */