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