1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Zeev Suraski <zeev@zend.com> |
16 : | Jouni Ahto <jouni.ahto@exdec.fi> |
17 : | Yasuo Ohgaki <yohgaki@php.net> |
18 : | Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*) |
19 : | Chris Kings-Lynne <chriskl@php.net> (v3 protocol) |
20 : +----------------------------------------------------------------------+
21 : */
22 :
23 : /* $Id: pgsql.c 290146 2009-11-02 13:33:24Z iliaa $ */
24 :
25 : #include <stdlib.h>
26 :
27 : #define PHP_PGSQL_PRIVATE 1
28 :
29 : #ifdef HAVE_CONFIG_H
30 : #include "config.h"
31 : #endif
32 :
33 : #define SMART_STR_PREALLOC 512
34 :
35 : #include "php.h"
36 : #include "php_ini.h"
37 : #include "ext/standard/php_standard.h"
38 : #include "ext/standard/php_smart_str.h"
39 :
40 : #undef PACKAGE_BUGREPORT
41 : #undef PACKAGE_NAME
42 : #undef PACKAGE_STRING
43 : #undef PACKAGE_TARNAME
44 : #undef PACKAGE_VERSION
45 : #include "php_pgsql.h"
46 : #include "php_globals.h"
47 : #include "zend_exceptions.h"
48 :
49 : #if HAVE_PGSQL
50 :
51 : #ifndef InvalidOid
52 : #define InvalidOid ((Oid) 0)
53 : #endif
54 :
55 : #define PGSQL_ASSOC 1<<0
56 : #define PGSQL_NUM 1<<1
57 : #define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
58 :
59 : #define PGSQL_STATUS_LONG 1
60 : #define PGSQL_STATUS_STRING 2
61 :
62 : #define PGSQL_MAX_LENGTH_OF_LONG 30
63 : #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
64 :
65 : #define PGSQL_RETURN_OID(oid) do { \
66 : if (oid > LONG_MAX) { \
67 : smart_str s = {0}; \
68 : smart_str_append_unsigned(&s, oid); \
69 : smart_str_0(&s); \
70 : RETURN_STRINGL(s.c, s.len, 0); \
71 : } \
72 : RETURN_LONG((long)oid); \
73 : } while(0)
74 :
75 :
76 : #if HAVE_PQSETNONBLOCKING
77 : #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
78 : #else
79 : #define PQ_SETNONBLOCKING(pg_link, flag) 0
80 : #endif
81 :
82 : #define CHECK_DEFAULT_LINK(x) if ((x) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "No PostgreSQL link opened yet"); }
83 :
84 : #ifndef HAVE_PQFREEMEM
85 : #define PQfreemem free
86 : #endif
87 :
88 : ZEND_DECLARE_MODULE_GLOBALS(pgsql)
89 : static PHP_GINIT_FUNCTION(pgsql);
90 :
91 : /* {{{ pgsql_functions[]
92 : */
93 : zend_function_entry pgsql_functions[] = {
94 : /* connection functions */
95 : PHP_FE(pg_connect, NULL)
96 : PHP_FE(pg_pconnect, NULL)
97 : PHP_FE(pg_close, NULL)
98 : PHP_FE(pg_connection_status, NULL)
99 : PHP_FE(pg_connection_busy, NULL)
100 : PHP_FE(pg_connection_reset, NULL)
101 : PHP_FE(pg_host, NULL)
102 : PHP_FE(pg_dbname, NULL)
103 : PHP_FE(pg_port, NULL)
104 : PHP_FE(pg_tty, NULL)
105 : PHP_FE(pg_options, NULL)
106 : PHP_FE(pg_version, NULL)
107 : PHP_FE(pg_ping, NULL)
108 : #if HAVE_PQPARAMETERSTATUS
109 : PHP_FE(pg_parameter_status, NULL)
110 : #endif
111 : #if HAVE_PGTRANSACTIONSTATUS
112 : PHP_FE(pg_transaction_status, NULL)
113 : #endif
114 : /* query functions */
115 : PHP_FE(pg_query, NULL)
116 : #if HAVE_PQEXECPARAMS
117 : PHP_FE(pg_query_params, NULL)
118 : #endif
119 : #if HAVE_PQPREPARE
120 : PHP_FE(pg_prepare, NULL)
121 : #endif
122 : #if HAVE_PQEXECPREPARED
123 : PHP_FE(pg_execute, NULL)
124 : #endif
125 : PHP_FE(pg_send_query, NULL)
126 : #if HAVE_PQSENDQUERYPARAMS
127 : PHP_FE(pg_send_query_params, NULL)
128 : #endif
129 : #if HAVE_PQSENDPREPARE
130 : PHP_FE(pg_send_prepare, NULL)
131 : #endif
132 : #if HAVE_PQSENDQUERYPREPARED
133 : PHP_FE(pg_send_execute, NULL)
134 : #endif
135 : PHP_FE(pg_cancel_query, NULL)
136 : /* result functions */
137 : PHP_FE(pg_fetch_result, NULL)
138 : PHP_FE(pg_fetch_row, NULL)
139 : PHP_FE(pg_fetch_assoc, NULL)
140 : PHP_FE(pg_fetch_array, NULL)
141 : PHP_FE(pg_fetch_object, NULL)
142 : PHP_FE(pg_fetch_all, NULL)
143 : PHP_FE(pg_fetch_all_columns, NULL)
144 : #if HAVE_PQCMDTUPLES
145 : PHP_FE(pg_affected_rows,NULL)
146 : #endif
147 : PHP_FE(pg_get_result, NULL)
148 : PHP_FE(pg_result_seek, NULL)
149 : PHP_FE(pg_result_status,NULL)
150 : PHP_FE(pg_free_result, NULL)
151 : PHP_FE(pg_last_oid, NULL)
152 : PHP_FE(pg_num_rows, NULL)
153 : PHP_FE(pg_num_fields, NULL)
154 : PHP_FE(pg_field_name, NULL)
155 : PHP_FE(pg_field_num, NULL)
156 : PHP_FE(pg_field_size, NULL)
157 : PHP_FE(pg_field_type, NULL)
158 : PHP_FE(pg_field_type_oid, NULL)
159 : PHP_FE(pg_field_prtlen, NULL)
160 : PHP_FE(pg_field_is_null,NULL)
161 : #ifdef HAVE_PQFTABLE
162 : PHP_FE(pg_field_table, NULL)
163 : #endif
164 : /* async message function */
165 : PHP_FE(pg_get_notify, NULL)
166 : PHP_FE(pg_get_pid, NULL)
167 : /* error message functions */
168 : PHP_FE(pg_result_error, NULL)
169 : #if HAVE_PQRESULTERRORFIELD
170 : PHP_FE(pg_result_error_field, NULL)
171 : #endif
172 : PHP_FE(pg_last_error, NULL)
173 : PHP_FE(pg_last_notice, NULL)
174 : /* copy functions */
175 : PHP_FE(pg_put_line, NULL)
176 : PHP_FE(pg_end_copy, NULL)
177 : PHP_FE(pg_copy_to, NULL)
178 : PHP_FE(pg_copy_from, NULL)
179 : /* debug functions */
180 : PHP_FE(pg_trace, NULL)
181 : PHP_FE(pg_untrace, NULL)
182 : /* large object functions */
183 : PHP_FE(pg_lo_create, NULL)
184 : PHP_FE(pg_lo_unlink, NULL)
185 : PHP_FE(pg_lo_open, NULL)
186 : PHP_FE(pg_lo_close, NULL)
187 : PHP_FE(pg_lo_read, NULL)
188 : PHP_FE(pg_lo_write, NULL)
189 : PHP_FE(pg_lo_read_all, NULL)
190 : PHP_FE(pg_lo_import, NULL)
191 : PHP_FE(pg_lo_export, NULL)
192 : PHP_FE(pg_lo_seek, NULL)
193 : PHP_FE(pg_lo_tell, NULL)
194 : /* utility functions */
195 : #if HAVE_PQESCAPE
196 : PHP_FE(pg_escape_string,NULL)
197 : PHP_FE(pg_escape_bytea, NULL)
198 : PHP_FE(pg_unescape_bytea, NULL)
199 : #endif
200 : #if HAVE_PQSETERRORVERBOSITY
201 : PHP_FE(pg_set_error_verbosity, NULL)
202 : #endif
203 : #if HAVE_PQCLIENTENCODING
204 : PHP_FE(pg_client_encoding, NULL)
205 : PHP_FE(pg_set_client_encoding, NULL)
206 : #endif
207 : /* misc function */
208 : PHP_FE(pg_meta_data, NULL)
209 : PHP_FE(pg_convert, NULL)
210 : PHP_FE(pg_insert, NULL)
211 : PHP_FE(pg_update, NULL)
212 : PHP_FE(pg_delete, NULL)
213 : PHP_FE(pg_select, NULL)
214 : /* aliases for downwards compatibility */
215 : PHP_FALIAS(pg_exec, pg_query, NULL)
216 : PHP_FALIAS(pg_getlastoid, pg_last_oid, NULL)
217 : #if HAVE_PQCMDTUPLES
218 : PHP_FALIAS(pg_cmdtuples, pg_affected_rows, NULL)
219 : #endif
220 : PHP_FALIAS(pg_errormessage, pg_last_error, NULL)
221 : PHP_FALIAS(pg_numrows, pg_num_rows, NULL)
222 : PHP_FALIAS(pg_numfields, pg_num_fields, NULL)
223 : PHP_FALIAS(pg_fieldname, pg_field_name, NULL)
224 : PHP_FALIAS(pg_fieldsize, pg_field_size, NULL)
225 : PHP_FALIAS(pg_fieldtype, pg_field_type, NULL)
226 : PHP_FALIAS(pg_fieldnum, pg_field_num, NULL)
227 : PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, NULL)
228 : PHP_FALIAS(pg_fieldisnull, pg_field_is_null, NULL)
229 : PHP_FALIAS(pg_freeresult, pg_free_result, NULL)
230 : PHP_FALIAS(pg_result, pg_fetch_result, NULL)
231 : PHP_FALIAS(pg_loreadall, pg_lo_read_all, NULL)
232 : PHP_FALIAS(pg_locreate, pg_lo_create, NULL)
233 : PHP_FALIAS(pg_lounlink, pg_lo_unlink, NULL)
234 : PHP_FALIAS(pg_loopen, pg_lo_open, NULL)
235 : PHP_FALIAS(pg_loclose, pg_lo_close, NULL)
236 : PHP_FALIAS(pg_loread, pg_lo_read, NULL)
237 : PHP_FALIAS(pg_lowrite, pg_lo_write, NULL)
238 : PHP_FALIAS(pg_loimport, pg_lo_import, NULL)
239 : PHP_FALIAS(pg_loexport, pg_lo_export, NULL)
240 : #if HAVE_PQCLIENTENCODING
241 : PHP_FALIAS(pg_clientencoding, pg_client_encoding, NULL)
242 : PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, NULL)
243 : #endif
244 : {NULL, NULL, NULL}
245 : };
246 : /* }}} */
247 :
248 : /* {{{ pgsql_module_entry
249 : */
250 : zend_module_entry pgsql_module_entry = {
251 : STANDARD_MODULE_HEADER,
252 : "pgsql",
253 : pgsql_functions,
254 : PHP_MINIT(pgsql),
255 : PHP_MSHUTDOWN(pgsql),
256 : PHP_RINIT(pgsql),
257 : PHP_RSHUTDOWN(pgsql),
258 : PHP_MINFO(pgsql),
259 : NO_VERSION_YET,
260 : PHP_MODULE_GLOBALS(pgsql),
261 : PHP_GINIT(pgsql),
262 : NULL,
263 : NULL,
264 : STANDARD_MODULE_PROPERTIES_EX
265 : };
266 : /* }}} */
267 :
268 : #ifdef COMPILE_DL_PGSQL
269 : ZEND_GET_MODULE(pgsql)
270 : #endif
271 :
272 : static int le_link, le_plink, le_result, le_lofp, le_string;
273 :
274 : /* {{{ _php_pgsql_trim_message */
275 : static char * _php_pgsql_trim_message(const char *message, int *len)
276 14 : {
277 14 : register int i = strlen(message)-1;
278 :
279 14 : if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') {
280 0 : --i;
281 : }
282 40 : while (i>0 && (message[i] == '\r' || message[i] == '\n')) {
283 12 : --i;
284 : }
285 14 : ++i;
286 14 : if (len) {
287 7 : *len = i;
288 : }
289 14 : return estrndup(message, i);
290 : }
291 : /* }}} */
292 :
293 : /* {{{ _php_pgsql_trim_result */
294 : static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
295 2 : {
296 2 : return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
297 : }
298 : /* }}} */
299 :
300 : #define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
301 :
302 : #define PHP_PQ_ERROR(text, pgsql) { \
303 : char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \
304 : php_error_docref(NULL TSRMLS_CC, E_WARNING, text, msgbuf); \
305 : efree(msgbuf); \
306 : } \
307 :
308 : /* {{{ php_pgsql_set_default_link
309 : */
310 : static void php_pgsql_set_default_link(int id TSRMLS_DC)
311 85 : {
312 85 : zend_list_addref(id);
313 :
314 85 : if (PGG(default_link) != -1) {
315 0 : zend_list_delete(PGG(default_link));
316 : }
317 :
318 85 : PGG(default_link) = id;
319 85 : }
320 : /* }}} */
321 :
322 : /* {{{ _close_pgsql_link
323 : */
324 : static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
325 84 : {
326 84 : PGconn *link = (PGconn *)rsrc->ptr;
327 : PGresult *res;
328 :
329 170 : while ((res = PQgetResult(link))) {
330 2 : PQclear(res);
331 : }
332 84 : PQfinish(link);
333 84 : PGG(num_links)--;
334 84 : }
335 : /* }}} */
336 :
337 : /* {{{ _close_pgsql_plink
338 : */
339 : static void _close_pgsql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
340 1 : {
341 1 : PGconn *link = (PGconn *)rsrc->ptr;
342 : PGresult *res;
343 :
344 2 : while ((res = PQgetResult(link))) {
345 0 : PQclear(res);
346 : }
347 1 : PQfinish(link);
348 1 : PGG(num_persistent)--;
349 1 : PGG(num_links)--;
350 1 : }
351 : /* }}} */
352 :
353 : /* {{{ _php_pgsql_notice_handler
354 : */
355 : static void _php_pgsql_notice_handler(void *resource_id, const char *message)
356 7 : {
357 : php_pgsql_notice *notice;
358 :
359 : TSRMLS_FETCH();
360 7 : if (! PGG(ignore_notices)) {
361 7 : notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice));
362 7 : notice->message = _php_pgsql_trim_message(message, ¬ice->len);
363 7 : if (PGG(log_notices)) {
364 1 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", notice->message);
365 : }
366 7 : zend_hash_index_update(&PGG(notices), (ulong)resource_id, (void **)¬ice, sizeof(php_pgsql_notice *), NULL);
367 : }
368 7 : }
369 : /* }}} */
370 :
371 : #define PHP_PGSQL_NOTICE_PTR_DTOR (void (*)(void *))_php_pgsql_notice_ptr_dtor
372 :
373 : /* {{{ _php_pgsql_notice_dtor
374 : */
375 : static void _php_pgsql_notice_ptr_dtor(void **ptr)
376 7 : {
377 7 : php_pgsql_notice *notice = (php_pgsql_notice *)*ptr;
378 7 : if (notice) {
379 7 : efree(notice->message);
380 7 : efree(notice);
381 7 : notice = NULL;
382 : }
383 7 : }
384 : /* }}} */
385 :
386 : /* {{{ _rollback_transactions
387 : */
388 : static int _rollback_transactions(zend_rsrc_list_entry *rsrc TSRMLS_DC)
389 40 : {
390 : PGconn *link;
391 : PGresult *res;
392 : int orig;
393 :
394 40 : if (Z_TYPE_P(rsrc) != le_plink)
395 39 : return 0;
396 :
397 1 : link = (PGconn *) rsrc->ptr;
398 :
399 1 : if (PQ_SETNONBLOCKING(link, 0)) {
400 0 : php_error_docref("ref.pgsql" TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
401 0 : return -1;
402 : }
403 :
404 2 : while ((res = PQgetResult(link))) {
405 0 : PQclear(res);
406 : }
407 : #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
408 1 : if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
409 : #endif
410 : {
411 0 : orig = PGG(ignore_notices);
412 0 : PGG(ignore_notices) = 1;
413 : #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
414 0 : res = PQexec(link,"ROLLBACK;");
415 : #else
416 : res = PQexec(link,"BEGIN;");
417 : PQclear(res);
418 : res = PQexec(link,"ROLLBACK;");
419 : #endif
420 0 : PQclear(res);
421 0 : PGG(ignore_notices) = orig;
422 : }
423 :
424 1 : return 0;
425 : }
426 : /* }}} */
427 :
428 : /* {{{ _free_ptr
429 : */
430 : static void _free_ptr(zend_rsrc_list_entry *rsrc TSRMLS_DC)
431 1641 : {
432 1641 : pgLofp *lofp = (pgLofp *)rsrc->ptr;
433 1641 : efree(lofp);
434 1641 : }
435 : /* }}} */
436 :
437 : /* {{{ _free_result
438 : */
439 : static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
440 1129 : {
441 1129 : pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
442 :
443 1129 : PQclear(pg_result->result);
444 1129 : efree(pg_result);
445 1129 : }
446 : /* }}} */
447 :
448 : /* {{{ PHP_INI
449 : */
450 : PHP_INI_BEGIN()
451 : STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
452 : STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers)
453 : STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers)
454 : STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
455 : STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals)
456 : STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals)
457 : PHP_INI_END()
458 : /* }}} */
459 :
460 : /* {{{ PHP_GINIT_FUNCTION
461 : */
462 : static PHP_GINIT_FUNCTION(pgsql)
463 13565 : {
464 13565 : memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
465 : /* Initilize notice message hash at MINIT only */
466 13565 : zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0);
467 13565 : }
468 : /* }}} */
469 :
470 : /* {{{ PHP_MINIT_FUNCTION
471 : */
472 : PHP_MINIT_FUNCTION(pgsql)
473 13565 : {
474 13565 : REGISTER_INI_ENTRIES();
475 :
476 13565 : le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
477 13565 : le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
478 13565 : le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
479 13565 : le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
480 13565 : le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
481 : /* For connection option */
482 13565 : REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
483 : /* For pg_fetch_array() */
484 13565 : REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
485 13565 : REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
486 13565 : REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
487 : /* For pg_connection_status() */
488 13565 : REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
489 13565 : REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
490 : #if HAVE_PGTRANSACTIONSTATUS
491 : /* For pg_transaction_status() */
492 13565 : REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
493 13565 : REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
494 13565 : REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
495 13565 : REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
496 13565 : REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
497 : #endif
498 : #if HAVE_PQSETERRORVERBOSITY
499 : /* For pg_set_error_verbosity() */
500 13565 : REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
501 13565 : REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
502 13565 : REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
503 : #endif
504 : /* For lo_seek() */
505 13565 : REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
506 13565 : REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
507 13565 : REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
508 : /* For pg_result_status() return value type */
509 13565 : REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
510 13565 : REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
511 : /* For pg_result_status() return value */
512 13565 : REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
513 13565 : REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
514 13565 : REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
515 13565 : REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
516 13565 : REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
517 13565 : REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
518 13565 : REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
519 13565 : REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
520 : #if HAVE_PQRESULTERRORFIELD
521 : /* For pg_result_error_field() field codes */
522 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
523 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
524 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
525 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
526 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
527 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
528 : #ifdef PG_DIAG_INTERNAL_POSITION
529 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
530 : #endif
531 : #ifdef PG_DIAG_INTERNAL_QUERY
532 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
533 : #endif
534 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
535 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
536 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
537 13565 : REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
538 : #endif
539 : /* pg_convert options */
540 13565 : REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
541 13565 : REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
542 13565 : REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
543 : /* pg_insert/update/delete/select options */
544 13565 : REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
545 13565 : REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
546 13565 : REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
547 13565 : REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
548 13565 : return SUCCESS;
549 : }
550 : /* }}} */
551 :
552 : /* {{{ PHP_MSHUTDOWN_FUNCTION
553 : */
554 : PHP_MSHUTDOWN_FUNCTION(pgsql)
555 13598 : {
556 13598 : UNREGISTER_INI_ENTRIES();
557 13598 : zend_hash_destroy(&PGG(notices));
558 :
559 13598 : return SUCCESS;
560 : }
561 : /* }}} */
562 :
563 : /* {{{ PHP_RINIT_FUNCTION
564 : */
565 : PHP_RINIT_FUNCTION(pgsql)
566 13551 : {
567 13551 : PGG(default_link)=-1;
568 13551 : PGG(num_links) = PGG(num_persistent);
569 13551 : return SUCCESS;
570 : }
571 : /* }}} */
572 :
573 : /* {{{ PHP_RSHUTDOWN_FUNCTION
574 : */
575 : PHP_RSHUTDOWN_FUNCTION(pgsql)
576 13584 : {
577 : /* clean up notice messages */
578 13584 : zend_hash_clean(&PGG(notices));
579 : /* clean up persistent connection */
580 13584 : zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions TSRMLS_CC);
581 13584 : return SUCCESS;
582 : }
583 : /* }}} */
584 :
585 : /* {{{ PHP_MINFO_FUNCTION
586 : */
587 : PHP_MINFO_FUNCTION(pgsql)
588 6 : {
589 : char buf[256];
590 :
591 6 : php_info_print_table_start();
592 6 : php_info_print_table_header(2, "PostgreSQL Support", "enabled");
593 : #if HAVE_PG_CONFIG_H
594 6 : php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
595 : #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
596 6 : php_info_print_table_row(2, "Multibyte character support", "enabled");
597 : #else
598 : php_info_print_table_row(2, "Multibyte character support", "disabled");
599 : #endif
600 : #ifdef USE_SSL
601 6 : php_info_print_table_row(2, "SSL support", "enabled");
602 : #else
603 : php_info_print_table_row(2, "SSL support", "disabled");
604 : #endif
605 : #endif /* HAVE_PG_CONFIG_H */
606 6 : snprintf(buf, sizeof(buf), "%ld", PGG(num_persistent));
607 6 : php_info_print_table_row(2, "Active Persistent Links", buf);
608 6 : snprintf(buf, sizeof(buf), "%ld", PGG(num_links));
609 6 : php_info_print_table_row(2, "Active Links", buf);
610 6 : php_info_print_table_end();
611 :
612 6 : DISPLAY_INI_ENTRIES();
613 6 : }
614 : /* }}} */
615 :
616 :
617 : /* {{{ php_pgsql_do_connect
618 : */
619 : static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
620 85 : {
621 85 : char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
622 : PGconn *pgsql;
623 85 : smart_str str = {0};
624 : zval **args[5];
625 85 : int i, connect_type = 0;
626 : PGresult *pg_result;
627 :
628 85 : if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
629 : || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
630 0 : WRONG_PARAM_COUNT;
631 : }
632 :
633 85 : smart_str_appends(&str, "pgsql");
634 :
635 170 : for (i = 0; i < ZEND_NUM_ARGS(); i++) {
636 : /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
637 : * can re-use this connection. Bug #39979
638 : */
639 85 : if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE_PP(args[i]) == IS_LONG) {
640 0 : if (Z_LVAL_PP(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
641 0 : continue;
642 0 : } else if (Z_LVAL_PP(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
643 0 : smart_str_append_long(&str, Z_LVAL_PP(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
644 : }
645 : }
646 85 : convert_to_string_ex(args[i]);
647 85 : smart_str_appendc(&str, '_');
648 85 : smart_str_appendl(&str, Z_STRVAL_PP(args[i]), Z_STRLEN_PP(args[i]));
649 : }
650 :
651 85 : smart_str_0(&str);
652 :
653 85 : if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
654 85 : connstring = Z_STRVAL_PP(args[0]);
655 0 : } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
656 0 : connstring = Z_STRVAL_PP(args[0]);
657 0 : convert_to_long_ex(args[1]);
658 0 : connect_type = Z_LVAL_PP(args[1]);
659 : } else {
660 0 : host = Z_STRVAL_PP(args[0]);
661 0 : port = Z_STRVAL_PP(args[1]);
662 0 : dbname = Z_STRVAL_PP(args[ZEND_NUM_ARGS()-1]);
663 :
664 0 : switch (ZEND_NUM_ARGS()) {
665 : case 5:
666 0 : tty = Z_STRVAL_PP(args[3]);
667 : /* fall through */
668 : case 4:
669 0 : options = Z_STRVAL_PP(args[2]);
670 : break;
671 : }
672 : }
673 :
674 86 : if (persistent && PGG(allow_persistent)) {
675 : zend_rsrc_list_entry *le;
676 :
677 : /* try to find if we already have this link in our persistent list */
678 1 : if (zend_hash_find(&EG(persistent_list), str.c, str.len+1, (void **) &le)==FAILURE) { /* we don't */
679 : zend_rsrc_list_entry new_le;
680 :
681 1 : if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
682 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,
683 : "Cannot create new link. Too many open links (%ld)", PGG(num_links));
684 0 : goto err;
685 : }
686 1 : if (PGG(max_persistent)!=-1 && PGG(num_persistent)>=PGG(max_persistent)) {
687 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,
688 : "Cannot create new link. Too many open persistent links (%ld)", PGG(num_persistent));
689 0 : goto err;
690 : }
691 :
692 : /* create the link */
693 1 : if (connstring) {
694 1 : pgsql=PQconnectdb(connstring);
695 : } else {
696 0 : pgsql=PQsetdb(host,port,options,tty,dbname);
697 : }
698 1 : if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
699 0 : PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
700 0 : if (pgsql) {
701 0 : PQfinish(pgsql);
702 : }
703 0 : goto err;
704 : }
705 :
706 : /* hash it up */
707 1 : Z_TYPE(new_le) = le_plink;
708 1 : new_le.ptr = pgsql;
709 1 : if (zend_hash_update(&EG(persistent_list), str.c, str.len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
710 0 : goto err;
711 : }
712 1 : PGG(num_links)++;
713 1 : PGG(num_persistent)++;
714 : } else { /* we do */
715 0 : if (Z_TYPE_P(le) != le_plink) {
716 0 : RETURN_FALSE;
717 : }
718 : /* ensure that the link did not die */
719 0 : if (PGG(auto_reset_persistent) & 1) {
720 : /* need to send & get something from backend to
721 : make sure we catch CONNECTION_BAD everytime */
722 : PGresult *pg_result;
723 0 : pg_result = PQexec(le->ptr, "select 1");
724 0 : PQclear(pg_result);
725 : }
726 0 : if (PQstatus(le->ptr)==CONNECTION_BAD) { /* the link died */
727 0 : if (le->ptr == NULL) {
728 0 : if (connstring) {
729 0 : le->ptr=PQconnectdb(connstring);
730 : } else {
731 0 : le->ptr=PQsetdb(host,port,options,tty,dbname);
732 : }
733 : }
734 : else {
735 0 : PQreset(le->ptr);
736 : }
737 0 : if (le->ptr==NULL || PQstatus(le->ptr)==CONNECTION_BAD) {
738 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"PostgreSQL link lost, unable to reconnect");
739 0 : zend_hash_del(&EG(persistent_list),str.c,str.len+1);
740 0 : goto err;
741 : }
742 : }
743 0 : pgsql = (PGconn *) le->ptr;
744 : #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
745 0 : if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
746 : #else
747 : if (atof(PG_VERSION) >= 7.2) {
748 : #endif
749 0 : pg_result = PQexec(pgsql, "RESET ALL;");
750 0 : PQclear(pg_result);
751 : }
752 : }
753 1 : ZEND_REGISTER_RESOURCE(return_value, pgsql, le_plink);
754 : } else { /* Non persistent connection */
755 : zend_rsrc_list_entry *index_ptr,new_index_ptr;
756 :
757 : /* first we check the hash for the hashed_details key. if it exists,
758 : * it should point us to the right offset where the actual pgsql link sits.
759 : * if it doesn't, open a new pgsql link, add it to the resource list,
760 : * and add a pointer to it with hashed_details as the key.
761 : */
762 84 : if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
763 : && zend_hash_find(&EG(regular_list),str.c,str.len+1,(void **) &index_ptr)==SUCCESS) {
764 : int type;
765 : ulong link;
766 : void *ptr;
767 :
768 1 : if (Z_TYPE_P(index_ptr) != le_index_ptr) {
769 0 : RETURN_FALSE;
770 : }
771 1 : link = (uintptr_t) index_ptr->ptr;
772 1 : ptr = zend_list_find(link,&type); /* check if the link is still there */
773 1 : if (ptr && (type==le_link || type==le_plink)) {
774 0 : Z_LVAL_P(return_value) = link;
775 0 : zend_list_addref(link);
776 0 : php_pgsql_set_default_link(link TSRMLS_CC);
777 0 : Z_TYPE_P(return_value) = IS_RESOURCE;
778 0 : goto cleanup;
779 : } else {
780 1 : zend_hash_del(&EG(regular_list),str.c,str.len+1);
781 : }
782 : }
783 84 : if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
784 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create new link. Too many open links (%ld)", PGG(num_links));
785 0 : goto err;
786 : }
787 84 : if (connstring) {
788 84 : pgsql = PQconnectdb(connstring);
789 : } else {
790 0 : pgsql = PQsetdb(host,port,options,tty,dbname);
791 : }
792 84 : if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
793 0 : PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
794 0 : if (pgsql) {
795 0 : PQfinish(pgsql);
796 : }
797 0 : goto err;
798 : }
799 :
800 : /* add it to the list */
801 84 : ZEND_REGISTER_RESOURCE(return_value, pgsql, le_link);
802 :
803 : /* add it to the hash */
804 84 : new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
805 84 : Z_TYPE(new_index_ptr) = le_index_ptr;
806 84 : if (zend_hash_update(&EG(regular_list),str.c,str.len+1,(void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
807 0 : goto err;
808 : }
809 84 : PGG(num_links)++;
810 : }
811 : /* set notice processer */
812 85 : if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
813 85 : PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)Z_RESVAL_P(return_value));
814 : }
815 85 : php_pgsql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
816 :
817 85 : cleanup:
818 85 : smart_str_free(&str);
819 85 : return;
820 :
821 0 : err:
822 0 : smart_str_free(&str);
823 0 : RETURN_FALSE;
824 : }
825 : /* }}} */
826 :
827 : #if 0
828 : /* {{{ php_pgsql_get_default_link
829 : */
830 : static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
831 : {
832 : if (PGG(default_link)==-1) { /* no link opened yet, implicitly open one */
833 : ht = 0;
834 : php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
835 : }
836 : return PGG(default_link);
837 : }
838 : /* }}} */
839 : #endif
840 :
841 : /* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database)
842 : Open a PostgreSQL connection */
843 : PHP_FUNCTION(pg_connect)
844 84 : {
845 84 : php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
846 84 : }
847 : /* }}} */
848 :
849 : /* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database)
850 : Open a persistent PostgreSQL connection */
851 : PHP_FUNCTION(pg_pconnect)
852 1 : {
853 1 : php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
854 1 : }
855 : /* }}} */
856 :
857 : /* {{{ proto bool pg_close([resource connection])
858 : Close a PostgreSQL connection */
859 : PHP_FUNCTION(pg_close)
860 17 : {
861 17 : zval **pgsql_link = NULL;
862 : int id;
863 : PGconn *pgsql;
864 :
865 17 : switch (ZEND_NUM_ARGS()) {
866 : case 0:
867 0 : id = PGG(default_link);
868 0 : CHECK_DEFAULT_LINK(id);
869 0 : break;
870 : case 1:
871 17 : if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
872 0 : RETURN_FALSE;
873 : }
874 17 : id = -1;
875 17 : break;
876 : default:
877 0 : WRONG_PARAM_COUNT;
878 : break;
879 : }
880 17 : if (pgsql_link == NULL && id == -1) {
881 0 : RETURN_FALSE;
882 : }
883 :
884 17 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
885 :
886 17 : if (id==-1) { /* explicit resource number */
887 17 : zend_list_delete(Z_RESVAL_PP(pgsql_link));
888 : }
889 :
890 17 : if (id!=-1
891 : || (pgsql_link && Z_RESVAL_PP(pgsql_link)==PGG(default_link))) {
892 17 : zend_list_delete(PGG(default_link));
893 17 : PGG(default_link) = -1;
894 : }
895 :
896 17 : RETURN_TRUE;
897 : }
898 : /* }}} */
899 :
900 :
901 : #define PHP_PG_DBNAME 1
902 : #define PHP_PG_ERROR_MESSAGE 2
903 : #define PHP_PG_OPTIONS 3
904 : #define PHP_PG_PORT 4
905 : #define PHP_PG_TTY 5
906 : #define PHP_PG_HOST 6
907 : #define PHP_PG_VERSION 7
908 :
909 : /* {{{ php_pgsql_get_link_info
910 : */
911 : static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
912 11 : {
913 11 : zval **pgsql_link = NULL;
914 11 : int id = -1;
915 : PGconn *pgsql;
916 : char *msgbuf;
917 :
918 11 : switch(ZEND_NUM_ARGS()) {
919 : case 0:
920 2 : id = PGG(default_link);
921 2 : CHECK_DEFAULT_LINK(id);
922 2 : break;
923 : case 1:
924 9 : if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
925 0 : RETURN_FALSE;
926 : }
927 9 : break;
928 : default:
929 0 : WRONG_PARAM_COUNT;
930 : break;
931 : }
932 11 : if (pgsql_link == NULL && id == -1) {
933 0 : RETURN_FALSE;
934 : }
935 :
936 11 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
937 :
938 11 : switch(entry_type) {
939 : case PHP_PG_DBNAME:
940 1 : Z_STRVAL_P(return_value) = PQdb(pgsql);
941 1 : break;
942 : case PHP_PG_ERROR_MESSAGE:
943 2 : RETURN_STRING(PQErrorMessageTrim(pgsql, &msgbuf), 0);
944 : return;
945 : case PHP_PG_OPTIONS:
946 1 : Z_STRVAL_P(return_value) = PQoptions(pgsql);
947 1 : break;
948 : case PHP_PG_PORT:
949 1 : Z_STRVAL_P(return_value) = PQport(pgsql);
950 1 : break;
951 : case PHP_PG_TTY:
952 1 : Z_STRVAL_P(return_value) = PQtty(pgsql);
953 1 : break;
954 : case PHP_PG_HOST:
955 1 : Z_STRVAL_P(return_value) = PQhost(pgsql);
956 1 : break;
957 : case PHP_PG_VERSION:
958 4 : array_init(return_value);
959 4 : add_assoc_string(return_value, "client", PG_VERSION, 1);
960 : #if HAVE_PQPROTOCOLVERSION
961 4 : add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
962 : #if HAVE_PQPARAMETERSTATUS
963 4 : if (PQprotocolVersion(pgsql) >= 3) {
964 4 : add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"), 1);
965 : }
966 : #endif
967 : #endif
968 4 : return;
969 : default:
970 0 : RETURN_FALSE;
971 : }
972 5 : if (Z_STRVAL_P(return_value)) {
973 5 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
974 5 : Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
975 : } else {
976 0 : Z_STRLEN_P(return_value) = 0;
977 0 : Z_STRVAL_P(return_value) = (char *) estrdup("");
978 : }
979 5 : Z_TYPE_P(return_value) = IS_STRING;
980 : }
981 : /* }}} */
982 :
983 : /* {{{ proto string pg_dbname([resource connection])
984 : Get the database name */
985 : PHP_FUNCTION(pg_dbname)
986 1 : {
987 1 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
988 1 : }
989 : /* }}} */
990 :
991 : /* {{{ proto string pg_last_error([resource connection])
992 : Get the error message string */
993 : PHP_FUNCTION(pg_last_error)
994 2 : {
995 2 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
996 2 : }
997 : /* }}} */
998 :
999 : /* {{{ proto string pg_options([resource connection])
1000 : Get the options associated with the connection */
1001 : PHP_FUNCTION(pg_options)
1002 1 : {
1003 1 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
1004 1 : }
1005 : /* }}} */
1006 :
1007 : /* {{{ proto int pg_port([resource connection])
1008 : Return the port number associated with the connection */
1009 : PHP_FUNCTION(pg_port)
1010 1 : {
1011 1 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
1012 1 : }
1013 : /* }}} */
1014 :
1015 : /* {{{ proto string pg_tty([resource connection])
1016 : Return the tty name associated with the connection */
1017 : PHP_FUNCTION(pg_tty)
1018 1 : {
1019 1 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
1020 1 : }
1021 : /* }}} */
1022 :
1023 : /* {{{ proto string pg_host([resource connection])
1024 : Returns the host name associated with the connection */
1025 : PHP_FUNCTION(pg_host)
1026 1 : {
1027 1 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
1028 1 : }
1029 : /* }}} */
1030 :
1031 : /* {{{ proto array pg_version([resource connection])
1032 : Returns an array with client, protocol and server version (when available) */
1033 : PHP_FUNCTION(pg_version)
1034 4 : {
1035 4 : php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
1036 4 : }
1037 : /* }}} */
1038 :
1039 : #if HAVE_PQPARAMETERSTATUS
1040 : /* {{{ proto string|false pg_parameter_status([resource connection,] string param_name)
1041 : Returns the value of a server parameter */
1042 : PHP_FUNCTION(pg_parameter_status)
1043 0 : {
1044 : zval *pgsql_link;
1045 : int id;
1046 : PGconn *pgsql;
1047 : char *param;
1048 : int len;
1049 :
1050 0 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, ¶m, &len) == SUCCESS) {
1051 0 : id = -1;
1052 0 : } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", ¶m, &len) == SUCCESS) {
1053 0 : pgsql_link = NULL;
1054 0 : id = PGG(default_link);
1055 : } else {
1056 0 : RETURN_FALSE;
1057 : }
1058 0 : if (pgsql_link == NULL && id == -1) {
1059 0 : RETURN_FALSE;
1060 : }
1061 :
1062 0 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1063 :
1064 0 : param = (char*)PQparameterStatus(pgsql, param);
1065 0 : if (param) {
1066 0 : RETURN_STRING(param, 1);
1067 : } else {
1068 0 : RETURN_FALSE;
1069 : }
1070 : }
1071 : /* }}} */
1072 : #endif
1073 :
1074 : /* {{{ proto bool pg_ping([resource connection])
1075 : Ping database. If connection is bad, try to reconnect. */
1076 : PHP_FUNCTION(pg_ping)
1077 1 : {
1078 : zval *pgsql_link;
1079 : int id;
1080 : PGconn *pgsql;
1081 : PGresult *res;
1082 :
1083 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == SUCCESS) {
1084 1 : id = -1;
1085 : } else {
1086 0 : pgsql_link = NULL;
1087 0 : id = PGG(default_link);
1088 : }
1089 1 : if (pgsql_link == NULL && id == -1) {
1090 0 : RETURN_FALSE;
1091 : }
1092 :
1093 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1094 :
1095 : /* ping connection */
1096 1 : res = PQexec(pgsql, "SELECT 1;");
1097 1 : PQclear(res);
1098 :
1099 : /* check status. */
1100 1 : if (PQstatus(pgsql) == CONNECTION_OK)
1101 1 : RETURN_TRUE;
1102 :
1103 : /* reset connection if it's broken */
1104 0 : PQreset(pgsql);
1105 0 : if (PQstatus(pgsql) == CONNECTION_OK) {
1106 0 : RETURN_TRUE;
1107 : }
1108 0 : RETURN_FALSE;
1109 : }
1110 : /* }}} */
1111 :
1112 : /* {{{ proto resource pg_query([resource connection,] string query)
1113 : Execute a query */
1114 : PHP_FUNCTION(pg_query)
1115 1114 : {
1116 1114 : zval **query, **pgsql_link = NULL;
1117 1114 : int id = -1;
1118 1114 : int leftover = 0;
1119 : PGconn *pgsql;
1120 : PGresult *pgsql_result;
1121 : ExecStatusType status;
1122 : pgsql_result_handle *pg_result;
1123 :
1124 1114 : switch(ZEND_NUM_ARGS()) {
1125 : case 1:
1126 62 : if (zend_get_parameters_ex(1, &query)==FAILURE) {
1127 0 : RETURN_FALSE;
1128 : }
1129 62 : id = PGG(default_link);
1130 62 : CHECK_DEFAULT_LINK(id);
1131 62 : break;
1132 : case 2:
1133 1052 : if (zend_get_parameters_ex(2, &pgsql_link, &query)==FAILURE) {
1134 0 : RETURN_FALSE;
1135 : }
1136 1052 : break;
1137 : default:
1138 0 : WRONG_PARAM_COUNT;
1139 : break;
1140 : }
1141 1114 : if (pgsql_link == NULL && id == -1) {
1142 0 : RETURN_FALSE;
1143 : }
1144 :
1145 1114 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1146 :
1147 1114 : convert_to_string_ex(query);
1148 1114 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
1149 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
1150 0 : RETURN_FALSE;
1151 : }
1152 2228 : while ((pgsql_result = PQgetResult(pgsql))) {
1153 0 : PQclear(pgsql_result);
1154 0 : leftover = 1;
1155 : }
1156 1114 : if (leftover) {
1157 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
1158 : }
1159 1114 : pgsql_result = PQexec(pgsql, Z_STRVAL_PP(query));
1160 1114 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
1161 0 : PQclear(pgsql_result);
1162 0 : PQreset(pgsql);
1163 0 : pgsql_result = PQexec(pgsql, Z_STRVAL_PP(query));
1164 : }
1165 :
1166 1114 : if (pgsql_result) {
1167 1114 : status = PQresultStatus(pgsql_result);
1168 : } else {
1169 0 : status = (ExecStatusType) PQstatus(pgsql);
1170 : }
1171 :
1172 1114 : switch (status) {
1173 : case PGRES_EMPTY_QUERY:
1174 : case PGRES_BAD_RESPONSE:
1175 : case PGRES_NONFATAL_ERROR:
1176 : case PGRES_FATAL_ERROR:
1177 5 : PHP_PQ_ERROR("Query failed: %s", pgsql);
1178 5 : PQclear(pgsql_result);
1179 5 : RETURN_FALSE;
1180 : break;
1181 : case PGRES_COMMAND_OK: /* successful command that did not return rows */
1182 : default:
1183 1109 : if (pgsql_result) {
1184 1109 : pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
1185 1109 : pg_result->conn = pgsql;
1186 1109 : pg_result->result = pgsql_result;
1187 1109 : pg_result->row = 0;
1188 1109 : ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
1189 : } else {
1190 0 : PQclear(pgsql_result);
1191 0 : RETURN_FALSE;
1192 : }
1193 : break;
1194 : }
1195 : }
1196 : /* }}} */
1197 :
1198 : #if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED
1199 : /* {{{ _php_pgsql_free_params */
1200 : static void _php_pgsql_free_params(char **params, int num_params)
1201 16 : {
1202 16 : if (num_params > 0) {
1203 : int i;
1204 36 : for (i = 0; i < num_params; i++) {
1205 20 : if (params[i]) {
1206 20 : efree(params[i]);
1207 : }
1208 : }
1209 16 : efree(params);
1210 : }
1211 16 : }
1212 : /* }}} */
1213 : #endif
1214 :
1215 : #if HAVE_PQEXECPARAMS
1216 : /* {{{ proto resource pg_query_params([resource connection,] string query, array params)
1217 : Execute a query */
1218 : PHP_FUNCTION(pg_query_params)
1219 8 : {
1220 8 : zval **query, **pgsql_link = NULL;
1221 : zval **pv_param_arr, **tmp;
1222 8 : int id = -1;
1223 8 : int leftover = 0;
1224 8 : int num_params = 0;
1225 8 : char **params = NULL;
1226 : PGconn *pgsql;
1227 : PGresult *pgsql_result;
1228 : ExecStatusType status;
1229 : pgsql_result_handle *pg_result;
1230 :
1231 8 : switch(ZEND_NUM_ARGS()) {
1232 : case 2:
1233 0 : if (zend_get_parameters_ex(2, &query, &pv_param_arr)==FAILURE) {
1234 0 : RETURN_FALSE;
1235 : }
1236 0 : id = PGG(default_link);
1237 0 : CHECK_DEFAULT_LINK(id);
1238 0 : break;
1239 : case 3:
1240 8 : if (zend_get_parameters_ex(3, &pgsql_link, &query, &pv_param_arr)==FAILURE) {
1241 0 : RETURN_FALSE;
1242 : }
1243 8 : break;
1244 : default:
1245 0 : WRONG_PARAM_COUNT;
1246 : break;
1247 : }
1248 8 : if (pgsql_link == NULL && id == -1) {
1249 0 : RETURN_FALSE;
1250 : }
1251 :
1252 8 : if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) {
1253 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed");
1254 0 : RETURN_FALSE;
1255 : }
1256 :
1257 8 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1258 :
1259 8 : convert_to_string_ex(query);
1260 8 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
1261 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
1262 0 : RETURN_FALSE;
1263 : }
1264 16 : while ((pgsql_result = PQgetResult(pgsql))) {
1265 0 : PQclear(pgsql_result);
1266 0 : leftover = 1;
1267 : }
1268 8 : if (leftover) {
1269 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
1270 : }
1271 :
1272 8 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr));
1273 8 : num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr));
1274 8 : if (num_params > 0) {
1275 8 : int i = 0;
1276 8 : params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
1277 :
1278 17 : for(i = 0; i < num_params; i++) {
1279 9 : if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) {
1280 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
1281 0 : _php_pgsql_free_params(params, num_params);
1282 0 : RETURN_FALSE;
1283 : }
1284 :
1285 9 : if (Z_TYPE_PP(tmp) == IS_NULL) {
1286 0 : params[i] = NULL;
1287 : } else {
1288 9 : zval tmp_val = **tmp;
1289 9 : zval_copy_ctor(&tmp_val);
1290 9 : convert_to_string(&tmp_val);
1291 9 : if (Z_TYPE(tmp_val) != IS_STRING) {
1292 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
1293 0 : zval_dtor(&tmp_val);
1294 0 : _php_pgsql_free_params(params, num_params);
1295 0 : RETURN_FALSE;
1296 : }
1297 9 : params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
1298 9 : zval_dtor(&tmp_val);
1299 : }
1300 :
1301 9 : zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr));
1302 : }
1303 : }
1304 :
1305 8 : pgsql_result = PQexecParams(pgsql, Z_STRVAL_PP(query), num_params,
1306 : NULL, (const char * const *)params, NULL, NULL, 0);
1307 8 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
1308 0 : PQclear(pgsql_result);
1309 0 : PQreset(pgsql);
1310 0 : pgsql_result = PQexecParams(pgsql, Z_STRVAL_PP(query), num_params,
1311 : NULL, (const char * const *)params, NULL, NULL, 0);
1312 : }
1313 :
1314 8 : if (pgsql_result) {
1315 8 : status = PQresultStatus(pgsql_result);
1316 : } else {
1317 0 : status = (ExecStatusType) PQstatus(pgsql);
1318 : }
1319 :
1320 8 : _php_pgsql_free_params(params, num_params);
1321 :
1322 8 : switch (status) {
1323 : case PGRES_EMPTY_QUERY:
1324 : case PGRES_BAD_RESPONSE:
1325 : case PGRES_NONFATAL_ERROR:
1326 : case PGRES_FATAL_ERROR:
1327 0 : PHP_PQ_ERROR("Query failed: %s", pgsql);
1328 0 : PQclear(pgsql_result);
1329 0 : RETURN_FALSE;
1330 : break;
1331 : case PGRES_COMMAND_OK: /* successful command that did not return rows */
1332 : default:
1333 8 : if (pgsql_result) {
1334 8 : pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
1335 8 : pg_result->conn = pgsql;
1336 8 : pg_result->result = pgsql_result;
1337 8 : pg_result->row = 0;
1338 8 : ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
1339 : } else {
1340 0 : PQclear(pgsql_result);
1341 0 : RETURN_FALSE;
1342 : }
1343 : break;
1344 : }
1345 : }
1346 : /* }}} */
1347 : #endif
1348 :
1349 : #if HAVE_PQPREPARE
1350 : /* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query)
1351 : Prepare a query for future execution */
1352 : PHP_FUNCTION(pg_prepare)
1353 2 : {
1354 2 : zval **query, **stmtname, **pgsql_link = NULL;
1355 2 : int id = -1;
1356 2 : int leftover = 0;
1357 : PGconn *pgsql;
1358 : PGresult *pgsql_result;
1359 : ExecStatusType status;
1360 : pgsql_result_handle *pg_result;
1361 :
1362 2 : switch(ZEND_NUM_ARGS()) {
1363 : case 2:
1364 0 : if (zend_get_parameters_ex(2, &stmtname, &query)==FAILURE) {
1365 0 : RETURN_FALSE;
1366 : }
1367 0 : id = PGG(default_link);
1368 0 : CHECK_DEFAULT_LINK(id);
1369 0 : break;
1370 : case 3:
1371 2 : if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &query)==FAILURE) {
1372 0 : RETURN_FALSE;
1373 : }
1374 2 : break;
1375 : default:
1376 0 : WRONG_PARAM_COUNT;
1377 : break;
1378 : }
1379 2 : if (pgsql_link == NULL && id == -1) {
1380 0 : RETURN_FALSE;
1381 : }
1382 :
1383 2 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1384 :
1385 2 : convert_to_string_ex(stmtname);
1386 2 : convert_to_string_ex(query);
1387 2 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
1388 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
1389 0 : RETURN_FALSE;
1390 : }
1391 4 : while ((pgsql_result = PQgetResult(pgsql))) {
1392 0 : PQclear(pgsql_result);
1393 0 : leftover = 1;
1394 : }
1395 2 : if (leftover) {
1396 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
1397 : }
1398 2 : pgsql_result = PQprepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL);
1399 2 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
1400 0 : PQclear(pgsql_result);
1401 0 : PQreset(pgsql);
1402 0 : pgsql_result = PQprepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL);
1403 : }
1404 :
1405 2 : if (pgsql_result) {
1406 2 : status = PQresultStatus(pgsql_result);
1407 : } else {
1408 0 : status = (ExecStatusType) PQstatus(pgsql);
1409 : }
1410 :
1411 2 : switch (status) {
1412 : case PGRES_EMPTY_QUERY:
1413 : case PGRES_BAD_RESPONSE:
1414 : case PGRES_NONFATAL_ERROR:
1415 : case PGRES_FATAL_ERROR:
1416 0 : PHP_PQ_ERROR("Query failed: %s", pgsql);
1417 0 : PQclear(pgsql_result);
1418 0 : RETURN_FALSE;
1419 : break;
1420 : case PGRES_COMMAND_OK: /* successful command that did not return rows */
1421 : default:
1422 2 : if (pgsql_result) {
1423 2 : pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
1424 2 : pg_result->conn = pgsql;
1425 2 : pg_result->result = pgsql_result;
1426 2 : pg_result->row = 0;
1427 2 : ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
1428 : } else {
1429 0 : PQclear(pgsql_result);
1430 0 : RETURN_FALSE;
1431 : }
1432 : break;
1433 : }
1434 : }
1435 : /* }}} */
1436 : #endif
1437 :
1438 : #if HAVE_PQEXECPREPARED
1439 : /* {{{ proto resource pg_execute([resource connection,] string stmtname, array params)
1440 : Execute a prepared query */
1441 : PHP_FUNCTION(pg_execute)
1442 4 : {
1443 4 : zval **stmtname, **pgsql_link = NULL;
1444 : zval **pv_param_arr, **tmp;
1445 4 : int id = -1;
1446 4 : int leftover = 0;
1447 4 : int num_params = 0;
1448 4 : char **params = NULL;
1449 : PGconn *pgsql;
1450 : PGresult *pgsql_result;
1451 : ExecStatusType status;
1452 : pgsql_result_handle *pg_result;
1453 :
1454 4 : switch(ZEND_NUM_ARGS()) {
1455 : case 2:
1456 0 : if (zend_get_parameters_ex(2, &stmtname, &pv_param_arr)==FAILURE) {
1457 0 : RETURN_FALSE;
1458 : }
1459 0 : id = PGG(default_link);
1460 0 : CHECK_DEFAULT_LINK(id);
1461 0 : break;
1462 : case 3:
1463 4 : if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &pv_param_arr)==FAILURE) {
1464 0 : RETURN_FALSE;
1465 : }
1466 4 : break;
1467 : default:
1468 0 : WRONG_PARAM_COUNT;
1469 : break;
1470 : }
1471 4 : if (pgsql_link == NULL && id == -1) {
1472 0 : RETURN_FALSE;
1473 : }
1474 :
1475 4 : if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) {
1476 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed");
1477 0 : RETURN_FALSE;
1478 : }
1479 :
1480 4 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1481 :
1482 4 : convert_to_string_ex(stmtname);
1483 4 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
1484 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
1485 0 : RETURN_FALSE;
1486 : }
1487 8 : while ((pgsql_result = PQgetResult(pgsql))) {
1488 0 : PQclear(pgsql_result);
1489 0 : leftover = 1;
1490 : }
1491 4 : if (leftover) {
1492 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
1493 : }
1494 :
1495 4 : SEPARATE_ZVAL(pv_param_arr);
1496 4 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr));
1497 4 : num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr));
1498 4 : if (num_params > 0) {
1499 4 : int i = 0;
1500 4 : params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
1501 :
1502 9 : for(i = 0; i < num_params; i++) {
1503 5 : if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) {
1504 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
1505 0 : _php_pgsql_free_params(params, num_params);
1506 0 : RETURN_FALSE;
1507 : }
1508 :
1509 5 : if (Z_TYPE_PP(tmp) == IS_NULL) {
1510 0 : params[i] = NULL;
1511 : } else {
1512 5 : zval tmp_val = **tmp;
1513 5 : zval_copy_ctor(&tmp_val);
1514 5 : convert_to_string(&tmp_val);
1515 5 : if (Z_TYPE(tmp_val) != IS_STRING) {
1516 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
1517 0 : zval_dtor(&tmp_val);
1518 0 : _php_pgsql_free_params(params, num_params);
1519 0 : RETURN_FALSE;
1520 : }
1521 5 : params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
1522 5 : zval_dtor(&tmp_val);
1523 : }
1524 :
1525 5 : zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr));
1526 : }
1527 : }
1528 :
1529 4 : pgsql_result = PQexecPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params,
1530 : (const char * const *)params, NULL, NULL, 0);
1531 4 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
1532 0 : PQclear(pgsql_result);
1533 0 : PQreset(pgsql);
1534 0 : pgsql_result = PQexecPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params,
1535 : (const char * const *)params, NULL, NULL, 0);
1536 : }
1537 :
1538 4 : if (pgsql_result) {
1539 4 : status = PQresultStatus(pgsql_result);
1540 : } else {
1541 0 : status = (ExecStatusType) PQstatus(pgsql);
1542 : }
1543 :
1544 4 : _php_pgsql_free_params(params, num_params);
1545 :
1546 4 : switch (status) {
1547 : case PGRES_EMPTY_QUERY:
1548 : case PGRES_BAD_RESPONSE:
1549 : case PGRES_NONFATAL_ERROR:
1550 : case PGRES_FATAL_ERROR:
1551 0 : PHP_PQ_ERROR("Query failed: %s", pgsql);
1552 0 : PQclear(pgsql_result);
1553 0 : RETURN_FALSE;
1554 : break;
1555 : case PGRES_COMMAND_OK: /* successful command that did not return rows */
1556 : default:
1557 4 : if (pgsql_result) {
1558 4 : pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
1559 4 : pg_result->conn = pgsql;
1560 4 : pg_result->result = pgsql_result;
1561 4 : pg_result->row = 0;
1562 4 : ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
1563 : } else {
1564 0 : PQclear(pgsql_result);
1565 0 : RETURN_FALSE;
1566 : }
1567 : break;
1568 : }
1569 : }
1570 : /* }}} */
1571 : #endif
1572 :
1573 : #define PHP_PG_NUM_ROWS 1
1574 : #define PHP_PG_NUM_FIELDS 2
1575 : #define PHP_PG_CMD_TUPLES 3
1576 :
1577 : /* {{{ php_pgsql_get_result_info
1578 : */
1579 : static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
1580 24 : {
1581 : zval **result;
1582 : PGresult *pgsql_result;
1583 : pgsql_result_handle *pg_result;
1584 :
1585 24 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result)==FAILURE) {
1586 0 : WRONG_PARAM_COUNT;
1587 : }
1588 :
1589 24 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
1590 :
1591 23 : pgsql_result = pg_result->result;
1592 :
1593 23 : switch (entry_type) {
1594 : case PHP_PG_NUM_ROWS:
1595 15 : Z_LVAL_P(return_value) = PQntuples(pgsql_result);
1596 15 : break;
1597 : case PHP_PG_NUM_FIELDS:
1598 7 : Z_LVAL_P(return_value) = PQnfields(pgsql_result);
1599 7 : break;
1600 : case PHP_PG_CMD_TUPLES:
1601 : #if HAVE_PQCMDTUPLES
1602 1 : Z_LVAL_P(return_value) = atoi(PQcmdTuples(pgsql_result));
1603 : #else
1604 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported under this build");
1605 : Z_LVAL_P(return_value) = 0;
1606 : #endif
1607 1 : break;
1608 : default:
1609 0 : RETURN_FALSE;
1610 : }
1611 23 : Z_TYPE_P(return_value) = IS_LONG;
1612 : }
1613 : /* }}} */
1614 :
1615 : /* {{{ proto int pg_num_rows(resource result)
1616 : Return the number of rows in the result */
1617 : PHP_FUNCTION(pg_num_rows)
1618 16 : {
1619 16 : php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
1620 16 : }
1621 : /* }}} */
1622 :
1623 : /* {{{ proto int pg_num_fields(resource result)
1624 : Return the number of fields in the result */
1625 : PHP_FUNCTION(pg_num_fields)
1626 7 : {
1627 7 : php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
1628 7 : }
1629 : /* }}} */
1630 :
1631 : #if HAVE_PQCMDTUPLES
1632 : /* {{{ proto int pg_affected_rows(resource result)
1633 : Returns the number of affected tuples */
1634 : PHP_FUNCTION(pg_affected_rows)
1635 1 : {
1636 1 : php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
1637 1 : }
1638 : /* }}} */
1639 : #endif
1640 :
1641 : /* {{{ proto string pg_last_notice(resource connection)
1642 : Returns the last notice set by the backend */
1643 : PHP_FUNCTION(pg_last_notice)
1644 3 : {
1645 : zval *pgsql_link;
1646 : PGconn *pg_link;
1647 3 : int id = -1;
1648 : php_pgsql_notice **notice;
1649 :
1650 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
1651 : &pgsql_link) == FAILURE) {
1652 0 : return;
1653 : }
1654 : /* Just to check if user passed valid resoruce */
1655 3 : ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
1656 :
1657 3 : if (zend_hash_index_find(&PGG(notices), Z_RESVAL_P(pgsql_link), (void **)¬ice) == FAILURE) {
1658 0 : RETURN_FALSE;
1659 : }
1660 3 : RETURN_STRINGL((*notice)->message, (*notice)->len, 1);
1661 : }
1662 : /* }}} */
1663 :
1664 : /* {{{ get_field_name
1665 : */
1666 : static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list TSRMLS_DC)
1667 7 : {
1668 : PGresult *result;
1669 7 : smart_str str = {0};
1670 : zend_rsrc_list_entry *field_type;
1671 7 : char *ret=NULL;
1672 :
1673 : /* try to lookup the type in the resource list */
1674 7 : smart_str_appends(&str, "pgsql_oid_");
1675 7 : smart_str_append_unsigned(&str, oid);
1676 7 : smart_str_0(&str);
1677 :
1678 7 : if (zend_hash_find(list,str.c,str.len+1,(void **) &field_type)==SUCCESS) {
1679 0 : ret = estrdup((char *)field_type->ptr);
1680 : } else { /* hash all oid's */
1681 : int i,num_rows;
1682 : int oid_offset,name_offset;
1683 : char *tmp_oid, *end_ptr, *tmp_name;
1684 : zend_rsrc_list_entry new_oid_entry;
1685 :
1686 7 : if ((result = PQexec(pgsql,"select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) {
1687 0 : if (result) {
1688 0 : PQclear(result);
1689 : }
1690 0 : smart_str_free(&str);
1691 0 : return STR_EMPTY_ALLOC();
1692 : }
1693 7 : num_rows = PQntuples(result);
1694 7 : oid_offset = PQfnumber(result,"oid");
1695 7 : name_offset = PQfnumber(result,"typname");
1696 :
1697 1645 : for (i=0; i<num_rows; i++) {
1698 1638 : if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
1699 0 : continue;
1700 : }
1701 :
1702 1638 : str.len = 0;
1703 1638 : smart_str_appends(&str, "pgsql_oid_");
1704 1638 : smart_str_appends(&str, tmp_oid);
1705 1638 : smart_str_0(&str);
1706 :
1707 1638 : if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
1708 0 : continue;
1709 : }
1710 1638 : Z_TYPE(new_oid_entry) = le_string;
1711 1638 : new_oid_entry.ptr = estrdup(tmp_name);
1712 1638 : zend_hash_update(list,str.c,str.len+1,(void *) &new_oid_entry, sizeof(zend_rsrc_list_entry), NULL);
1713 1638 : if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) {
1714 7 : ret = estrdup(tmp_name);
1715 : }
1716 : }
1717 7 : PQclear(result);
1718 : }
1719 :
1720 7 : smart_str_free(&str);
1721 7 : return ret;
1722 : }
1723 : /* }}} */
1724 :
1725 : #ifdef HAVE_PQFTABLE
1726 : /* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only])
1727 : Returns the name of the table field belongs to, or table's oid if oid_only is true */
1728 : PHP_FUNCTION(pg_field_table)
1729 0 : {
1730 : zval *result;
1731 : pgsql_result_handle *pg_result;
1732 0 : long fnum = -1;
1733 0 : zend_bool return_oid = 0;
1734 : Oid oid;
1735 0 : smart_str hash_key = {0};
1736 : char *table_name;
1737 : zend_rsrc_list_entry *field_table;
1738 :
1739 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|b", &result, &fnum, &return_oid) == FAILURE) {
1740 0 : return;
1741 : }
1742 :
1743 0 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
1744 :
1745 0 : if (fnum < 0 || fnum >= PQnfields(pg_result->result)) {
1746 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified");
1747 0 : RETURN_FALSE;
1748 : }
1749 :
1750 0 : oid = PQftable(pg_result->result, fnum);
1751 :
1752 0 : if (InvalidOid == oid) {
1753 0 : RETURN_FALSE;
1754 : }
1755 :
1756 :
1757 0 : if (return_oid) {
1758 : #if UINT_MAX > LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */
1759 0 : if (oid > LONG_MAX) {
1760 0 : smart_str oidstr = {0};
1761 0 : smart_str_append_unsigned(&oidstr, oid);
1762 0 : smart_str_0(&oidstr);
1763 0 : RETURN_STRINGL(oidstr.c, oidstr.len, 0);
1764 : } else
1765 : #endif
1766 0 : RETURN_LONG((long)oid);
1767 : }
1768 :
1769 : /* try to lookup the table name in the resource list */
1770 0 : smart_str_appends(&hash_key, "pgsql_table_oid_");
1771 0 : smart_str_append_unsigned(&hash_key, oid);
1772 0 : smart_str_0(&hash_key);
1773 :
1774 0 : if (zend_hash_find(&EG(regular_list), hash_key.c, hash_key.len+1, (void **) &field_table) == SUCCESS) {
1775 0 : smart_str_free(&hash_key);
1776 0 : RETURN_STRING((char *)field_table->ptr, 1);
1777 : } else { /* Not found, lookup by querying PostgreSQL system tables */
1778 : PGresult *tmp_res;
1779 0 : smart_str querystr = {0};
1780 : zend_rsrc_list_entry new_field_table;
1781 :
1782 0 : smart_str_appends(&querystr, "select relname from pg_class where oid=");
1783 0 : smart_str_append_unsigned(&querystr, oid);
1784 0 : smart_str_0(&querystr);
1785 :
1786 :
1787 0 : if ((tmp_res = PQexec(pg_result->conn, querystr.c)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
1788 0 : if (tmp_res) {
1789 0 : PQclear(tmp_res);
1790 : }
1791 0 : smart_str_free(&querystr);
1792 0 : smart_str_free(&hash_key);
1793 0 : RETURN_FALSE;
1794 : }
1795 :
1796 0 : smart_str_free(&querystr);
1797 :
1798 0 : if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) {
1799 0 : PQclear(tmp_res);
1800 0 : smart_str_free(&hash_key);
1801 0 : RETURN_FALSE;
1802 : }
1803 :
1804 0 : Z_TYPE(new_field_table) = le_string;
1805 0 : new_field_table.ptr = estrdup(table_name);
1806 0 : zend_hash_update(&EG(regular_list), hash_key.c, hash_key.len+1, (void *) &new_field_table, sizeof(zend_rsrc_list_entry), NULL);
1807 :
1808 0 : smart_str_free(&hash_key);
1809 0 : PQclear(tmp_res);
1810 0 : RETURN_STRING(table_name, 1);
1811 : }
1812 :
1813 : }
1814 : /* }}} */
1815 : #endif
1816 :
1817 : #define PHP_PG_FIELD_NAME 1
1818 : #define PHP_PG_FIELD_SIZE 2
1819 : #define PHP_PG_FIELD_TYPE 3
1820 : #define PHP_PG_FIELD_TYPE_OID 4
1821 :
1822 : /* {{{ php_pgsql_get_field_info
1823 : */
1824 : static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
1825 21 : {
1826 : zval **result, **field;
1827 : PGresult *pgsql_result;
1828 : pgsql_result_handle *pg_result;
1829 : Oid oid;
1830 :
1831 21 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE) {
1832 0 : WRONG_PARAM_COUNT;
1833 : }
1834 :
1835 21 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
1836 :
1837 21 : pgsql_result = pg_result->result;
1838 21 : convert_to_long_ex(field);
1839 :
1840 21 : if (Z_LVAL_PP(field) < 0 || Z_LVAL_PP(field) >= PQnfields(pgsql_result)) {
1841 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified");
1842 0 : RETURN_FALSE;
1843 : }
1844 :
1845 21 : switch (entry_type) {
1846 : case PHP_PG_FIELD_NAME:
1847 7 : Z_STRVAL_P(return_value) = PQfname(pgsql_result, Z_LVAL_PP(field));
1848 7 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
1849 7 : Z_STRVAL_P(return_value) = estrndup(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value));
1850 7 : Z_TYPE_P(return_value) = IS_STRING;
1851 7 : break;
1852 : case PHP_PG_FIELD_SIZE:
1853 7 : Z_LVAL_P(return_value) = PQfsize(pgsql_result, Z_LVAL_PP(field));
1854 7 : Z_TYPE_P(return_value) = IS_LONG;
1855 7 : break;
1856 : case PHP_PG_FIELD_TYPE:
1857 7 : Z_STRVAL_P(return_value) = get_field_name(pg_result->conn, PQftype(pgsql_result, Z_LVAL_PP(field)), &EG(regular_list) TSRMLS_CC);
1858 7 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
1859 7 : Z_TYPE_P(return_value) = IS_STRING;
1860 7 : break;
1861 : case PHP_PG_FIELD_TYPE_OID:
1862 :
1863 0 : oid = PQftype(pgsql_result, Z_LVAL_PP(field));
1864 : #if UINT_MAX > LONG_MAX
1865 0 : if (oid > LONG_MAX) {
1866 0 : smart_str s = {0};
1867 0 : smart_str_append_unsigned(&s, oid);
1868 0 : smart_str_0(&s);
1869 0 : Z_STRVAL_P(return_value) = s.c;
1870 0 : Z_STRLEN_P(return_value) = s.len;
1871 0 : Z_TYPE_P(return_value) = IS_STRING;
1872 : } else
1873 : #endif
1874 : {
1875 0 : Z_LVAL_P(return_value) = (long)oid;
1876 0 : Z_TYPE_P(return_value) = IS_LONG;
1877 : }
1878 0 : break;
1879 : default:
1880 0 : RETURN_FALSE;
1881 : }
1882 : }
1883 : /* }}} */
1884 :
1885 : /* {{{ proto string pg_field_name(resource result, int field_number)
1886 : Returns the name of the field */
1887 : PHP_FUNCTION(pg_field_name)
1888 7 : {
1889 7 : php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
1890 7 : }
1891 : /* }}} */
1892 :
1893 : /* {{{ proto int pg_field_size(resource result, int field_number)
1894 : Returns the internal size of the field */
1895 : PHP_FUNCTION(pg_field_size)
1896 7 : {
1897 7 : php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
1898 7 : }
1899 : /* }}} */
1900 :
1901 : /* {{{ proto string pg_field_type(resource result, int field_number)
1902 : Returns the type name for the given field */
1903 : PHP_FUNCTION(pg_field_type)
1904 7 : {
1905 7 : php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
1906 7 : }
1907 : /* }}} */
1908 :
1909 :
1910 : /* {{{ proto string pg_field_type_oid(resource result, int field_number)
1911 : Returns the type oid for the given field */
1912 : PHP_FUNCTION(pg_field_type_oid)
1913 0 : {
1914 0 : php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
1915 0 : }
1916 : /* }}} */
1917 :
1918 : /* {{{ proto int pg_field_num(resource result, string field_name)
1919 : Returns the field number of the named field */
1920 : PHP_FUNCTION(pg_field_num)
1921 6 : {
1922 : zval **result, **field;
1923 : PGresult *pgsql_result;
1924 : pgsql_result_handle *pg_result;
1925 :
1926 6 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE) {
1927 0 : WRONG_PARAM_COUNT;
1928 : }
1929 :
1930 6 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
1931 :
1932 6 : pgsql_result = pg_result->result;
1933 :
1934 6 : convert_to_string_ex(field);
1935 6 : Z_LVAL_P(return_value) = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
1936 6 : Z_TYPE_P(return_value) = IS_LONG;
1937 : }
1938 : /* }}} */
1939 :
1940 : /* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
1941 : Returns values from a result identifier */
1942 : PHP_FUNCTION(pg_fetch_result)
1943 5618 : {
1944 5618 : zval **result, **row, **field=NULL;
1945 : PGresult *pgsql_result;
1946 : pgsql_result_handle *pg_result;
1947 : int field_offset, pgsql_row;
1948 :
1949 5618 : if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row, &field)==FAILURE) &&
1950 : (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE)) {
1951 0 : WRONG_PARAM_COUNT;
1952 : }
1953 :
1954 5618 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
1955 :
1956 5618 : pgsql_result = pg_result->result;
1957 5618 : if (ZEND_NUM_ARGS() == 2) {
1958 2 : if (pg_result->row < 0)
1959 0 : pg_result->row = 0;
1960 2 : pgsql_row = pg_result->row;
1961 2 : if (pgsql_row >= PQntuples(pgsql_result)) {
1962 0 : RETURN_FALSE;
1963 : }
1964 : } else {
1965 5616 : convert_to_long_ex(row);
1966 5616 : pgsql_row = Z_LVAL_PP(row);
1967 5616 : if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
1968 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
1969 : Z_LVAL_PP(row), Z_LVAL_PP(result));
1970 0 : RETURN_FALSE;
1971 : }
1972 : }
1973 5618 : switch(Z_TYPE_PP(field)) {
1974 : case IS_STRING:
1975 0 : field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
1976 0 : break;
1977 : default:
1978 5618 : convert_to_long_ex(field);
1979 5618 : field_offset = Z_LVAL_PP(field);
1980 : break;
1981 : }
1982 5618 : if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) {
1983 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
1984 0 : RETURN_FALSE;
1985 : }
1986 :
1987 5618 : if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
1988 0 : Z_TYPE_P(return_value) = IS_NULL;
1989 : } else {
1990 5618 : char *value = PQgetvalue(pgsql_result, pgsql_row, field_offset);
1991 5618 : int value_len = PQgetlength(pgsql_result, pgsql_row, field_offset);
1992 5618 : ZVAL_STRINGL(return_value, value, value_len, 1);
1993 : }
1994 : }
1995 : /* }}} */
1996 :
1997 : /* {{{ void php_pgsql_fetch_hash */
1998 : static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, int into_object)
1999 16865 : {
2000 16865 : zval *result, *zrow = NULL;
2001 : PGresult *pgsql_result;
2002 : pgsql_result_handle *pg_result;
2003 : int i, num_fields, pgsql_row, use_row;
2004 16865 : long row = -1;
2005 : char *element, *field_name;
2006 : uint element_len;
2007 16865 : zval *ctor_params = NULL;
2008 16865 : zend_class_entry *ce = NULL;
2009 :
2010 16865 : if (into_object) {
2011 : char *class_name;
2012 : int class_name_len;
2013 :
2014 5618 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!sz", &result, &zrow, &class_name, &class_name_len, &ctor_params) == FAILURE) {
2015 0 : return;
2016 : }
2017 5618 : if (ZEND_NUM_ARGS() < 3) {
2018 5617 : ce = zend_standard_class_def;
2019 : } else {
2020 1 : ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
2021 : }
2022 5618 : if (!ce) {
2023 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find class '%s'", class_name);
2024 0 : return;
2025 : }
2026 5618 : result_type = PGSQL_ASSOC;
2027 : } else {
2028 11247 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!l", &result, &zrow, &result_type) == FAILURE) {
2029 0 : return;
2030 : }
2031 : }
2032 16865 : if (zrow == NULL) {
2033 5629 : row = -1;
2034 : } else {
2035 11236 : convert_to_long(zrow);
2036 11236 : row = Z_LVAL_P(zrow);
2037 : }
2038 16865 : use_row = ZEND_NUM_ARGS() > 1 && row != -1;
2039 :
2040 16865 : if (!(result_type & PGSQL_BOTH)) {
2041 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
2042 0 : RETURN_FALSE;
2043 : }
2044 :
2045 16865 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
2046 :
2047 16865 : pgsql_result = pg_result->result;
2048 :
2049 16865 : if (use_row) {
2050 11236 : pgsql_row = row;
2051 11236 : pg_result->row = pgsql_row;
2052 11236 : if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
2053 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
2054 : row, Z_LVAL_P(result));
2055 0 : RETURN_FALSE;
2056 : }
2057 : } else {
2058 : /* If 2nd param is NULL, use internal row counter to access next row */
2059 5629 : pgsql_row = pg_result->row;
2060 5629 : if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
2061 5611 : RETURN_FALSE;
2062 : }
2063 18 : pg_result->row++;
2064 : }
2065 :
2066 11254 : array_init(return_value);
2067 44993 : for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
2068 33739 : if (PQgetisnull(pgsql_result, pgsql_row, i)) {
2069 11241 : if (result_type & PGSQL_NUM) {
2070 11232 : add_index_null(return_value, i);
2071 : }
2072 11241 : if (result_type & PGSQL_ASSOC) {
2073 10 : field_name = PQfname(pgsql_result, i);
2074 10 : add_assoc_null(return_value, field_name);
2075 : }
2076 : } else {
2077 22498 : element = PQgetvalue(pgsql_result, pgsql_row, i);
2078 22498 : element_len = (element ? strlen(element) : 0);
2079 22498 : if (element) {
2080 : char *data;
2081 : int data_len;
2082 22498 : int should_copy=0;
2083 :
2084 22498 : if (PG(magic_quotes_runtime)) {
2085 0 : data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
2086 : } else {
2087 22498 : data = safe_estrndup(element, element_len);
2088 22498 : data_len = element_len;
2089 : }
2090 :
2091 22498 : if (result_type & PGSQL_NUM) {
2092 22468 : add_index_stringl(return_value, i, data, data_len, should_copy);
2093 22468 : should_copy=1;
2094 : }
2095 :
2096 22498 : if (result_type & PGSQL_ASSOC) {
2097 34 : field_name = PQfname(pgsql_result, i);
2098 34 : add_assoc_stringl(return_value, field_name, data, data_len, should_copy);
2099 : }
2100 : }
2101 : }
2102 : }
2103 :
2104 11254 : if (into_object) {
2105 9 : zval dataset = *return_value;
2106 : zend_fcall_info fci;
2107 : zend_fcall_info_cache fcc;
2108 : zval *retval_ptr;
2109 :
2110 9 : object_and_properties_init(return_value, ce, NULL);
2111 9 : zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
2112 :
2113 9 : if (ce->constructor) {
2114 1 : fci.size = sizeof(fci);
2115 1 : fci.function_table = &ce->function_table;
2116 1 : fci.function_name = NULL;
2117 1 : fci.symbol_table = NULL;
2118 1 : fci.object_pp = &return_value;
2119 1 : fci.retval_ptr_ptr = &retval_ptr;
2120 2 : if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
2121 1 : if (Z_TYPE_P(ctor_params) == IS_ARRAY) {
2122 1 : HashTable *ht = Z_ARRVAL_P(ctor_params);
2123 : Bucket *p;
2124 :
2125 1 : fci.param_count = 0;
2126 1 : fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
2127 1 : p = ht->pListHead;
2128 4 : while (p != NULL) {
2129 2 : fci.params[fci.param_count++] = (zval**)p->pData;
2130 2 : p = p->pListNext;
2131 : }
2132 : } else {
2133 : /* Two problems why we throw exceptions here: PHP is typeless
2134 : * and hence passing one argument that's not an array could be
2135 : * by mistake and the other way round is possible, too. The
2136 : * single value is an array. Also we'd have to make that one
2137 : * argument passed by reference.
2138 : */
2139 0 : zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC);
2140 0 : return;
2141 : }
2142 : } else {
2143 0 : fci.param_count = 0;
2144 0 : fci.params = NULL;
2145 : }
2146 1 : fci.no_separation = 1;
2147 :
2148 1 : fcc.initialized = 1;
2149 1 : fcc.function_handler = ce->constructor;
2150 1 : fcc.calling_scope = EG(scope);
2151 1 : fcc.object_pp = &return_value;
2152 :
2153 1 : if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
2154 0 : zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
2155 : } else {
2156 1 : if (retval_ptr) {
2157 1 : zval_ptr_dtor(&retval_ptr);
2158 : }
2159 : }
2160 1 : if (fci.params) {
2161 1 : efree(fci.params);
2162 : }
2163 8 : } else if (ctor_params) {
2164 0 : zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
2165 : }
2166 : }
2167 : }
2168 : /* }}} */
2169 :
2170 : /* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
2171 : Get a row as an enumerated array */
2172 : PHP_FUNCTION(pg_fetch_row)
2173 5618 : {
2174 5618 : php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
2175 5618 : }
2176 : /* }}} */
2177 :
2178 : /* {{{ proto array pg_fetch_assoc(resource result [, int row])
2179 : Fetch a row as an assoc array */
2180 : PHP_FUNCTION(pg_fetch_assoc)
2181 5 : {
2182 : /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
2183 : there is 3rd parameter */
2184 5 : if (ZEND_NUM_ARGS() > 2)
2185 0 : WRONG_PARAM_COUNT;
2186 5 : php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
2187 : }
2188 : /* }}} */
2189 :
2190 : /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
2191 : Fetch a row as an array */
2192 : PHP_FUNCTION(pg_fetch_array)
2193 5624 : {
2194 5624 : php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
2195 5624 : }
2196 : /* }}} */
2197 :
2198 : /* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
2199 : Fetch a row as an object */
2200 : PHP_FUNCTION(pg_fetch_object)
2201 5618 : {
2202 : /* pg_fetch_object() allowed result_type used to be. 3rd parameter
2203 : must be allowed for compatibility */
2204 5618 : php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
2205 5618 : }
2206 : /* }}} */
2207 :
2208 : /* {{{ proto array pg_fetch_all(resource result)
2209 : Fetch all rows into array */
2210 : PHP_FUNCTION(pg_fetch_all)
2211 3 : {
2212 : zval *result;
2213 : PGresult *pgsql_result;
2214 : pgsql_result_handle *pg_result;
2215 :
2216 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
2217 : &result) == FAILURE) {
2218 0 : return;
2219 : }
2220 :
2221 3 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
2222 :
2223 3 : pgsql_result = pg_result->result;
2224 3 : array_init(return_value);
2225 3 : if (php_pgsql_result2array(pgsql_result, return_value TSRMLS_CC) == FAILURE) {
2226 0 : zval_dtor(return_value);
2227 0 : RETURN_FALSE;
2228 : }
2229 : }
2230 : /* }}} */
2231 :
2232 : /* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
2233 : Fetch all rows into array */
2234 : PHP_FUNCTION(pg_fetch_all_columns)
2235 0 : {
2236 : zval *result;
2237 : PGresult *pgsql_result;
2238 : pgsql_result_handle *pg_result;
2239 0 : long colno=0;
2240 : int pg_numrows, pg_row;
2241 : size_t num_fields;
2242 :
2243 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result, &colno) == FAILURE) {
2244 0 : RETURN_FALSE;
2245 : }
2246 :
2247 0 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
2248 :
2249 0 : pgsql_result = pg_result->result;
2250 :
2251 0 : num_fields = PQnfields(pgsql_result);
2252 0 : if (colno >= num_fields || colno < 0) {
2253 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column number '%ld'", colno);
2254 0 : RETURN_FALSE;
2255 : }
2256 :
2257 0 : array_init(return_value);
2258 :
2259 0 : if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
2260 0 : return;
2261 : }
2262 :
2263 0 : for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
2264 0 : if (PQgetisnull(pgsql_result, pg_row, colno)) {
2265 0 : add_next_index_null(return_value);
2266 : } else {
2267 0 : add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, colno), 1);
2268 : }
2269 : }
2270 : }
2271 : /* }}} */
2272 :
2273 : /* {{{ proto bool pg_result_seek(resource result, int offset)
2274 : Set internal row offset */
2275 : PHP_FUNCTION(pg_result_seek)
2276 2 : {
2277 : zval *result;
2278 : long row;
2279 : pgsql_result_handle *pg_result;
2280 :
2281 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &row) == FAILURE) {
2282 0 : return;
2283 : }
2284 :
2285 2 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
2286 :
2287 2 : if (row < 0 || row >= PQntuples(pg_result->result)) {
2288 0 : RETURN_FALSE;
2289 : }
2290 :
2291 : /* seek to offset */
2292 2 : pg_result->row = row;
2293 2 : RETURN_TRUE;
2294 : }
2295 : /* }}} */
2296 :
2297 :
2298 : #define PHP_PG_DATA_LENGTH 1
2299 : #define PHP_PG_DATA_ISNULL 2
2300 :
2301 : /* {{{ php_pgsql_data_info
2302 : */
2303 : static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
2304 14 : {
2305 : zval **result, **row, **field;
2306 : PGresult *pgsql_result;
2307 : pgsql_result_handle *pg_result;
2308 : int field_offset, pgsql_row;
2309 :
2310 14 : if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row, &field)==FAILURE) &&
2311 : (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result, &field)==FAILURE)) {
2312 0 : WRONG_PARAM_COUNT;
2313 : }
2314 :
2315 14 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
2316 :
2317 14 : pgsql_result = pg_result->result;
2318 14 : if (ZEND_NUM_ARGS() == 2) {
2319 14 : if (pg_result->row < 0)
2320 0 : pg_result->row = 0;
2321 14 : pgsql_row = pg_result->row;
2322 14 : if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
2323 0 : RETURN_FALSE;
2324 : }
2325 : } else {
2326 0 : convert_to_long_ex(row);
2327 0 : pgsql_row = Z_LVAL_PP(row);
2328 0 : if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
2329 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
2330 : Z_LVAL_PP(row), Z_LVAL_PP(result));
2331 0 : RETURN_FALSE;
2332 : }
2333 : }
2334 :
2335 14 : switch(Z_TYPE_PP(field)) {
2336 : case IS_STRING:
2337 0 : convert_to_string_ex(field);
2338 0 : field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
2339 0 : break;
2340 : default:
2341 14 : convert_to_long_ex(field);
2342 14 : field_offset = Z_LVAL_PP(field);
2343 : break;
2344 : }
2345 14 : if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
2346 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
2347 0 : RETURN_FALSE;
2348 : }
2349 :
2350 14 : switch (entry_type) {
2351 : case PHP_PG_DATA_LENGTH:
2352 7 : Z_LVAL_P(return_value) = PQgetlength(pgsql_result, pgsql_row, field_offset);
2353 7 : break;
2354 : case PHP_PG_DATA_ISNULL:
2355 7 : Z_LVAL_P(return_value) = PQgetisnull(pgsql_result, pgsql_row, field_offset);
2356 : break;
2357 : }
2358 14 : Z_TYPE_P(return_value) = IS_LONG;
2359 : }
2360 : /* }}} */
2361 :
2362 : /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
2363 : Returns the printed length */
2364 : PHP_FUNCTION(pg_field_prtlen)
2365 7 : {
2366 7 : php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
2367 7 : }
2368 : /* }}} */
2369 :
2370 : /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
2371 : Test if a field is NULL */
2372 : PHP_FUNCTION(pg_field_is_null)
2373 7 : {
2374 7 : php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
2375 7 : }
2376 : /* }}} */
2377 :
2378 : /* {{{ proto bool pg_free_result(resource result)
2379 : Free result memory */
2380 : PHP_FUNCTION(pg_free_result)
2381 13 : {
2382 : zval **result;
2383 : pgsql_result_handle *pg_result;
2384 :
2385 13 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result)==FAILURE) {
2386 0 : WRONG_PARAM_COUNT;
2387 : }
2388 :
2389 13 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
2390 13 : if (Z_LVAL_PP(result) == 0) {
2391 0 : RETURN_FALSE;
2392 : }
2393 13 : zend_list_delete(Z_LVAL_PP(result));
2394 13 : RETURN_TRUE;
2395 : }
2396 : /* }}} */
2397 :
2398 : /* {{{ proto string pg_last_oid(resource result)
2399 : Returns the last object identifier */
2400 : PHP_FUNCTION(pg_last_oid)
2401 7 : {
2402 : zval **result;
2403 : PGresult *pgsql_result;
2404 : pgsql_result_handle *pg_result;
2405 : #ifdef HAVE_PQOIDVALUE
2406 : Oid oid;
2407 : #endif
2408 :
2409 7 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result)==FAILURE) {
2410 0 : WRONG_PARAM_COUNT;
2411 : }
2412 :
2413 7 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL result", le_result);
2414 7 : pgsql_result = pg_result->result;
2415 : #ifdef HAVE_PQOIDVALUE
2416 7 : oid = PQoidValue(pgsql_result);
2417 7 : if (oid == InvalidOid) {
2418 7 : RETURN_FALSE;
2419 : }
2420 0 : PGSQL_RETURN_OID(oid);
2421 : #else
2422 : Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
2423 : if (Z_STRVAL_P(return_value)) {
2424 : RETURN_STRING(Z_STRVAL_P(return_value), 1);
2425 : }
2426 : RETURN_STRING("", 1);
2427 : #endif
2428 : }
2429 : /* }}} */
2430 :
2431 : /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
2432 : Enable tracing a PostgreSQL connection */
2433 : PHP_FUNCTION(pg_trace)
2434 1 : {
2435 1 : zval **z_filename, **z_mode, **pgsql_link = NULL;
2436 1 : int id = -1;
2437 : PGconn *pgsql;
2438 1 : char *mode = "w";
2439 1 : FILE *fp = NULL;
2440 : php_stream *stream;
2441 1 : id = PGG(default_link);
2442 :
2443 1 : switch (ZEND_NUM_ARGS()) {
2444 : case 1:
2445 0 : if (zend_get_parameters_ex(1, &z_filename)==FAILURE) {
2446 0 : RETURN_FALSE;
2447 : }
2448 0 : CHECK_DEFAULT_LINK(id);
2449 0 : break;
2450 : case 2:
2451 0 : if (zend_get_parameters_ex(2, &z_filename, &z_mode)==FAILURE) {
2452 0 : RETURN_FALSE;
2453 : }
2454 0 : CHECK_DEFAULT_LINK(id);
2455 0 : convert_to_string_ex(z_mode);
2456 0 : mode = Z_STRVAL_PP(z_mode);
2457 0 : break;
2458 : case 3:
2459 1 : if (zend_get_parameters_ex(3, &z_filename, &z_mode, &pgsql_link)==FAILURE) {
2460 0 : RETURN_FALSE;
2461 : }
2462 1 : convert_to_string_ex(z_mode);
2463 1 : mode = Z_STRVAL_PP(z_mode);
2464 1 : break;
2465 : default:
2466 0 : ZEND_WRONG_PARAM_COUNT();
2467 : break;
2468 : }
2469 1 : if (pgsql_link == NULL && id == -1) {
2470 0 : RETURN_FALSE;
2471 : }
2472 :
2473 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
2474 1 : convert_to_string_ex(z_filename);
2475 :
2476 1 : stream = php_stream_open_wrapper(Z_STRVAL_PP(z_filename), mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
2477 :
2478 1 : if (!stream) {
2479 0 : RETURN_FALSE;
2480 : }
2481 :
2482 1 : if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
2483 0 : php_stream_close(stream);
2484 0 : RETURN_FALSE;
2485 : }
2486 : php_stream_auto_cleanup(stream);
2487 1 : PQtrace(pgsql, fp);
2488 1 : RETURN_TRUE;
2489 : }
2490 : /* }}} */
2491 :
2492 : /* {{{ proto bool pg_untrace([resource connection])
2493 : Disable tracing of a PostgreSQL connection */
2494 : PHP_FUNCTION(pg_untrace)
2495 0 : {
2496 0 : zval **pgsql_link = NULL;
2497 0 : int id = -1;
2498 : PGconn *pgsql;
2499 :
2500 0 : switch (ZEND_NUM_ARGS()) {
2501 : case 0:
2502 0 : id = PGG(default_link);
2503 0 : CHECK_DEFAULT_LINK(id);
2504 0 : break;
2505 : case 1:
2506 0 : if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
2507 0 : RETURN_FALSE;
2508 : }
2509 0 : break;
2510 : default:
2511 0 : ZEND_WRONG_PARAM_COUNT();
2512 : break;
2513 : }
2514 0 : if (pgsql_link == NULL && id == -1) {
2515 0 : RETURN_FALSE;
2516 : }
2517 :
2518 0 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
2519 0 : PQuntrace(pgsql);
2520 0 : RETURN_TRUE;
2521 : }
2522 : /* }}} */
2523 :
2524 : /* {{{ proto int pg_lo_create([resource connection])
2525 : Create a large object */
2526 : PHP_FUNCTION(pg_lo_create)
2527 3 : {
2528 3 : zval **pgsql_link = NULL;
2529 : PGconn *pgsql;
2530 : Oid pgsql_oid;
2531 3 : int id = -1;
2532 :
2533 3 : switch(ZEND_NUM_ARGS()) {
2534 : case 0:
2535 0 : id = PGG(default_link);
2536 0 : CHECK_DEFAULT_LINK(id);
2537 0 : break;
2538 : case 1:
2539 3 : if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
2540 0 : RETURN_FALSE;
2541 : }
2542 3 : break;
2543 : default:
2544 0 : WRONG_PARAM_COUNT;
2545 : break;
2546 : }
2547 3 : if (pgsql_link == NULL && id == -1) {
2548 0 : RETURN_FALSE;
2549 : }
2550 :
2551 3 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
2552 :
2553 : /* NOTE: Archive modes not supported until I get some more data. Don't think anybody's
2554 : using it anyway. I believe it's also somehow related to the 'time travel' feature of
2555 : PostgreSQL, that's on the list of features to be removed... Create modes not supported.
2556 : What's the use of an object that can be only written to, but not read from, and vice
2557 : versa? Beats me... And the access type (r/w) must be specified again when opening
2558 : the object, probably (?) overrides this. (Jouni)
2559 : */
2560 :
2561 3 : if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
2562 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
2563 0 : RETURN_FALSE;
2564 : }
2565 3 : PGSQL_RETURN_OID(pgsql_oid);
2566 : }
2567 : /* }}} */
2568 :
2569 : /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
2570 : Delete a large object */
2571 : PHP_FUNCTION(pg_lo_unlink)
2572 3 : {
2573 3 : zval *pgsql_link = NULL;
2574 : long oid_long;
2575 : char *oid_string, *end_ptr;
2576 : int oid_strlen;
2577 : PGconn *pgsql;
2578 : Oid oid;
2579 3 : int id = -1;
2580 3 : int argc = ZEND_NUM_ARGS();
2581 :
2582 : /* accept string type since Oid type is unsigned int */
2583 3 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2584 : "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
2585 2 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
2586 2 : if ((oid_string+oid_strlen) != end_ptr) {
2587 : /* wrong integer format */
2588 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
2589 0 : RETURN_FALSE;
2590 : }
2591 : }
2592 1 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2593 : "rl", &pgsql_link, &oid_long) == SUCCESS) {
2594 0 : if (oid_long <= InvalidOid) {
2595 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
2596 0 : RETURN_FALSE;
2597 : }
2598 0 : oid = (Oid)oid_long;
2599 : }
2600 1 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2601 : "s", &oid_string, &oid_strlen) == SUCCESS) {
2602 1 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
2603 1 : if ((oid_string+oid_strlen) != end_ptr) {
2604 : /* wrong integer format */
2605 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
2606 0 : RETURN_FALSE;
2607 : }
2608 1 : id = PGG(default_link);
2609 1 : CHECK_DEFAULT_LINK(id);
2610 : }
2611 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2612 : "l", &oid_long) == SUCCESS) {
2613 0 : if (oid_long <= InvalidOid) {
2614 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID is specified");
2615 0 : RETURN_FALSE;
2616 : }
2617 0 : oid = (Oid)oid_long;
2618 0 : id = PGG(default_link);
2619 0 : CHECK_DEFAULT_LINK(id);
2620 : }
2621 : else {
2622 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
2623 0 : RETURN_FALSE;
2624 : }
2625 3 : if (pgsql_link == NULL && id == -1) {
2626 0 : RETURN_FALSE;
2627 : }
2628 :
2629 3 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
2630 :
2631 3 : if (lo_unlink(pgsql, oid) == -1) {
2632 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
2633 0 : RETURN_FALSE;
2634 : }
2635 3 : RETURN_TRUE;
2636 : }
2637 : /* }}} */
2638 :
2639 : /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
2640 : Open a large object and return fd */
2641 : PHP_FUNCTION(pg_lo_open)
2642 3 : {
2643 3 : zval *pgsql_link = NULL;
2644 : long oid_long;
2645 : char *oid_string, *end_ptr, *mode_string;
2646 : int oid_strlen, mode_strlen;
2647 : PGconn *pgsql;
2648 : Oid oid;
2649 3 : int id = -1, pgsql_mode=0, pgsql_lofd;
2650 3 : int create=0;
2651 : pgLofp *pgsql_lofp;
2652 3 : int argc = ZEND_NUM_ARGS();
2653 :
2654 : /* accept string type since Oid is unsigned int */
2655 3 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2656 : "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
2657 3 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
2658 3 : if ((oid_string+oid_strlen) != end_ptr) {
2659 : /* wrong integer format */
2660 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
2661 0 : RETURN_FALSE;
2662 : }
2663 : }
2664 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2665 : "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
2666 0 : if (oid_long <= InvalidOid) {
2667 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
2668 0 : RETURN_FALSE;
2669 : }
2670 0 : oid = (Oid)oid_long;
2671 : }
2672 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2673 : "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
2674 0 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
2675 0 : if ((oid_string+oid_strlen) != end_ptr) {
2676 : /* wrong integer format */
2677 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
2678 0 : RETURN_FALSE;
2679 : }
2680 0 : id = PGG(default_link);
2681 0 : CHECK_DEFAULT_LINK(id);
2682 : }
2683 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2684 : "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
2685 0 : if (oid_long <= InvalidOid) {
2686 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
2687 0 : RETURN_FALSE;
2688 : }
2689 0 : oid = (Oid)oid_long;
2690 0 : id = PGG(default_link);
2691 0 : CHECK_DEFAULT_LINK(id);
2692 : }
2693 : else {
2694 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
2695 0 : RETURN_FALSE;
2696 : }
2697 3 : if (pgsql_link == NULL && id == -1) {
2698 0 : RETURN_FALSE;
2699 : }
2700 :
2701 3 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
2702 :
2703 : /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
2704 : faster to type. Unfortunately, doesn't behave the same way as fopen()...
2705 : (Jouni)
2706 : */
2707 :
2708 3 : if (strchr(mode_string, 'r') == mode_string) {
2709 0 : pgsql_mode |= INV_READ;
2710 0 : if (strchr(mode_string, '+') == mode_string+1) {
2711 0 : pgsql_mode |= INV_WRITE;
2712 : }
2713 : }
2714 3 : if (strchr(mode_string, 'w') == mode_string) {
2715 3 : pgsql_mode |= INV_WRITE;
2716 3 : create = 1;
2717 3 : if (strchr(mode_string, '+') == mode_string+1) {
2718 0 : pgsql_mode |= INV_READ;
2719 : }
2720 : }
2721 :
2722 3 : pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
2723 :
2724 3 : if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
2725 0 : if (create) {
2726 0 : if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
2727 0 : efree(pgsql_lofp);
2728 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
2729 0 : RETURN_FALSE;
2730 : } else {
2731 0 : if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
2732 0 : if (lo_unlink(pgsql, oid) == -1) {
2733 0 : efree(pgsql_lofp);
2734 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
2735 0 : RETURN_FALSE;
2736 : }
2737 0 : efree(pgsql_lofp);
2738 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
2739 0 : RETURN_FALSE;
2740 : } else {
2741 0 : pgsql_lofp->conn = pgsql;
2742 0 : pgsql_lofp->lofd = pgsql_lofd;
2743 0 : Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp);
2744 0 : Z_TYPE_P(return_value) = IS_LONG;
2745 : }
2746 : }
2747 : } else {
2748 0 : efree(pgsql_lofp);
2749 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
2750 0 : RETURN_FALSE;
2751 : }
2752 : } else {
2753 3 : pgsql_lofp->conn = pgsql;
2754 3 : pgsql_lofp->lofd = pgsql_lofd;
2755 3 : ZEND_REGISTER_RESOURCE(return_value, pgsql_lofp, le_lofp);
2756 : }
2757 : }
2758 : /* }}} */
2759 :
2760 : /* {{{ proto bool pg_lo_close(resource large_object)
2761 : Close a large object */
2762 : PHP_FUNCTION(pg_lo_close)
2763 3 : {
2764 : zval **pgsql_lofp;
2765 : pgLofp *pgsql;
2766 :
2767 3 : switch(ZEND_NUM_ARGS()) {
2768 : case 1:
2769 3 : if (zend_get_parameters_ex(1, &pgsql_lofp)==FAILURE) {
2770 0 : RETURN_FALSE;
2771 : }
2772 : break;
2773 : default:
2774 0 : WRONG_PARAM_COUNT;
2775 : break;
2776 : }
2777 :
2778 3 : ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_lofp, -1, "PostgreSQL large object", le_lofp);
2779 :
2780 3 : if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
2781 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
2782 0 : RETVAL_FALSE;
2783 : } else {
2784 3 : RETVAL_TRUE;
2785 : }
2786 :
2787 3 : zend_list_delete(Z_RESVAL_PP(pgsql_lofp));
2788 3 : return;
2789 : }
2790 : /* }}} */
2791 :
2792 : #define PGSQL_LO_READ_BUF_SIZE 8192
2793 :
2794 : /* {{{ proto string pg_lo_read(resource large_object [, int len])
2795 : Read a large object */
2796 : PHP_FUNCTION(pg_lo_read)
2797 1 : {
2798 : zval **pgsql_id, **len;
2799 1 : int buf_len = PGSQL_LO_READ_BUF_SIZE, nbytes;
2800 : char *buf;
2801 : pgLofp *pgsql;
2802 :
2803 1 : if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
2804 : zend_get_parameters_ex(ZEND_NUM_ARGS(), &pgsql_id, &len) == FAILURE) {
2805 0 : WRONG_PARAM_COUNT;
2806 : }
2807 :
2808 1 : ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_id, -1, "PostgreSQL large object", le_lofp);
2809 :
2810 1 : if (ZEND_NUM_ARGS() > 1) {
2811 1 : convert_to_long_ex(len);
2812 1 : buf_len = Z_LVAL_PP(len);
2813 : }
2814 :
2815 1 : buf = (char *) safe_emalloc(sizeof(char), (buf_len+1), 0);
2816 1 : if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) {
2817 0 : efree(buf);
2818 0 : RETURN_FALSE;
2819 : }
2820 :
2821 1 : buf[nbytes] = '\0';
2822 1 : RETURN_STRINGL(buf, nbytes, 0);
2823 : }
2824 : /* }}} */
2825 :
2826 : /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
2827 : Write a large object */
2828 : PHP_FUNCTION(pg_lo_write)
2829 1 : {
2830 : zval **pgsql_id, **str, **z_len;
2831 : int nbytes;
2832 : int len;
2833 : pgLofp *pgsql;
2834 1 : int argc = ZEND_NUM_ARGS();
2835 :
2836 1 : if (argc < 2 || argc > 3 ||
2837 : zend_get_parameters_ex(argc, &pgsql_id, &str, &z_len) == FAILURE) {
2838 0 : WRONG_PARAM_COUNT;
2839 : }
2840 :
2841 1 : convert_to_string_ex(str);
2842 :
2843 1 : if (argc > 2) {
2844 0 : convert_to_long_ex(z_len);
2845 0 : if (Z_LVAL_PP(z_len) > Z_STRLEN_PP(str)) {
2846 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write more than buffer size %d. Tried to write %ld",
2847 : Z_STRLEN_PP(str), Z_LVAL_PP(z_len));
2848 0 : RETURN_FALSE;
2849 : }
2850 0 : if (Z_LVAL_PP(z_len) < 0) {
2851 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer size must be larger than 0, but %ld was specified", Z_LVAL_PP(z_len));
2852 0 : RETURN_FALSE;
2853 : }
2854 0 : len = Z_LVAL_PP(z_len);
2855 : }
2856 : else {
2857 1 : len = Z_STRLEN_PP(str);
2858 : }
2859 :
2860 1 : ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_id, -1, "PostgreSQL large object", le_lofp);
2861 :
2862 1 : if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, Z_STRVAL_PP(str), len)) == -1) {
2863 0 : RETURN_FALSE;
2864 : }
2865 :
2866 1 : RETURN_LONG(nbytes);
2867 : }
2868 : /* }}} */
2869 :
2870 : /* {{{ proto int pg_lo_read_all(resource large_object)
2871 : Read a large object and send straight to browser */
2872 : PHP_FUNCTION(pg_lo_read_all)
2873 1 : {
2874 : zval **pgsql_id;
2875 : int tbytes;
2876 : volatile int nbytes;
2877 : char buf[PGSQL_LO_READ_BUF_SIZE];
2878 : pgLofp *pgsql;
2879 :
2880 1 : switch(ZEND_NUM_ARGS()) {
2881 : case 1:
2882 1 : if (zend_get_parameters_ex(1, &pgsql_id)==FAILURE) {
2883 0 : RETURN_FALSE;
2884 : }
2885 : break;
2886 : default:
2887 0 : WRONG_PARAM_COUNT;
2888 : break;
2889 : }
2890 :
2891 1 : ZEND_FETCH_RESOURCE(pgsql, pgLofp *, pgsql_id, -1, "PostgreSQL large object", le_lofp);
2892 :
2893 1 : tbytes = 0;
2894 3 : while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
2895 1 : php_body_write(buf, nbytes TSRMLS_CC);
2896 1 : tbytes += nbytes;
2897 : }
2898 1 : RETURN_LONG(tbytes);
2899 : }
2900 : /* }}} */
2901 :
2902 : /* {{{ proto int pg_lo_import([resource connection, ] string filename)
2903 : Import large object direct from filesystem */
2904 : PHP_FUNCTION(pg_lo_import)
2905 1 : {
2906 1 : zval *pgsql_link = NULL;
2907 : char *file_in;
2908 1 : int id = -1, name_len;
2909 1 : int argc = ZEND_NUM_ARGS();
2910 : PGconn *pgsql;
2911 : Oid oid;
2912 :
2913 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2914 : "rs", &pgsql_link, &file_in, &name_len) == SUCCESS) {
2915 : ;
2916 : }
2917 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2918 : "s", &file_in, &name_len) == SUCCESS) {
2919 0 : id = PGG(default_link);
2920 0 : CHECK_DEFAULT_LINK(id);
2921 : }
2922 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2923 : "sr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
2924 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
2925 : }
2926 : else {
2927 0 : WRONG_PARAM_COUNT;
2928 : }
2929 :
2930 1 : if (PG(safe_mode) &&(!php_checkuid(file_in, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
2931 0 : RETURN_FALSE;
2932 : }
2933 :
2934 1 : if (php_check_open_basedir(file_in TSRMLS_CC)) {
2935 0 : RETURN_FALSE;
2936 : }
2937 :
2938 1 : if (pgsql_link == NULL && id == -1) {
2939 0 : RETURN_FALSE;
2940 : }
2941 :
2942 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
2943 :
2944 1 : oid = lo_import(pgsql, file_in);
2945 :
2946 1 : if (oid == InvalidOid) {
2947 0 : RETURN_FALSE;
2948 : }
2949 1 : PGSQL_RETURN_OID(oid);
2950 : }
2951 : /* }}} */
2952 :
2953 : /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
2954 : Export large object direct to filesystem */
2955 : PHP_FUNCTION(pg_lo_export)
2956 1 : {
2957 1 : zval *pgsql_link = NULL;
2958 : char *file_out, *oid_string, *end_ptr;
2959 : int oid_strlen;
2960 1 : int id = -1, name_len;
2961 : long oid_long;
2962 : Oid oid;
2963 : PGconn *pgsql;
2964 1 : int argc = ZEND_NUM_ARGS();
2965 :
2966 : /* allow string to handle large OID value correctly */
2967 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2968 : "rls", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
2969 0 : if (oid_long <= InvalidOid) {
2970 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
2971 0 : RETURN_FALSE;
2972 : }
2973 0 : oid = (Oid)oid_long;
2974 : }
2975 1 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2976 : "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
2977 0 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
2978 0 : if ((oid_string+oid_strlen) != end_ptr) {
2979 : /* wrong integer format */
2980 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
2981 0 : RETURN_FALSE;
2982 : }
2983 : }
2984 1 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2985 : "ls", &oid_long, &file_out, &name_len) == SUCCESS) {
2986 0 : if (oid_long <= InvalidOid) {
2987 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
2988 0 : RETURN_FALSE;
2989 : }
2990 0 : oid = (Oid)oid_long;
2991 0 : id = PGG(default_link);
2992 0 : CHECK_DEFAULT_LINK(id);
2993 : }
2994 1 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
2995 : "ss", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
2996 0 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
2997 0 : if ((oid_string+oid_strlen) != end_ptr) {
2998 : /* wrong integer format */
2999 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
3000 0 : RETURN_FALSE;
3001 : }
3002 0 : id = PGG(default_link);
3003 0 : CHECK_DEFAULT_LINK(id);
3004 : }
3005 1 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
3006 : "ssr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
3007 1 : oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3008 1 : if ((oid_string+oid_strlen) != end_ptr) {
3009 : /* wrong integer format */
3010 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
3011 0 : RETURN_FALSE;
3012 : }
3013 : }
3014 0 : else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
3015 : "lsr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
3016 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
3017 0 : if (oid_long <= InvalidOid) {
3018 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
3019 0 : RETURN_FALSE;
3020 : }
3021 0 : oid = (Oid)oid_long;
3022 : }
3023 : else {
3024 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 2 or 3 arguments");
3025 0 : RETURN_FALSE;
3026 : }
3027 :
3028 1 : if (PG(safe_mode) &&(!php_checkuid(file_out, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
3029 0 : RETURN_FALSE;
3030 : }
3031 :
3032 1 : if (php_check_open_basedir(file_out TSRMLS_CC)) {
3033 0 : RETURN_FALSE;
3034 : }
3035 :
3036 1 : if (pgsql_link == NULL && id == -1) {
3037 0 : RETURN_FALSE;
3038 : }
3039 :
3040 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3041 :
3042 1 : if (lo_export(pgsql, oid, file_out)) {
3043 1 : RETURN_TRUE;
3044 : }
3045 0 : RETURN_FALSE;
3046 : }
3047 : /* }}} */
3048 :
3049 : /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
3050 : Seeks position of large object */
3051 : PHP_FUNCTION(pg_lo_seek)
3052 1 : {
3053 1 : zval *pgsql_id = NULL;
3054 1 : long offset = 0, whence = SEEK_CUR;
3055 : pgLofp *pgsql;
3056 1 : int argc = ZEND_NUM_ARGS();
3057 :
3058 1 : if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
3059 0 : return;
3060 : }
3061 1 : if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
3062 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid whence parameter");
3063 0 : return;
3064 : }
3065 :
3066 1 : ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
3067 :
3068 1 : if (lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence) > -1) {
3069 1 : RETURN_TRUE;
3070 : } else {
3071 0 : RETURN_FALSE;
3072 : }
3073 : }
3074 : /* }}} */
3075 :
3076 : /* {{{ proto int pg_lo_tell(resource large_object)
3077 : Returns current position of large object */
3078 : PHP_FUNCTION(pg_lo_tell)
3079 1 : {
3080 1 : zval *pgsql_id = NULL;
3081 1 : int offset = 0;
3082 : pgLofp *pgsql;
3083 1 : int argc = ZEND_NUM_ARGS();
3084 :
3085 1 : if (zend_parse_parameters(argc TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
3086 0 : return;
3087 : }
3088 :
3089 1 : ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
3090 :
3091 1 : offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
3092 1 : RETURN_LONG(offset);
3093 : }
3094 : /* }}} */
3095 :
3096 : #if HAVE_PQSETERRORVERBOSITY
3097 : /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
3098 : Set error verbosity */
3099 : PHP_FUNCTION(pg_set_error_verbosity)
3100 3 : {
3101 3 : zval **verbosity, **pgsql_link = NULL;
3102 : long val;
3103 3 : int id = -1;
3104 : PGconn *pgsql;
3105 :
3106 3 : switch(ZEND_NUM_ARGS()) {
3107 : case 1:
3108 3 : if (zend_get_parameters_ex(1, &verbosity)==FAILURE) {
3109 0 : RETURN_FALSE;
3110 : }
3111 3 : id = PGG(default_link);
3112 3 : CHECK_DEFAULT_LINK(id);
3113 3 : break;
3114 : case 2:
3115 0 : if (zend_get_parameters_ex(2, &pgsql_link, &verbosity)==FAILURE) {
3116 0 : RETURN_FALSE;
3117 : }
3118 0 : break;
3119 : default:
3120 0 : WRONG_PARAM_COUNT;
3121 : break;
3122 : }
3123 3 : if (pgsql_link == NULL && id == -1) {
3124 0 : RETURN_FALSE;
3125 : }
3126 :
3127 3 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3128 :
3129 3 : convert_to_long_ex(verbosity);
3130 3 : val = Z_LVAL_PP(verbosity);
3131 3 : if (val & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
3132 2 : Z_LVAL_P(return_value) = PQsetErrorVerbosity(pgsql, val);
3133 2 : Z_TYPE_P(return_value) = IS_LONG;
3134 : } else {
3135 1 : RETURN_FALSE;
3136 : }
3137 : }
3138 : /* }}} */
3139 : #endif
3140 :
3141 : #ifdef HAVE_PQCLIENTENCODING
3142 : /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
3143 : Set client encoding */
3144 : PHP_FUNCTION(pg_set_client_encoding)
3145 1 : {
3146 1 : zval **encoding, **pgsql_link = NULL;
3147 1 : int id = -1;
3148 : PGconn *pgsql;
3149 :
3150 1 : switch(ZEND_NUM_ARGS()) {
3151 : case 1:
3152 0 : if (zend_get_parameters_ex(1, &encoding)==FAILURE) {
3153 0 : RETURN_FALSE;
3154 : }
3155 0 : id = PGG(default_link);
3156 0 : CHECK_DEFAULT_LINK(id);
3157 0 : break;
3158 : case 2:
3159 1 : if (zend_get_parameters_ex(2, &pgsql_link, &encoding)==FAILURE) {
3160 0 : RETURN_FALSE;
3161 : }
3162 1 : break;
3163 : default:
3164 0 : WRONG_PARAM_COUNT;
3165 : break;
3166 : }
3167 1 : if (pgsql_link == NULL && id == -1) {
3168 0 : RETURN_FALSE;
3169 : }
3170 :
3171 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3172 :
3173 1 : convert_to_string_ex(encoding);
3174 1 : Z_LVAL_P(return_value) = PQsetClientEncoding(pgsql, Z_STRVAL_PP(encoding));
3175 1 : Z_TYPE_P(return_value) = IS_LONG;
3176 :
3177 : }
3178 : /* }}} */
3179 :
3180 : /* {{{ proto string pg_client_encoding([resource connection])
3181 : Get the current client encoding */
3182 : PHP_FUNCTION(pg_client_encoding)
3183 1 : {
3184 1 : zval **pgsql_link = NULL;
3185 1 : int id = -1;
3186 : PGconn *pgsql;
3187 :
3188 1 : switch(ZEND_NUM_ARGS()) {
3189 : case 0:
3190 0 : id = PGG(default_link);
3191 0 : CHECK_DEFAULT_LINK(id);
3192 0 : break;
3193 : case 1:
3194 1 : if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
3195 0 : RETURN_FALSE;
3196 : }
3197 1 : break;
3198 : default:
3199 0 : WRONG_PARAM_COUNT;
3200 : break;
3201 : }
3202 1 : if (pgsql_link == NULL && id == -1) {
3203 0 : RETURN_FALSE;
3204 : }
3205 :
3206 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3207 :
3208 : /* Just do the same as found in PostgreSQL sources... */
3209 :
3210 : #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
3211 : #define pg_encoding_to_char(x) "SQL_ASCII"
3212 : #endif
3213 :
3214 1 : Z_STRVAL_P(return_value)
3215 : = (char *) pg_encoding_to_char(PQclientEncoding(pgsql));
3216 1 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
3217 1 : Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
3218 1 : Z_TYPE_P(return_value) = IS_STRING;
3219 : }
3220 : /* }}} */
3221 : #endif
3222 :
3223 : #if !HAVE_PQGETCOPYDATA
3224 : #define COPYBUFSIZ 8192
3225 : #endif
3226 :
3227 : /* {{{ proto bool pg_end_copy([resource connection])
3228 : Sync with backend. Completes the Copy command */
3229 : PHP_FUNCTION(pg_end_copy)
3230 0 : {
3231 0 : zval **pgsql_link = NULL;
3232 0 : int id = -1;
3233 : PGconn *pgsql;
3234 0 : int result = 0;
3235 :
3236 0 : switch(ZEND_NUM_ARGS()) {
3237 : case 0:
3238 0 : id = PGG(default_link);
3239 0 : CHECK_DEFAULT_LINK(id);
3240 0 : break;
3241 : case 1:
3242 0 : if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) {
3243 0 : RETURN_FALSE;
3244 : }
3245 0 : break;
3246 : default:
3247 0 : WRONG_PARAM_COUNT;
3248 : break;
3249 : }
3250 0 : if (pgsql_link == NULL && id == -1) {
3251 0 : RETURN_FALSE;
3252 : }
3253 :
3254 0 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3255 :
3256 0 : result = PQendcopy(pgsql);
3257 :
3258 0 : if (result!=0) {
3259 0 : PHP_PQ_ERROR("Query failed: %s", pgsql);
3260 0 : RETURN_FALSE;
3261 : }
3262 0 : RETURN_TRUE;
3263 : }
3264 : /* }}} */
3265 :
3266 :
3267 : /* {{{ proto bool pg_put_line([resource connection,] string query)
3268 : Send null-terminated string to backend server*/
3269 : PHP_FUNCTION(pg_put_line)
3270 0 : {
3271 0 : zval **query, **pgsql_link = NULL;
3272 0 : int id = -1;
3273 : PGconn *pgsql;
3274 0 : int result = 0;
3275 :
3276 0 : switch(ZEND_NUM_ARGS()) {
3277 : case 1:
3278 0 : if (zend_get_parameters_ex(1, &query)==FAILURE) {
3279 0 : RETURN_FALSE;
3280 : }
3281 0 : id = PGG(default_link);
3282 0 : CHECK_DEFAULT_LINK(id);
3283 0 : break;
3284 : case 2:
3285 0 : if (zend_get_parameters_ex(2, &pgsql_link, &query)==FAILURE) {
3286 0 : RETURN_FALSE;
3287 : }
3288 0 : break;
3289 : default:
3290 0 : WRONG_PARAM_COUNT;
3291 : break;
3292 : }
3293 0 : if (pgsql_link == NULL && id == -1) {
3294 0 : RETURN_FALSE;
3295 : }
3296 :
3297 0 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3298 :
3299 0 : convert_to_string_ex(query);
3300 0 : result = PQputline(pgsql, Z_STRVAL_PP(query));
3301 0 : if (result==EOF) {
3302 0 : PHP_PQ_ERROR("Query failed: %s", pgsql);
3303 0 : RETURN_FALSE;
3304 : }
3305 0 : RETURN_TRUE;
3306 : }
3307 : /* }}} */
3308 :
3309 : /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
3310 : Copy table to array */
3311 : PHP_FUNCTION(pg_copy_to)
3312 1 : {
3313 : zval *pgsql_link;
3314 1 : char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
3315 : int table_name_len, pg_delim_len, pg_null_as_len;
3316 : char *query;
3317 1 : int id = -1;
3318 : PGconn *pgsql;
3319 : PGresult *pgsql_result;
3320 : ExecStatusType status;
3321 1 : int copydone = 0;
3322 : #if !HAVE_PQGETCOPYDATA
3323 : char copybuf[COPYBUFSIZ];
3324 : #endif
3325 1 : char *csv = (char *)NULL;
3326 : int ret;
3327 1 : int argc = ZEND_NUM_ARGS();
3328 :
3329 1 : if (zend_parse_parameters(argc TSRMLS_CC, "rs|ss",
3330 : &pgsql_link, &table_name, &table_name_len,
3331 : &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
3332 0 : return;
3333 : }
3334 1 : if (!pg_delim) {
3335 1 : pg_delim = "\t";
3336 : }
3337 :
3338 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3339 :
3340 1 : if (!pg_null_as) {
3341 1 : pg_null_as = safe_estrdup("\\\\N");
3342 : }
3343 :
3344 1 : spprintf(&query, 0, "COPY \"%s\" TO STDOUT DELIMITERS '%c' WITH NULL AS '%s'", table_name, *pg_delim, pg_null_as);
3345 :
3346 2 : while ((pgsql_result = PQgetResult(pgsql))) {
3347 0 : PQclear(pgsql_result);
3348 : }
3349 1 : pgsql_result = PQexec(pgsql, query);
3350 1 : efree(pg_null_as);
3351 1 : efree(query);
3352 :
3353 1 : if (pgsql_result) {
3354 1 : status = PQresultStatus(pgsql_result);
3355 : } else {
3356 0 : status = (ExecStatusType) PQstatus(pgsql);
3357 : }
3358 :
3359 1 : switch (status) {
3360 : case PGRES_COPY_OUT:
3361 1 : if (pgsql_result) {
3362 1 : PQclear(pgsql_result);
3363 1 : array_init(return_value);
3364 : #if HAVE_PQGETCOPYDATA
3365 1005 : while (!copydone)
3366 : {
3367 1003 : ret = PQgetCopyData(pgsql, &csv, 0);
3368 1003 : switch (ret) {
3369 : case -1:
3370 1 : copydone = 1;
3371 1 : break;
3372 : case 0:
3373 : case -2:
3374 0 : PHP_PQ_ERROR("getline failed: %s", pgsql);
3375 0 : RETURN_FALSE;
3376 : break;
3377 : default:
3378 1002 : add_next_index_string(return_value, csv, 1);
3379 1002 : PQfreemem(csv);
3380 : break;
3381 : }
3382 : }
3383 : #else
3384 : while (!copydone)
3385 : {
3386 : if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
3387 : PHP_PQ_ERROR("getline failed: %s", pgsql);
3388 : RETURN_FALSE;
3389 : }
3390 :
3391 : if (copybuf[0] == '\\' &&
3392 : copybuf[1] == '.' &&
3393 : copybuf[2] == '\0')
3394 : {
3395 : copydone = 1;
3396 : }
3397 : else
3398 : {
3399 : if (csv == (char *)NULL) {
3400 : csv = estrdup(copybuf);
3401 : } else {
3402 : csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
3403 : strcat(csv, copybuf);
3404 : }
3405 :
3406 : switch (ret)
3407 : {
3408 : case EOF:
3409 : copydone = 1;
3410 : case 0:
3411 : add_next_index_string(return_value, csv, 1);
3412 : efree(csv);
3413 : csv = (char *)NULL;
3414 : break;
3415 : case 1:
3416 : break;
3417 : }
3418 : }
3419 : }
3420 : if (PQendcopy(pgsql)) {
3421 : PHP_PQ_ERROR("endcopy failed: %s", pgsql);
3422 : RETURN_FALSE;
3423 : }
3424 : #endif
3425 3 : while ((pgsql_result = PQgetResult(pgsql))) {
3426 1 : PQclear(pgsql_result);
3427 : }
3428 : } else {
3429 0 : PQclear(pgsql_result);
3430 0 : RETURN_FALSE;
3431 : }
3432 1 : break;
3433 : default:
3434 0 : PQclear(pgsql_result);
3435 0 : PHP_PQ_ERROR("Copy command failed: %s", pgsql);
3436 0 : RETURN_FALSE;
3437 : break;
3438 : }
3439 : }
3440 : /* }}} */
3441 :
3442 : /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
3443 : Copy table from array */
3444 : PHP_FUNCTION(pg_copy_from)
3445 1 : {
3446 1 : zval *pgsql_link = NULL, *pg_rows;
3447 : zval **tmp;
3448 1 : char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
3449 : int table_name_len, pg_delim_len, pg_null_as_len;
3450 1 : int pg_null_as_free = 0;
3451 : char *query;
3452 : HashPosition pos;
3453 1 : int id = -1;
3454 : PGconn *pgsql;
3455 : PGresult *pgsql_result;
3456 : ExecStatusType status;
3457 1 : int argc = ZEND_NUM_ARGS();
3458 :
3459 1 : if (zend_parse_parameters(argc TSRMLS_CC, "rsa|ss",
3460 : &pgsql_link, &table_name, &table_name_len, &pg_rows,
3461 : &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
3462 0 : return;
3463 : }
3464 1 : if (!pg_delim) {
3465 1 : pg_delim = "\t";
3466 : }
3467 1 : if (!pg_null_as) {
3468 1 : pg_null_as = safe_estrdup("\\\\N");
3469 1 : pg_null_as_free = 1;
3470 : }
3471 :
3472 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3473 :
3474 1 : spprintf(&query, 0, "COPY \"%s\" FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
3475 2 : while ((pgsql_result = PQgetResult(pgsql))) {
3476 0 : PQclear(pgsql_result);
3477 : }
3478 1 : pgsql_result = PQexec(pgsql, query);
3479 :
3480 1 : if (pg_null_as_free) {
3481 1 : efree(pg_null_as);
3482 : }
3483 1 : efree(query);
3484 :
3485 1 : if (pgsql_result) {
3486 1 : status = PQresultStatus(pgsql_result);
3487 : } else {
3488 0 : status = (ExecStatusType) PQstatus(pgsql);
3489 : }
3490 :
3491 1 : switch (status) {
3492 : case PGRES_COPY_IN:
3493 1 : if (pgsql_result) {
3494 1 : int command_failed = 0;
3495 1 : PQclear(pgsql_result);
3496 1 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
3497 : #if HAVE_PQPUTCOPYDATA
3498 1004 : while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
3499 1002 : convert_to_string_ex(tmp);
3500 1002 : query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2);
3501 1002 : strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2);
3502 1002 : if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') {
3503 0 : strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2);
3504 : }
3505 1002 : if (PQputCopyData(pgsql, query, strlen(query)) != 1) {
3506 0 : efree(query);
3507 0 : PHP_PQ_ERROR("copy failed: %s", pgsql);
3508 0 : RETURN_FALSE;
3509 : }
3510 1002 : efree(query);
3511 1002 : zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
3512 : }
3513 1 : if (PQputCopyEnd(pgsql, NULL) != 1) {
3514 0 : PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
3515 0 : RETURN_FALSE;
3516 : }
3517 : #else
3518 : while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
3519 : convert_to_string_ex(tmp);
3520 : query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2);
3521 : strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2);
3522 : if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') {
3523 : strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2);
3524 : }
3525 : if (PQputline(pgsql, query)==EOF) {
3526 : efree(query);
3527 : PHP_PQ_ERROR("copy failed: %s", pgsql);
3528 : RETURN_FALSE;
3529 : }
3530 : efree(query);
3531 : zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
3532 : }
3533 : if (PQputline(pgsql, "\\.\n") == EOF) {
3534 : PHP_PQ_ERROR("putline failed: %s", pgsql);
3535 : RETURN_FALSE;
3536 : }
3537 : if (PQendcopy(pgsql)) {
3538 : PHP_PQ_ERROR("endcopy failed: %s", pgsql);
3539 : RETURN_FALSE;
3540 : }
3541 : #endif
3542 3 : while ((pgsql_result = PQgetResult(pgsql))) {
3543 1 : if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
3544 0 : PHP_PQ_ERROR("Copy command failed: %s", pgsql);
3545 0 : command_failed = 1;
3546 : }
3547 1 : PQclear(pgsql_result);
3548 : }
3549 1 : if (command_failed) {
3550 0 : RETURN_FALSE;
3551 : }
3552 : } else {
3553 0 : PQclear(pgsql_result);
3554 0 : RETURN_FALSE;
3555 : }
3556 1 : RETURN_TRUE;
3557 : break;
3558 : default:
3559 0 : PQclear(pgsql_result);
3560 0 : PHP_PQ_ERROR("Copy command failed: %s", pgsql);
3561 0 : RETURN_FALSE;
3562 : break;
3563 : }
3564 : }
3565 : /* }}} */
3566 :
3567 : #ifdef HAVE_PQESCAPE
3568 : /* {{{ proto string pg_escape_string([resource connection,] string data)
3569 : Escape string for text/char type */
3570 : PHP_FUNCTION(pg_escape_string)
3571 1 : {
3572 1 : char *from = NULL, *to = NULL;
3573 : zval *pgsql_link;
3574 : #ifdef HAVE_PQESCAPE_CONN
3575 : PGconn *pgsql;
3576 : #endif
3577 : int to_len;
3578 : int from_len;
3579 1 : int id = -1;
3580 :
3581 1 : switch (ZEND_NUM_ARGS()) {
3582 : case 1:
3583 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
3584 0 : return;
3585 : }
3586 1 : pgsql_link = NULL;
3587 1 : id = PGG(default_link);
3588 1 : break;
3589 :
3590 : default:
3591 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
3592 0 : return;
3593 : }
3594 : break;
3595 : }
3596 :
3597 1 : to = (char *) safe_emalloc(from_len, 2, 1);
3598 :
3599 : #ifdef HAVE_PQESCAPE_CONN
3600 1 : if (pgsql_link != NULL || id != -1) {
3601 0 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3602 0 : to_len = (int) PQescapeStringConn(pgsql, to, from, (size_t)from_len, NULL);
3603 : } else
3604 : #endif
3605 1 : to_len = (int) PQescapeString(to, from, (size_t)from_len);
3606 :
3607 1 : RETURN_STRINGL(to, to_len, 0);
3608 : }
3609 : /* }}} */
3610 :
3611 : /* {{{ proto string pg_escape_bytea([resource connection,] string data)
3612 : Escape binary for bytea type */
3613 : PHP_FUNCTION(pg_escape_bytea)
3614 3 : {
3615 3 : char *from = NULL, *to = NULL;
3616 : size_t to_len;
3617 3 : int from_len, id = -1;
3618 : #ifdef HAVE_PQESCAPE_BYTEA_CONN
3619 : PGconn *pgsql;
3620 : #endif
3621 : zval *pgsql_link;
3622 :
3623 3 : switch (ZEND_NUM_ARGS()) {
3624 : case 1:
3625 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
3626 0 : return;
3627 : }
3628 3 : pgsql_link = NULL;
3629 3 : id = PGG(default_link);
3630 3 : break;
3631 :
3632 : default:
3633 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
3634 0 : return;
3635 : }
3636 : break;
3637 : }
3638 :
3639 : #ifdef HAVE_PQESCAPE_BYTEA_CONN
3640 4 : if (pgsql_link != NULL || id != -1) {
3641 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3642 1 : to = (char *)PQescapeByteaConn(pgsql, from, (size_t)from_len, &to_len);
3643 : } else
3644 : #endif
3645 2 : to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
3646 :
3647 3 : RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes addtional '\0' */
3648 3 : PQfreemem(to);
3649 : }
3650 : /* }}} */
3651 :
3652 : #if !HAVE_PQUNESCAPEBYTEA
3653 : /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
3654 : Renamed to php_pgsql_unescape_bytea() */
3655 : /*
3656 : * PQunescapeBytea - converts the null terminated string representation
3657 : * of a bytea, strtext, into binary, filling a buffer. It returns a
3658 : * pointer to the buffer which is NULL on error, and the size of the
3659 : * buffer in retbuflen. The pointer may subsequently be used as an
3660 : * argument to the function free(3). It is the reverse of PQescapeBytea.
3661 : *
3662 : * The following transformations are reversed:
3663 : * '\0' == ASCII 0 == \000
3664 : * '\'' == ASCII 39 == \'
3665 : * '\\' == ASCII 92 == \\
3666 : *
3667 : * States:
3668 : * 0 normal 0->1->2->3->4
3669 : * 1 \ 1->5
3670 : * 2 \0 1->6
3671 : * 3 \00
3672 : * 4 \000
3673 : * 5 \'
3674 : * 6 \\
3675 : */
3676 : static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen)
3677 : {
3678 : size_t buflen;
3679 : unsigned char *buffer,
3680 : *sp,
3681 : *bp;
3682 : unsigned int state = 0;
3683 :
3684 : if (strtext == NULL)
3685 : return NULL;
3686 : buflen = strlen(strtext); /* will shrink, also we discover if
3687 : * strtext */
3688 : buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */
3689 : for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
3690 : {
3691 : switch (state)
3692 : {
3693 : case 0:
3694 : if (*sp == '\\')
3695 : state = 1;
3696 : *bp = *sp;
3697 : break;
3698 : case 1:
3699 : if (*sp == '\'') /* state=5 */
3700 : { /* replace \' with 39 */
3701 : bp--;
3702 : *bp = '\'';
3703 : buflen--;
3704 : state = 0;
3705 : }
3706 : else if (*sp == '\\') /* state=6 */
3707 : { /* replace \\ with 92 */
3708 : bp--;
3709 : *bp = '\\';
3710 : buflen--;
3711 : state = 0;
3712 : }
3713 : else
3714 : {
3715 : if (isdigit(*sp))
3716 : state = 2;
3717 : else
3718 : state = 0;
3719 : *bp = *sp;
3720 : }
3721 : break;
3722 : case 2:
3723 : if (isdigit(*sp))
3724 : state = 3;
3725 : else
3726 : state = 0;
3727 : *bp = *sp;
3728 : break;
3729 : case 3:
3730 : if (isdigit(*sp)) /* state=4 */
3731 : {
3732 : unsigned char *start, *end, buf[4]; /* 000 + '\0' */
3733 :
3734 : bp -= 3;
3735 : memcpy(buf, sp-2, 3);
3736 : buf[3] = '\0';
3737 : start = buf;
3738 : *bp = (unsigned char)strtoul(start, (char **)&end, 8);
3739 : buflen -= 3;
3740 : state = 0;
3741 : }
3742 : else
3743 : {
3744 : *bp = *sp;
3745 : state = 0;
3746 : }
3747 : break;
3748 : }
3749 : }
3750 : buffer = erealloc(buffer, buflen+1);
3751 : buffer[buflen] = '\0';
3752 :
3753 : *retbuflen = buflen;
3754 : return buffer;
3755 : }
3756 : #endif
3757 :
3758 : /* {{{ proto string pg_unescape_bytea(string data)
3759 : Unescape binary for bytea type */
3760 : PHP_FUNCTION(pg_unescape_bytea)
3761 3 : {
3762 3 : char *from = NULL, *to = NULL, *tmp = NULL;
3763 : size_t to_len;
3764 : int from_len;
3765 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
3766 : &from, &from_len) == FAILURE) {
3767 0 : return;
3768 : }
3769 :
3770 : #if HAVE_PQUNESCAPEBYTEA
3771 3 : tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
3772 3 : to = estrndup(tmp, to_len);
3773 3 : PQfreemem(tmp);
3774 : #else
3775 : to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
3776 : #endif
3777 3 : if (!to) {
3778 0 : RETURN_FALSE;
3779 : }
3780 3 : RETVAL_STRINGL(to, to_len, 0);
3781 : }
3782 : /* }}} */
3783 : #endif
3784 :
3785 : /* {{{ proto string pg_result_error(resource result)
3786 : Get error message associated with result */
3787 : PHP_FUNCTION(pg_result_error)
3788 5 : {
3789 : zval *result;
3790 : PGresult *pgsql_result;
3791 : pgsql_result_handle *pg_result;
3792 5 : char *err = NULL;
3793 :
3794 5 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
3795 : &result) == FAILURE) {
3796 0 : RETURN_FALSE;
3797 : }
3798 :
3799 5 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
3800 :
3801 5 : pgsql_result = pg_result->result;
3802 5 : if (!pgsql_result) {
3803 0 : RETURN_FALSE;
3804 : }
3805 5 : err = (char *)PQresultErrorMessage(pgsql_result);
3806 5 : RETURN_STRING(err,1);
3807 : }
3808 : /* }}} */
3809 :
3810 : #if HAVE_PQRESULTERRORFIELD
3811 : /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
3812 : Get error message field associated with result */
3813 : PHP_FUNCTION(pg_result_error_field)
3814 12 : {
3815 : zval *result;
3816 : long fieldcode;
3817 : PGresult *pgsql_result;
3818 : pgsql_result_handle *pg_result;
3819 12 : char *field = NULL;
3820 :
3821 12 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl",
3822 : &result, &fieldcode) == FAILURE) {
3823 0 : RETURN_FALSE;
3824 : }
3825 :
3826 12 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
3827 :
3828 12 : pgsql_result = pg_result->result;
3829 12 : if (!pgsql_result) {
3830 0 : RETURN_FALSE;
3831 : }
3832 12 : if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
3833 : |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
3834 : #if PG_DIAG_INTERNAL_POSITION
3835 : |PG_DIAG_INTERNAL_POSITION
3836 : #endif
3837 : #if PG_DIAG_INTERNAL_QUERY
3838 : |PG_DIAG_INTERNAL_QUERY
3839 : #endif
3840 : |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
3841 : |PG_DIAG_SOURCE_FUNCTION)) {
3842 12 : field = (char *)PQresultErrorField(pgsql_result, fieldcode);
3843 12 : if (field == NULL) {
3844 12 : RETURN_NULL();
3845 : } else {
3846 0 : RETURN_STRING(field, 1);
3847 : }
3848 : } else {
3849 0 : RETURN_FALSE;
3850 : }
3851 : }
3852 : /* }}} */
3853 : #endif
3854 :
3855 : /* {{{ proto int pg_connection_status(resource connnection)
3856 : Get connection status */
3857 : PHP_FUNCTION(pg_connection_status)
3858 7 : {
3859 7 : zval *pgsql_link = NULL;
3860 7 : int id = -1;
3861 : PGconn *pgsql;
3862 :
3863 7 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
3864 : &pgsql_link) == FAILURE) {
3865 0 : RETURN_FALSE;
3866 : }
3867 :
3868 7 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3869 :
3870 7 : RETURN_LONG(PQstatus(pgsql));
3871 : }
3872 :
3873 : /* }}} */
3874 :
3875 : #if HAVE_PGTRANSACTIONSTATUS
3876 : /* {{{ proto int pg_transaction_status(resource connnection)
3877 : Get transaction status */
3878 : PHP_FUNCTION(pg_transaction_status)
3879 1 : {
3880 1 : zval *pgsql_link = NULL;
3881 1 : int id = -1;
3882 : PGconn *pgsql;
3883 :
3884 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
3885 : &pgsql_link) == FAILURE) {
3886 0 : RETURN_FALSE;
3887 : }
3888 :
3889 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3890 :
3891 1 : RETURN_LONG(PQtransactionStatus(pgsql));
3892 : }
3893 : #endif
3894 :
3895 : /* }}} */
3896 :
3897 : /* {{{ proto bool pg_connection_reset(resource connection)
3898 : Reset connection (reconnect) */
3899 : PHP_FUNCTION(pg_connection_reset)
3900 1 : {
3901 : zval *pgsql_link;
3902 1 : int id = -1;
3903 : PGconn *pgsql;
3904 :
3905 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
3906 : &pgsql_link) == FAILURE) {
3907 0 : RETURN_FALSE;
3908 : }
3909 :
3910 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3911 :
3912 1 : PQreset(pgsql);
3913 1 : if (PQstatus(pgsql) == CONNECTION_BAD) {
3914 0 : RETURN_FALSE;
3915 : }
3916 1 : RETURN_TRUE;
3917 : }
3918 :
3919 : /* }}} */
3920 :
3921 : #define PHP_PG_ASYNC_IS_BUSY 1
3922 : #define PHP_PG_ASYNC_REQUEST_CANCEL 2
3923 :
3924 : /* {{{ php_pgsql_flush_query
3925 : */
3926 : static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC)
3927 41 : {
3928 : PGresult *res;
3929 41 : int leftover = 0;
3930 :
3931 41 : if (PQ_SETNONBLOCKING(pgsql, 1)) {
3932 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to nonblocking mode");
3933 0 : return -1;
3934 : }
3935 82 : while ((res = PQgetResult(pgsql))) {
3936 0 : PQclear(res);
3937 0 : leftover++;
3938 : }
3939 41 : PQ_SETNONBLOCKING(pgsql, 0);
3940 41 : return leftover;
3941 : }
3942 : /* }}} */
3943 :
3944 : /* {{{ php_pgsql_do_async
3945 : */
3946 : static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
3947 38 : {
3948 : zval *pgsql_link;
3949 38 : int id = -1;
3950 : PGconn *pgsql;
3951 : PGresult *pgsql_result;
3952 :
3953 38 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
3954 : &pgsql_link) == FAILURE) {
3955 0 : RETURN_FALSE;
3956 : }
3957 :
3958 38 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
3959 :
3960 38 : if (PQ_SETNONBLOCKING(pgsql, 1)) {
3961 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
3962 0 : RETURN_FALSE;
3963 : }
3964 38 : switch(entry_type) {
3965 : case PHP_PG_ASYNC_IS_BUSY:
3966 38 : PQconsumeInput(pgsql);
3967 38 : Z_LVAL_P(return_value) = PQisBusy(pgsql);
3968 38 : Z_TYPE_P(return_value) = IS_LONG;
3969 38 : break;
3970 : case PHP_PG_ASYNC_REQUEST_CANCEL:
3971 0 : Z_LVAL_P(return_value) = PQrequestCancel(pgsql);
3972 0 : Z_TYPE_P(return_value) = IS_LONG;
3973 0 : while ((pgsql_result = PQgetResult(pgsql))) {
3974 0 : PQclear(pgsql_result);
3975 : }
3976 0 : break;
3977 : default:
3978 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "PostgreSQL module error, please report this error");
3979 : break;
3980 : }
3981 38 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
3982 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
3983 : }
3984 38 : convert_to_boolean_ex(&return_value);
3985 : }
3986 : /* }}} */
3987 :
3988 : /* {{{ proto bool pg_cancel_query(resource connection)
3989 : Cancel request */
3990 : PHP_FUNCTION(pg_cancel_query)
3991 0 : {
3992 0 : php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
3993 0 : }
3994 : /* }}} */
3995 :
3996 : /* {{{ proto bool pg_connection_busy(resource connection)
3997 : Get connection is busy or not */
3998 : PHP_FUNCTION(pg_connection_busy)
3999 38 : {
4000 38 : php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
4001 38 : }
4002 : /* }}} */
4003 :
4004 : /* {{{ proto bool pg_send_query(resource connection, string query)
4005 : Send asynchronous query */
4006 : PHP_FUNCTION(pg_send_query)
4007 2 : {
4008 : zval *pgsql_link;
4009 : char *query;
4010 : int len;
4011 2 : int id = -1;
4012 : PGconn *pgsql;
4013 : PGresult *res;
4014 2 : int leftover = 0;
4015 :
4016 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
4017 : &pgsql_link, &query, &len) == FAILURE) {
4018 0 : return;
4019 : }
4020 :
4021 2 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4022 :
4023 2 : if (PQ_SETNONBLOCKING(pgsql, 1)) {
4024 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4025 0 : RETURN_FALSE;
4026 : }
4027 4 : while ((res = PQgetResult(pgsql))) {
4028 0 : PQclear(res);
4029 0 : leftover = 1;
4030 : }
4031 2 : if (leftover) {
4032 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4033 : }
4034 2 : if (!PQsendQuery(pgsql, query)) {
4035 0 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4036 0 : PQreset(pgsql);
4037 : }
4038 0 : if (!PQsendQuery(pgsql, query)) {
4039 0 : RETURN_FALSE;
4040 : }
4041 : }
4042 2 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
4043 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4044 : }
4045 2 : RETURN_TRUE;
4046 : }
4047 : /* }}} */
4048 :
4049 : #if HAVE_PQSENDQUERYPARAMS
4050 : /* {{{ proto bool pg_send_query_params(resource connection, string query)
4051 : Send asynchronous parameterized query */
4052 : PHP_FUNCTION(pg_send_query_params)
4053 2 : {
4054 : zval **pgsql_link;
4055 : zval **pv_param_arr, **tmp;
4056 2 : int num_params = 0;
4057 2 : char **params = NULL;
4058 : zval **query;
4059 2 : int id = -1;
4060 : PGconn *pgsql;
4061 : PGresult *res;
4062 2 : int leftover = 0;
4063 :
4064 2 : if (zend_get_parameters_ex(3, &pgsql_link, &query, &pv_param_arr) == FAILURE) {
4065 0 : WRONG_PARAM_COUNT;
4066 : }
4067 :
4068 2 : if (pgsql_link == NULL && id == -1) {
4069 0 : RETURN_FALSE;
4070 : }
4071 :
4072 2 : if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) {
4073 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed");
4074 0 : RETURN_FALSE;
4075 : }
4076 :
4077 2 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4078 :
4079 2 : convert_to_string_ex(query);
4080 2 : if (PQ_SETNONBLOCKING(pgsql, 1)) {
4081 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4082 0 : RETURN_FALSE;
4083 : }
4084 4 : while ((res = PQgetResult(pgsql))) {
4085 0 : PQclear(res);
4086 0 : leftover = 1;
4087 : }
4088 2 : if (leftover) {
4089 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4090 : }
4091 :
4092 2 : SEPARATE_ZVAL(pv_param_arr);
4093 2 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr));
4094 2 : num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr));
4095 2 : if (num_params > 0) {
4096 2 : int i = 0;
4097 2 : params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4098 :
4099 5 : for(i = 0; i < num_params; i++) {
4100 3 : if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) {
4101 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
4102 0 : _php_pgsql_free_params(params, num_params);
4103 0 : RETURN_FALSE;
4104 : }
4105 :
4106 3 : if (Z_TYPE_PP(tmp) == IS_NULL) {
4107 0 : params[i] = NULL;
4108 : } else {
4109 3 : zval tmp_val = **tmp;
4110 3 : zval_copy_ctor(&tmp_val);
4111 3 : convert_to_string(&tmp_val);
4112 3 : if (Z_TYPE(tmp_val) != IS_STRING) {
4113 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
4114 0 : zval_dtor(&tmp_val);
4115 0 : _php_pgsql_free_params(params, num_params);
4116 0 : RETURN_FALSE;
4117 : }
4118 3 : params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
4119 3 : zval_dtor(&tmp_val);
4120 : }
4121 :
4122 3 : zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr));
4123 : }
4124 : }
4125 :
4126 2 : if (!PQsendQueryParams(pgsql, Z_STRVAL_PP(query), num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
4127 0 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4128 0 : PQreset(pgsql);
4129 : }
4130 0 : if (!PQsendQueryParams(pgsql, Z_STRVAL_PP(query), num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
4131 0 : _php_pgsql_free_params(params, num_params);
4132 0 : RETURN_FALSE;
4133 : }
4134 : }
4135 2 : _php_pgsql_free_params(params, num_params);
4136 2 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
4137 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4138 : }
4139 2 : RETURN_TRUE;
4140 : }
4141 : /* }}} */
4142 : #endif
4143 :
4144 : #if HAVE_PQSENDPREPARE
4145 : /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
4146 : Asynchronously prepare a query for future execution */
4147 : PHP_FUNCTION(pg_send_prepare)
4148 2 : {
4149 : zval **pgsql_link;
4150 : zval **query, **stmtname;
4151 2 : int id = -1;
4152 : PGconn *pgsql;
4153 : PGresult *res;
4154 2 : int leftover = 0;
4155 :
4156 2 : if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &query) == FAILURE) {
4157 0 : WRONG_PARAM_COUNT;
4158 : }
4159 2 : if (pgsql_link == NULL && id == -1) {
4160 0 : RETURN_FALSE;
4161 : }
4162 :
4163 2 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4164 :
4165 2 : convert_to_string_ex(stmtname);
4166 2 : convert_to_string_ex(query);
4167 2 : if (PQ_SETNONBLOCKING(pgsql, 1)) {
4168 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4169 0 : RETURN_FALSE;
4170 : }
4171 4 : while ((res = PQgetResult(pgsql))) {
4172 0 : PQclear(res);
4173 0 : leftover = 1;
4174 : }
4175 2 : if (leftover) {
4176 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4177 : }
4178 2 : if (!PQsendPrepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL)) {
4179 0 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4180 0 : PQreset(pgsql);
4181 : }
4182 0 : if (!PQsendPrepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL)) {
4183 0 : RETURN_FALSE;
4184 : }
4185 : }
4186 2 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
4187 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4188 : }
4189 2 : RETURN_TRUE;
4190 : }
4191 : /* }}} */
4192 : #endif
4193 :
4194 : #if HAVE_PQSENDQUERYPREPARED
4195 : /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
4196 : Executes prevriously prepared stmtname asynchronously */
4197 : PHP_FUNCTION(pg_send_execute)
4198 2 : {
4199 : zval **pgsql_link;
4200 : zval **pv_param_arr, **tmp;
4201 2 : int num_params = 0;
4202 2 : char **params = NULL;
4203 : zval **stmtname;
4204 2 : int id = -1;
4205 : PGconn *pgsql;
4206 : PGresult *res;
4207 2 : int leftover = 0;
4208 :
4209 2 : if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &pv_param_arr)==FAILURE) {
4210 0 : WRONG_PARAM_COUNT;
4211 : }
4212 2 : if (pgsql_link == NULL && id == -1) {
4213 0 : RETURN_FALSE;
4214 : }
4215 :
4216 2 : if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) {
4217 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed");
4218 0 : RETURN_FALSE;
4219 : }
4220 :
4221 2 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4222 :
4223 2 : convert_to_string_ex(stmtname);
4224 2 : if (PQ_SETNONBLOCKING(pgsql, 1)) {
4225 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4226 0 : RETURN_FALSE;
4227 : }
4228 4 : while ((res = PQgetResult(pgsql))) {
4229 0 : PQclear(res);
4230 0 : leftover = 1;
4231 : }
4232 2 : if (leftover) {
4233 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4234 : }
4235 :
4236 2 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr));
4237 2 : num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr));
4238 2 : if (num_params > 0) {
4239 2 : int i = 0;
4240 2 : params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4241 :
4242 5 : for(i = 0; i < num_params; i++) {
4243 3 : if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) {
4244 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
4245 0 : _php_pgsql_free_params(params, num_params);
4246 0 : RETURN_FALSE;
4247 : }
4248 :
4249 3 : if (Z_TYPE_PP(tmp) == IS_NULL) {
4250 0 : params[i] = NULL;
4251 : } else {
4252 3 : zval tmp_val = **tmp;
4253 3 : zval_copy_ctor(&tmp_val);
4254 3 : convert_to_string(&tmp_val);
4255 3 : if (Z_TYPE(tmp_val) != IS_STRING) {
4256 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
4257 0 : zval_dtor(&tmp_val);
4258 0 : _php_pgsql_free_params(params, num_params);
4259 0 : RETURN_FALSE;
4260 : }
4261 3 : params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
4262 3 : zval_dtor(&tmp_val);
4263 : }
4264 :
4265 3 : zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr));
4266 : }
4267 : }
4268 :
4269 2 : if (!PQsendQueryPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params, (const char * const *)params, NULL, NULL, 0)) {
4270 0 : if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4271 0 : PQreset(pgsql);
4272 : }
4273 0 : if (!PQsendQueryPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params, (const char * const *)params, NULL, NULL, 0)) {
4274 0 : _php_pgsql_free_params(params, num_params);
4275 0 : RETURN_FALSE;
4276 : }
4277 : }
4278 2 : _php_pgsql_free_params(params, num_params);
4279 2 : if (PQ_SETNONBLOCKING(pgsql, 0)) {
4280 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4281 : }
4282 2 : RETURN_TRUE;
4283 : }
4284 : /* }}} */
4285 : #endif
4286 :
4287 : /* {{{ proto resource pg_get_result(resource connection)
4288 : Get asynchronous query result */
4289 : PHP_FUNCTION(pg_get_result)
4290 6 : {
4291 : zval *pgsql_link;
4292 6 : int id = -1;
4293 : PGconn *pgsql;
4294 : PGresult *pgsql_result;
4295 : pgsql_result_handle *pg_result;
4296 :
4297 6 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4298 : &pgsql_link) == FAILURE) {
4299 0 : RETURN_FALSE;
4300 : }
4301 :
4302 6 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4303 :
4304 6 : pgsql_result = PQgetResult(pgsql);
4305 6 : if (!pgsql_result) {
4306 : /* no result */
4307 0 : RETURN_FALSE;
4308 : }
4309 6 : pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
4310 6 : pg_result->conn = pgsql;
4311 6 : pg_result->result = pgsql_result;
4312 6 : pg_result->row = 0;
4313 6 : ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
4314 : }
4315 : /* }}} */
4316 :
4317 : /* {{{ proto mixed pg_result_status(resource result[, long result_type])
4318 : Get status of query result */
4319 : PHP_FUNCTION(pg_result_status)
4320 2 : {
4321 : zval *result;
4322 2 : long result_type = PGSQL_STATUS_LONG;
4323 : ExecStatusType status;
4324 : PGresult *pgsql_result;
4325 : pgsql_result_handle *pg_result;
4326 :
4327 2 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
4328 : &result, &result_type) == FAILURE) {
4329 0 : RETURN_FALSE;
4330 : }
4331 :
4332 2 : ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
4333 :
4334 2 : pgsql_result = pg_result->result;
4335 2 : if (result_type == PGSQL_STATUS_LONG) {
4336 1 : status = PQresultStatus(pgsql_result);
4337 1 : RETURN_LONG((int)status);
4338 : }
4339 1 : else if (result_type == PGSQL_STATUS_STRING) {
4340 1 : RETURN_STRING(PQcmdStatus(pgsql_result), 1);
4341 : }
4342 : else {
4343 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
4344 0 : RETURN_FALSE;
4345 : }
4346 : }
4347 : /* }}} */
4348 :
4349 :
4350 : /* {{{ proto array pg_get_notify([resource connection[, result_type]])
4351 : Get asynchronous notification */
4352 : PHP_FUNCTION(pg_get_notify)
4353 1 : {
4354 : zval *pgsql_link;
4355 1 : int id = -1;
4356 1 : long result_type = PGSQL_ASSOC;
4357 : PGconn *pgsql;
4358 : PGnotify *pgsql_notify;
4359 :
4360 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
4361 : &pgsql_link, &result_type) == FAILURE) {
4362 0 : RETURN_FALSE;
4363 : }
4364 :
4365 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4366 :
4367 1 : if (!(result_type & PGSQL_BOTH)) {
4368 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
4369 0 : RETURN_FALSE;
4370 : }
4371 :
4372 1 : PQconsumeInput(pgsql);
4373 1 : pgsql_notify = PQnotifies(pgsql);
4374 1 : if (!pgsql_notify) {
4375 : /* no notify message */
4376 0 : RETURN_FALSE;
4377 : }
4378 1 : array_init(return_value);
4379 1 : if (result_type & PGSQL_NUM) {
4380 0 : add_index_string(return_value, 0, pgsql_notify->relname, 1);
4381 0 : add_index_long(return_value, 1, pgsql_notify->be_pid);
4382 : }
4383 1 : if (result_type & PGSQL_ASSOC) {
4384 1 : add_assoc_string(return_value, "message", pgsql_notify->relname, 1);
4385 1 : add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
4386 : }
4387 1 : PQfreemem(pgsql_notify);
4388 : }
4389 : /* }}} */
4390 :
4391 : /* {{{ proto int pg_get_pid([resource connection)
4392 : Get backend(server) pid */
4393 : PHP_FUNCTION(pg_get_pid)
4394 1 : {
4395 : zval *pgsql_link;
4396 1 : int id = -1;
4397 : PGconn *pgsql;
4398 :
4399 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4400 : &pgsql_link) == FAILURE) {
4401 0 : RETURN_FALSE;
4402 : }
4403 :
4404 1 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4405 :
4406 1 : RETURN_LONG(PQbackendPID(pgsql));
4407 : }
4408 : /* }}} */
4409 :
4410 : /* {{{ php_pgsql_meta_data
4411 : * TODO: Add meta_data cache for better performance
4412 : */
4413 : PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC)
4414 50 : {
4415 : PGresult *pg_result;
4416 50 : char *src, *tmp_name, *tmp_name2 = NULL;
4417 50 : smart_str querystr = {0};
4418 : int new_len;
4419 : int i, num_rows;
4420 : zval *elem;
4421 :
4422 50 : if (!*table_name) {
4423 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
4424 0 : return FAILURE;
4425 : }
4426 :
4427 50 : src = estrdup(table_name);
4428 50 : tmp_name = php_strtok_r(src, ".", &tmp_name2);
4429 :
4430 50 : if (!tmp_name2 || !*tmp_name2) {
4431 : /* Default schema */
4432 31 : tmp_name2 = tmp_name;
4433 31 : tmp_name = "public";
4434 : }
4435 :
4436 50 : smart_str_appends(&querystr,
4437 : "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims "
4438 : "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
4439 : "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '");
4440 50 : tmp_name2 = php_addslashes(tmp_name2, strlen(tmp_name2), &new_len, 0 TSRMLS_CC);
4441 50 : smart_str_appendl(&querystr, tmp_name2, new_len);
4442 :
4443 50 : smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '");
4444 50 : tmp_name = php_addslashes(tmp_name, strlen(tmp_name), &new_len, 0 TSRMLS_CC);
4445 50 : smart_str_appendl(&querystr, tmp_name, new_len);
4446 :
4447 50 : smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;");
4448 50 : smart_str_0(&querystr);
4449 :
4450 50 : efree(tmp_name2);
4451 50 : efree(tmp_name);
4452 50 : efree(src);
4453 :
4454 50 : pg_result = PQexec(pg_link, querystr.c);
4455 50 : if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
4456 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name);
4457 4 : smart_str_free(&querystr);
4458 4 : PQclear(pg_result);
4459 4 : return FAILURE;
4460 : }
4461 46 : smart_str_free(&querystr);
4462 :
4463 149 : for (i = 0; i < num_rows; i++) {
4464 : char *name;
4465 103 : MAKE_STD_ZVAL(elem);
4466 103 : array_init(elem);
4467 103 : add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
4468 103 : add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
4469 103 : add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
4470 103 : if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
4471 6 : add_assoc_bool(elem, "not null", 1);
4472 : }
4473 : else {
4474 97 : add_assoc_bool(elem, "not null", 0);
4475 : }
4476 103 : if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
4477 3 : add_assoc_bool(elem, "has default", 1);
4478 : }
4479 : else {
4480 100 : add_assoc_bool(elem, "has default", 0);
4481 : }
4482 103 : add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
4483 103 : name = PQgetvalue(pg_result,i,0);
4484 103 : add_assoc_zval(meta, name, elem);
4485 : }
4486 46 : PQclear(pg_result);
4487 :
4488 46 : return SUCCESS;
4489 : }
4490 :
4491 : /* }}} */
4492 :
4493 :
4494 : /* {{{ proto array pg_meta_data(resource db, string table)
4495 : Get meta_data */
4496 : PHP_FUNCTION(pg_meta_data)
4497 3 : {
4498 : zval *pgsql_link;
4499 : char *table_name;
4500 : uint table_name_len;
4501 : PGconn *pgsql;
4502 3 : int id = -1;
4503 :
4504 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
4505 : &pgsql_link, &table_name, &table_name_len) == FAILURE) {
4506 0 : return;
4507 : }
4508 :
4509 3 : ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4510 :
4511 3 : array_init(return_value);
4512 3 : if (php_pgsql_meta_data(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
4513 0 : zval_dtor(return_value); /* destroy array */
4514 0 : RETURN_FALSE;
4515 : }
4516 : }
4517 : /* }}} */
4518 :
4519 : /* {{{ php_pgsql_get_data_type
4520 : */
4521 : static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
4522 70 : {
4523 : /* This is stupid way to do. I'll fix it when I decied how to support
4524 : user defined types. (Yasuo) */
4525 :
4526 : /* boolean */
4527 70 : if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
4528 0 : return PG_BOOL;
4529 : /* object id */
4530 70 : if (!strcmp(type_name, "oid"))
4531 0 : return PG_OID;
4532 : /* integer */
4533 70 : if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
4534 0 : return PG_INT2;
4535 70 : if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
4536 58 : return PG_INT4;
4537 12 : if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
4538 0 : return PG_INT8;
4539 : /* real and other */
4540 12 : if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
4541 0 : return PG_FLOAT4;
4542 12 : if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
4543 0 : return PG_FLOAT8;
4544 12 : if (!strcmp(type_name, "numeric"))
4545 0 : return PG_NUMERIC;
4546 12 : if (!strcmp(type_name, "money"))
4547 0 : return PG_MONEY;
4548 : /* character */
4549 12 : if (!strcmp(type_name, "text"))
4550 5 : return PG_TEXT;
4551 7 : if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
4552 0 : return PG_CHAR;
4553 7 : if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
4554 0 : return PG_VARCHAR;
4555 : /* time and interval */
4556 7 : if (!strcmp(type_name, "abstime"))
4557 0 : return PG_UNIX_TIME;
4558 7 : if (!strcmp(type_name, "reltime"))
4559 0 : return PG_UNIX_TIME_INTERVAL;
4560 7 : if (!strcmp(type_name, "tinterval"))
4561 0 : return PG_UNIX_TIME_INTERVAL;
4562 7 : if (!strcmp(type_name, "date"))
4563 0 : return PG_DATE;
4564 7 : if (!strcmp(type_name, "time"))
4565 0 : return PG_TIME;
4566 7 : if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
4567 0 : return PG_TIME_WITH_TIMEZONE;
4568 7 : if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
4569 2 : return PG_TIMESTAMP;
4570 5 : if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
4571 0 : return PG_TIMESTAMP_WITH_TIMEZONE;
4572 5 : if (!strcmp(type_name, "interval"))
4573 0 : return PG_INTERVAL;
4574 : /* binary */
4575 5 : if (!strcmp(type_name, "bytea"))
4576 5 : return PG_BYTEA;
4577 : /* network */
4578 0 : if (!strcmp(type_name, "cidr"))
4579 0 : return PG_CIDR;
4580 0 : if (!strcmp(type_name, "inet"))
4581 0 : return PG_INET;
4582 0 : if (!strcmp(type_name, "macaddr"))
4583 0 : return PG_MACADDR;
4584 : /* bit */
4585 0 : if (!strcmp(type_name, "bit"))
4586 0 : return PG_BIT;
4587 0 : if (!strcmp(type_name, "bit varying"))
4588 0 : return PG_VARBIT;
4589 : /* geometric */
4590 0 : if (!strcmp(type_name, "line"))
4591 0 : return PG_LINE;
4592 0 : if (!strcmp(type_name, "lseg"))
4593 0 : return PG_LSEG;
4594 0 : if (!strcmp(type_name, "box"))
4595 0 : return PG_BOX;
4596 0 : if (!strcmp(type_name, "path"))
4597 0 : return PG_PATH;
4598 0 : if (!strcmp(type_name, "point"))
4599 0 : return PG_POINT;
4600 0 : if (!strcmp(type_name, "polygon"))
4601 0 : return PG_POLYGON;
4602 0 : if (!strcmp(type_name, "circle"))
4603 0 : return PG_CIRCLE;
4604 :
4605 0 : return PG_UNKNOWN;
4606 : }
4607 : /* }}} */
4608 :
4609 : /* {{{ php_pgsql_convert_match
4610 : * test field value with regular expression specified.
4611 : */
4612 : static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC)
4613 10 : {
4614 : regex_t re;
4615 : regmatch_t *subs;
4616 10 : int regopt = REG_EXTENDED;
4617 10 : int regerr, ret = SUCCESS;
4618 :
4619 10 : if (icase) {
4620 0 : regopt |= REG_ICASE;
4621 : }
4622 :
4623 10 : regerr = regcomp(&re, regex, regopt);
4624 10 : if (regerr) {
4625 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex");
4626 0 : regfree(&re);
4627 0 : return FAILURE;
4628 : }
4629 10 : subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
4630 :
4631 10 : regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
4632 10 : if (regerr == REG_NOMATCH) {
4633 : #ifdef PHP_DEBUG
4634 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "'%s' does not match with '%s'", str, regex);
4635 : #endif
4636 0 : ret = FAILURE;
4637 : }
4638 10 : else if (regerr) {
4639 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex");
4640 0 : ret = FAILURE;
4641 : }
4642 10 : regfree(&re);
4643 10 : efree(subs);
4644 10 : return ret;
4645 : }
4646 :
4647 : /* }}} */
4648 :
4649 : /* {{{ php_pgsql_add_quote
4650 : * add quotes around string.
4651 : */
4652 : static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
4653 10 : {
4654 10 : smart_str str = {0};
4655 :
4656 : assert(Z_TYPE_P(src) == IS_STRING);
4657 : assert(should_free == 1 || should_free == 0);
4658 :
4659 10 : smart_str_appendc(&str, '\'');
4660 10 : smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
4661 10 : smart_str_appendc(&str, '\'');
4662 10 : smart_str_0(&str);
4663 :
4664 10 : if (should_free) {
4665 10 : efree(Z_STRVAL_P(src));
4666 : }
4667 10 : Z_STRVAL_P(src) = str.c;
4668 10 : Z_STRLEN_P(src) = str.len;
4669 :
4670 10 : return SUCCESS;
4671 : }
4672 : /* }}} */
4673 :
4674 : #define PGSQL_CONV_CHECK_IGNORE() \
4675 : if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \
4676 : /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
4677 : if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \
4678 : zval_dtor(new_val); \
4679 : FREE_ZVAL(new_val); \
4680 : skip_field = 1; \
4681 : } \
4682 : /* raise error if it's not null and cannot be ignored */ \
4683 : else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \
4684 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \
4685 : err = 1; \
4686 : } \
4687 : }
4688 :
4689 : /* {{{ php_pgsql_convert
4690 : * check and convert array values (fieldname=>vlaue pair) for sql
4691 : */
4692 : PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC)
4693 47 : {
4694 : HashPosition pos;
4695 47 : char *field = NULL;
4696 47 : uint field_len = -1;
4697 47 : ulong num_idx = -1;
4698 : zval *meta, **def, **type, **not_null, **has_default, **val, *new_val;
4699 47 : int new_len, key_type, err = 0, skip_field;
4700 :
4701 : assert(pg_link != NULL);
4702 : assert(Z_TYPE_P(values) == IS_ARRAY);
4703 : assert(Z_TYPE_P(result) == IS_ARRAY);
4704 : assert(!(opt & ~PGSQL_CONV_OPTS));
4705 :
4706 47 : if (!table_name) {
4707 0 : return FAILURE;
4708 : }
4709 47 : MAKE_STD_ZVAL(meta);
4710 47 : array_init(meta);
4711 47 : if (php_pgsql_meta_data(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
4712 4 : zval_dtor(meta);
4713 4 : FREE_ZVAL(meta);
4714 4 : return FAILURE;
4715 : }
4716 43 : for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
4717 156 : zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
4718 70 : zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
4719 71 : skip_field = 0;
4720 71 : new_val = NULL;
4721 :
4722 71 : if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTANT) {
4723 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type");
4724 0 : err = 1;
4725 : }
4726 71 : if (!err && key_type == HASH_KEY_IS_LONG) {
4727 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
4728 0 : err = 1;
4729 : }
4730 71 : if (!err && key_type == HASH_KEY_NON_EXISTANT) {
4731 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
4732 0 : err = 1;
4733 : }
4734 71 : if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
4735 1 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field);
4736 1 : err = 1;
4737 : }
4738 71 : if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) {
4739 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'");
4740 0 : err = 1;
4741 : }
4742 71 : if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)¬_null) == FAILURE) {
4743 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'&qu |