2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
19 #include <ext/spl/spl_iterators.h>
20 #if PHP_PQ_HAVE_PHP_JSON_H
21 #include <php_json.h> /* we've added the include directory to INCLUDES */
24 #include <libpq-events.h>
27 #include "php_pq_misc.h"
28 #include "php_pq_object.h"
29 #include "php_pqexc.h"
30 #include "php_pqres.h"
32 #include "php_pq_type.h"
34 zend_class_entry
*php_pqres_class_entry
;
35 static zend_object_handlers php_pqres_object_handlers
;
36 static HashTable php_pqres_object_prophandlers
;
37 static zend_object_iterator_funcs php_pqres_iterator_funcs
;
39 static zend_object_iterator
*php_pqres_iterator_init(zend_class_entry
*ce
, zval
*object
, int by_ref
)
41 php_pqres_iterator_t
*iter
;
42 zval tmp
, *zfetch_type
;
44 iter
= ecalloc(1, sizeof(*iter
));
45 iter
->zi
.funcs
= &php_pqres_iterator_funcs
;
46 ZVAL_COPY(&iter
->zi
.data
, object
);
48 zend_iterator_init(&iter
->zi
);
50 zfetch_type
= zend_read_property(ce
, object
, ZEND_STRL("fetchType"), 0, &tmp
);
51 iter
->fetch_type
= zval_get_long(zfetch_type
);
53 fprintf(stderr
, "INIT iter(#%d) %p res(#%d) %p\n", iter
->zi
.std
.handle
, iter
, Z_OBJ_HANDLE_P(object
), PHP_PQ_OBJ(object
, NULL
));
55 return (zend_object_iterator
*) iter
;
58 static void php_pqres_internal_iterator_init(zval
*zobj
)
60 php_pqres_object_t
*obj
= PHP_PQ_OBJ(zobj
, NULL
);
62 obj
->intern
->iter
= (php_pqres_iterator_t
*) php_pqres_iterator_init(Z_OBJCE_P(zobj
), zobj
, 0);
63 /* prevent cyclic dep */
65 obj
->intern
->iter
->zi
.funcs
->rewind((zend_object_iterator
*) obj
->intern
->iter
);
69 static void php_pqres_iterator_dtor(zend_object_iterator
*i
)
71 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
74 fprintf(stderr
, "FREE iter(#%d) %p\n", iter
->zi
.std
.handle
, iter
);
76 if (!Z_ISUNDEF(iter
->current_val
)) {
77 zval_ptr_dtor(&iter
->current_val
);
78 ZVAL_UNDEF(&iter
->current_val
);
80 zval_ptr_dtor(&i
->data
);
81 zend_iterator_dtor(i
);
84 static ZEND_RESULT_CODE
php_pqres_iterator_valid(zend_object_iterator
*i
)
86 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
87 php_pqres_object_t
*obj
= PHP_PQ_OBJ(&i
->data
, NULL
);
89 switch (PQresultStatus(obj
->intern
->res
)) {
91 #ifdef HAVE_PGRES_SINGLE_TUPLE
92 case PGRES_SINGLE_TUPLE
:
94 if (PQntuples(obj
->intern
->res
) <= iter
->index
) {
105 #define PHP_PQRES_JSON_OPTIONS(res) \
106 (php_pqres_fetch_type(res) != PHP_PQRES_FETCH_OBJECT ? PHP_JSON_OBJECT_AS_ARRAY:0)
108 zval
*php_pqres_typed_zval(php_pqres_t
*res
, Oid typ
, zval
*zv
)
114 if ((zconv
= zend_hash_index_find(&res
->converters
, typ
))) {
118 ZVAL_LONG(&ztype
, typ
);
119 zend_call_method_with_2_params(zconv
, NULL
, NULL
, "convertfromstring", &rv
, zv
, &ztype
);
122 ZVAL_ZVAL(zv
, &rv
, 0, 0);
127 str
= zval_get_string(zv
);
131 case PHP_PQ_OID_BOOL
:
132 if (!(res
->auto_convert
& PHP_PQRES_CONV_BOOL
)) {
135 ZVAL_BOOL(zv
, *str
->val
== 't');
138 case PHP_PQ_OID_INT8
:
140 case PHP_PQ_OID_INT4
:
141 case PHP_PQ_OID_INT2
:
144 if (!(res
->auto_convert
& PHP_PQRES_CONV_INT
)) {
151 switch (is_numeric_str_function(str
, &lval
, &dval
)) {
156 ZVAL_DOUBLE(zv
, dval
);
164 case PHP_PQ_OID_FLOAT4
:
165 case PHP_PQ_OID_FLOAT8
:
166 if (!(res
->auto_convert
& PHP_PQRES_CONV_FLOAT
)) {
169 ZVAL_DOUBLE(zv
, zend_strtod(str
->val
, NULL
));
172 case PHP_PQ_OID_DATE
:
173 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
176 php_pqdt_from_string(zv
, NULL
, str
->val
, str
->len
, "Y-m-d", NULL
);
179 case PHP_PQ_OID_ABSTIME
:
180 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
183 php_pqdt_from_string(zv
, NULL
, str
->val
, str
->len
, "Y-m-d H:i:s", NULL
);
186 case PHP_PQ_OID_TIMESTAMP
:
187 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
190 php_pqdt_from_string(zv
, NULL
, str
->val
, str
->len
, "Y-m-d H:i:s.u", NULL
);
193 case PHP_PQ_OID_TIMESTAMPTZ
:
194 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
197 php_pqdt_from_string(zv
, NULL
, str
->val
, str
->len
, "Y-m-d H:i:s.uO", NULL
);
200 #if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
201 # ifdef PHP_PQ_OID_JSONB
202 case PHP_PQ_OID_JSONB
:
204 case PHP_PQ_OID_JSON
:
205 if (!(res
->auto_convert
& PHP_PQRES_CONV_JSON
)) {
208 php_json_decode_ex(zv
, str
->val
, str
->len
, PHP_PQRES_JSON_OPTIONS(res
), 512 /* PHP_JSON_DEFAULT_DEPTH */);
213 if (!(res
->auto_convert
& PHP_PQRES_CONV_ARRAY
)) {
216 if (PHP_PQ_TYPE_IS_ARRAY(typ
) && (ht
= php_pq_parse_array(res
, str
->val
, str
->len
, PHP_PQ_TYPE_OF_ARRAY(typ
)))) {
224 zend_string_release(str
);
232 static inline zval
*php_pqres_get_col(php_pqres_t
*r
, unsigned row
, unsigned col
, zval
*zv
)
234 if (PQgetisnull(r
->res
, row
, col
)) {
237 ZVAL_STRINGL(zv
, PQgetvalue(r
->res
, row
, col
), PQgetlength(r
->res
, row
, col
));
238 zv
= php_pqres_typed_zval(r
, PQftype(r
->res
, col
), zv
);
244 static inline void php_pqres_add_col_to_zval(php_pqres_t
*r
, unsigned row
, unsigned col
, php_pqres_fetch_t fetch_type
, zval
*data
)
246 if (PQgetisnull(r
->res
, row
, col
)) {
247 switch (fetch_type
) {
248 case PHP_PQRES_FETCH_OBJECT
:
249 add_property_null(data
, PQfname(r
->res
, col
));
252 case PHP_PQRES_FETCH_ASSOC
:
253 add_assoc_null(data
, PQfname(r
->res
, col
));
256 case PHP_PQRES_FETCH_ARRAY
:
257 add_index_null(data
, col
);
263 ZVAL_STRINGL(&zv
, PQgetvalue(r
->res
, row
, col
), PQgetlength(r
->res
, row
, col
));
264 php_pqres_typed_zval(r
, PQftype(r
->res
, col
), &zv
);
266 switch (fetch_type
) {
267 case PHP_PQRES_FETCH_OBJECT
:
268 add_property_zval(data
, PQfname(r
->res
, col
), &zv
);
272 case PHP_PQRES_FETCH_ASSOC
:
273 add_assoc_zval(data
, PQfname(r
->res
, col
), &zv
);
276 case PHP_PQRES_FETCH_ARRAY
:
277 add_index_zval(data
, col
, &zv
);
283 zval
*php_pqres_row_to_zval(PGresult
*res
, unsigned row
, php_pqres_fetch_t fetch_type
, zval
*data
)
285 int c
, cols
= PQnfields(res
);
286 php_pqres_object_t
*res_obj
= PQresultInstanceData(res
, php_pqconn_event
);
288 if (Z_TYPE_P(data
) != IS_OBJECT
&& Z_TYPE_P(data
) != IS_ARRAY
) {
289 if (PHP_PQRES_FETCH_OBJECT
== fetch_type
) {
292 array_init_size(data
, cols
);
296 if (PQntuples(res
) > row
) {
297 for (c
= 0; c
< cols
; ++c
) {
298 php_pqres_add_col_to_zval(res_obj
->intern
, row
, c
, fetch_type
, data
);
305 static zval
*php_pqres_iterator_current(zend_object_iterator
*i
)
307 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
308 php_pqres_object_t
*obj
= PHP_PQ_OBJ(&i
->data
, NULL
);
310 if (Z_ISUNDEF(iter
->current_val
)) {
311 php_pqres_row_to_zval(obj
->intern
->res
, iter
->index
, iter
->fetch_type
, &iter
->current_val
);
313 return &iter
->current_val
;
316 static void php_pqres_iterator_key(zend_object_iterator
*i
, zval
*key
)
318 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
320 ZVAL_LONG(key
, iter
->index
);
323 static void php_pqres_iterator_invalidate(zend_object_iterator
*i
)
325 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
327 if (!Z_ISUNDEF(iter
->current_val
)) {
328 zval_ptr_dtor(&iter
->current_val
);
329 ZVAL_UNDEF(&iter
->current_val
);
333 static void php_pqres_iterator_next(zend_object_iterator
*i
)
335 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
337 php_pqres_iterator_invalidate(i
);
341 static void php_pqres_iterator_rewind(zend_object_iterator
*i
)
343 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
345 php_pqres_iterator_invalidate(i
);
349 static zend_object_iterator_funcs php_pqres_iterator_funcs
= {
350 php_pqres_iterator_dtor
,
351 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
352 php_pqres_iterator_valid
,
353 /* fetch the item data for the current element */
354 php_pqres_iterator_current
,
355 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
356 php_pqres_iterator_key
,
357 /* step forwards to next element */
358 php_pqres_iterator_next
,
359 /* rewind to start of data (optional, may be NULL) */
360 php_pqres_iterator_rewind
,
361 /* invalidate current value/key (optional, may be NULL) */
362 php_pqres_iterator_invalidate
365 static ZEND_RESULT_CODE
php_pqres_count_elements(zval
*object
, long *count
)
367 php_pqres_object_t
*obj
= PHP_PQ_OBJ(object
, NULL
);
372 *count
= (long) PQntuples(obj
->intern
->res
);
377 ZEND_RESULT_CODE
php_pqres_success(PGresult
*res TSRMLS_DC
)
381 switch (PQresultStatus(res
)) {
382 case PGRES_BAD_RESPONSE
:
383 case PGRES_NONFATAL_ERROR
:
384 case PGRES_FATAL_ERROR
:
385 ZVAL_OBJ(&zexc
, throw_exce(EX_SQL
, "%s", PHP_PQresultErrorMessage(res
)));
386 zend_update_property_string(Z_OBJCE(zexc
), &zexc
, ZEND_STRL("sqlstate"), PQresultErrorField(res
, PG_DIAG_SQLSTATE
));
393 php_pqres_object_t
*php_pqres_init_instance_data(PGresult
*res
, php_pqconn_object_t
*conn_obj
)
395 php_pqres_object_t
*obj
;
396 php_pqres_t
*r
= ecalloc(1, sizeof(*r
));
399 zend_hash_init(&r
->bound
, 0, 0, ZVAL_PTR_DTOR
, 0);
400 zend_hash_init(&r
->converters
, zend_hash_num_elements(&conn_obj
->intern
->converters
), 0, ZVAL_PTR_DTOR
, 0);
401 zend_hash_copy(&r
->converters
, &conn_obj
->intern
->converters
, (copy_ctor_func_t
) zval_add_ref
);
403 r
->auto_convert
= conn_obj
->intern
->default_auto_convert
;
404 r
->default_fetch_type
= conn_obj
->intern
->default_fetch_type
;
406 obj
= php_pqres_create_object_ex(php_pqres_class_entry
, r
);
407 PQresultSetInstanceData(res
, php_pqconn_event
, obj
);
412 php_pqres_fetch_t
php_pqres_fetch_type(php_pqres_t
*res
)
414 return res
->iter
? res
->iter
->fetch_type
: res
->default_fetch_type
;
417 static void php_pqres_object_free(zend_object
*o
)
419 php_pqres_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
422 if (obj
->intern
->res
) {
423 PQresultSetInstanceData(obj
->intern
->res
, php_pqconn_event
, NULL
);
424 PQclear(obj
->intern
->res
);
425 obj
->intern
->res
= NULL
;
428 if (obj
->intern
->iter
) {
429 ZVAL_NULL(&obj
->intern
->iter
->zi
.data
);
430 php_pqres_iterator_dtor((zend_object_iterator
*) obj
->intern
->iter
);
431 obj
->intern
->iter
= NULL
;
434 zend_hash_destroy(&obj
->intern
->bound
);
435 zend_hash_destroy(&obj
->intern
->converters
);
440 php_pq_object_dtor(o
);
443 php_pqres_object_t
*php_pqres_create_object_ex(zend_class_entry
*ce
, php_pqres_t
*intern
)
445 return php_pq_object_create(ce
, intern
, sizeof(php_pqres_object_t
),
446 &php_pqres_object_handlers
, &php_pqres_object_prophandlers
);
449 static zend_object
*php_pqres_create_object(zend_class_entry
*class_type
)
451 return &php_pqres_create_object_ex(class_type
, NULL
)->zo
;
454 static void php_pqres_object_read_status(zval
*object
, void *o
, zval
*return_value
)
456 php_pqres_object_t
*obj
= o
;
458 RETVAL_LONG(PQresultStatus(obj
->intern
->res
));
461 static void php_pqres_object_read_status_message(zval
*object
, void *o
, zval
*return_value
)
463 php_pqres_object_t
*obj
= o
;
465 RETVAL_STRING(PQresStatus(PQresultStatus(obj
->intern
->res
))+sizeof("PGRES"));
468 static void php_pqres_object_read_error_message(zval
*object
, void *o
, zval
*return_value
)
470 php_pqres_object_t
*obj
= o
;
471 char *error
= PHP_PQresultErrorMessage(obj
->intern
->res
);
474 RETVAL_STRING(error
);
480 static void php_pqres_object_read_num_rows(zval
*object
, void *o
, zval
*return_value
)
482 php_pqres_object_t
*obj
= o
;
484 RETVAL_LONG(PQntuples(obj
->intern
->res
));
487 static void php_pqres_object_read_num_cols(zval
*object
, void *o
, zval
*return_value
)
489 php_pqres_object_t
*obj
= o
;
491 RETVAL_LONG(PQnfields(obj
->intern
->res
));
494 static void php_pqres_object_read_affected_rows(zval
*object
, void *o
, zval
*return_value
)
496 php_pqres_object_t
*obj
= o
;
498 RETVAL_LONG(atoi(PQcmdTuples(obj
->intern
->res
)));
501 static void php_pqres_object_read_fetch_type(zval
*object
, void *o
, zval
*return_value
)
503 php_pqres_object_t
*obj
= o
;
505 RETVAL_LONG(php_pqres_fetch_type(obj
->intern
));
508 static void php_pqres_object_write_fetch_type(zval
*object
, void *o
, zval
*value
)
510 php_pqres_object_t
*obj
= o
;
512 if (!obj
->intern
->iter
) {
513 php_pqres_internal_iterator_init(object
);
515 obj
->intern
->iter
->fetch_type
= zval_get_long(value
);
518 static void php_pqres_object_read_auto_conv(zval
*object
, void *o
, zval
*return_value
)
520 php_pqres_object_t
*obj
= o
;
522 RETVAL_LONG(obj
->intern
->auto_convert
);
525 static void php_pqres_object_write_auto_conv(zval
*object
, void *o
, zval
*value
)
527 php_pqres_object_t
*obj
= o
;
529 obj
->intern
->auto_convert
= zval_get_long(value
);
532 static ZEND_RESULT_CODE
php_pqres_iteration(zval
*zobj
, php_pqres_object_t
*obj
, php_pqres_fetch_t fetch_type
, zval
*row TSRMLS_DC
)
535 php_pqres_fetch_t orig_fetch
;
538 obj
= PHP_PQ_OBJ(zobj
, NULL
);
541 if (obj
->intern
->iter
) {
542 obj
->intern
->iter
->zi
.funcs
->move_forward((zend_object_iterator
*) obj
->intern
->iter
);
544 php_pqres_internal_iterator_init(zobj
);
546 orig_fetch
= obj
->intern
->iter
->fetch_type
;
547 obj
->intern
->iter
->fetch_type
= fetch_type
;
548 if (SUCCESS
== (rv
= obj
->intern
->iter
->zi
.funcs
->valid((zend_object_iterator
*) obj
->intern
->iter
))) {
549 zval
*tmp
= obj
->intern
->iter
->zi
.funcs
->get_current_data((zend_object_iterator
*) obj
->intern
->iter
);
550 ZVAL_COPY_VALUE(row
, tmp
);
552 obj
->intern
->iter
->fetch_type
= orig_fetch
;
557 typedef struct php_pqres_col
{
562 static ZEND_RESULT_CODE
column_nn(php_pqres_object_t
*obj
, zval
*zcol
, php_pqres_col_t
*col
)
570 switch (Z_TYPE_P(zcol
)) {
576 index
= Z_LVAL_P(zcol
);
580 convert_to_string(zcol
);
584 if (!is_numeric_string(Z_STRVAL_P(zcol
), Z_STRLEN_P(zcol
), &index
, NULL
, 0)) {
585 name
= Z_STRVAL_P(zcol
);
593 col
->num
= PQfnumber(obj
->intern
->res
, name
);
595 col
->name
= PQfname(obj
->intern
->res
, index
);
600 php_error_docref(NULL
, E_WARNING
, "Failed to find column at index %ld", index
);
603 if (col
->num
== -1) {
604 php_error_docref(NULL
, E_WARNING
, "Failed to find column with name '%s'", name
);
610 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind
, 0, 0, 2)
611 ZEND_ARG_INFO(0, col
)
612 ZEND_ARG_INFO(1, ref
)
614 static PHP_METHOD(pqres
, bind
) {
616 zend_error_handling zeh
;
619 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
620 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "z/z", &zcol
, &zref
);
621 zend_restore_error_handling(&zeh
);
624 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
627 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
631 if (SUCCESS
!= column_nn(obj
, zcol
, &col
)) {
634 Z_TRY_ADDREF_P(zref
);
636 if (!zend_hash_index_update(&obj
->intern
->bound
, col
.num
, zref
)) {
637 php_error_docref(NULL
, E_WARNING
, "Failed to bind column %s@%d", col
.name
, col
.num
);
640 zend_hash_sort(&obj
->intern
->bound
, php_pq_compare_index
, 0);
648 static int apply_bound(zval
*zbound
, int argc
, va_list argv
, zend_hash_key
*key
)
651 zval
*zrow
= va_arg(argv
, zval
*);
652 ZEND_RESULT_CODE
*rv
= va_arg(argv
, ZEND_RESULT_CODE
*);
654 if (!(zvalue
= zend_hash_index_find(Z_ARRVAL_P(zrow
), key
->h
))) {
655 php_error_docref(NULL
, E_WARNING
, "Failed to find column ad index %lu", key
->h
);
657 return ZEND_HASH_APPLY_STOP
;
661 ZVAL_COPY(zbound
, zvalue
);
663 return ZEND_HASH_APPLY_KEEP
;
667 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound
, 0, 0, 0)
669 static PHP_METHOD(pqres
, fetchBound
) {
670 zend_error_handling zeh
;
673 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
674 rv
= zend_parse_parameters_none();
675 zend_restore_error_handling(&zeh
);
678 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
681 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
685 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh
);
686 if (SUCCESS
== php_pqres_iteration(getThis(), obj
, PHP_PQRES_FETCH_ARRAY
, &row
)) {
687 zend_hash_apply_with_arguments(&obj
->intern
->bound
, apply_bound
, 2, &row
, &rv
);
690 RETVAL_ZVAL(&row
, 1, 0);
693 zend_restore_error_handling(&zeh
);
698 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row
, 0, 0, 0)
699 ZEND_ARG_INFO(0, fetch_type
)
701 static PHP_METHOD(pqres
, fetchRow
) {
702 zend_error_handling zeh
;
703 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
704 zend_long fetch_type
= -1;
707 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
708 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type
);
709 zend_restore_error_handling(&zeh
);
713 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
717 if (fetch_type
== -1) {
718 fetch_type
= php_pqres_fetch_type(obj
->intern
);
721 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh
);
722 if (SUCCESS
== php_pqres_iteration(getThis(), obj
, fetch_type
, &row
)) {
723 RETVAL_ZVAL(&row
, 1, 0);
725 zend_restore_error_handling(&zeh
);
730 static zval
*column_at(zval
*row
, int col
)
733 HashTable
*ht
= HASH_OF(row
);
734 int count
= zend_hash_num_elements(ht
);
737 php_error_docref(NULL
, E_WARNING
, "Column index %d exceeds column count %d", col
, count
);
739 zend_hash_internal_pointer_reset(ht
);
741 zend_hash_move_forward(ht
);
743 data
= zend_hash_get_current_data(ht
);
748 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col
, 0, 0, 1)
749 ZEND_ARG_INFO(1, ref
)
750 ZEND_ARG_INFO(0, col
)
752 static PHP_METHOD(pqres
, fetchCol
) {
753 zend_error_handling zeh
;
754 zval
*zcol
= NULL
, *zref
;
757 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
758 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "z|z/!", &zref
, &zcol
);
759 zend_restore_error_handling(&zeh
);
762 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
765 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
769 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh
);
770 if (SUCCESS
== php_pqres_iteration(getThis(), obj
, php_pqres_fetch_type(obj
->intern
), &row
)) {
773 if (SUCCESS
!= column_nn(obj
, zcol
, &col
)) {
776 zval
*zres
= column_at(&row
, col
.num
);
783 ZVAL_ZVAL(zref
, zres
, 1, 0);
788 zend_restore_error_handling(&zeh
);
793 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all_cols
, 0, 0, 0)
794 ZEND_ARG_INFO(0, col
)
796 static PHP_METHOD(pqres
, fetchAllCols
) {
797 zend_error_handling zeh
;
801 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
802 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zcol
);
803 zend_restore_error_handling(&zeh
);
806 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
809 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
813 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh
);
814 if (SUCCESS
== column_nn(obj
, zcol
, &col
)) {
815 int r
, rows
= PQntuples(obj
->intern
->res
);
818 array_init(return_value
);
819 for (r
= 0; r
< rows
; ++r
) {
820 add_next_index_zval(return_value
, php_pqres_get_col(obj
->intern
, r
, col
.num
, &tmp
));
823 zend_restore_error_handling(&zeh
);
828 struct apply_to_col_arg
{
829 php_pqres_object_t
*obj
;
830 php_pqres_col_t
*cols
;
831 ZEND_RESULT_CODE status
;
834 static int apply_to_col(zval
*c
, void *a
)
836 struct apply_to_col_arg
*arg
= a
;
838 if (SUCCESS
!= column_nn(arg
->obj
, c
, arg
->cols
)) {
839 arg
->status
= FAILURE
;
840 return ZEND_HASH_APPLY_STOP
;
842 arg
->status
= SUCCESS
;
844 return ZEND_HASH_APPLY_KEEP
;
848 static php_pqres_col_t
*php_pqres_convert_to_cols(php_pqres_object_t
*obj
, HashTable
*ht
)
850 struct apply_to_col_arg arg
= {NULL
};
851 php_pqres_col_t
*tmp
;
854 arg
.cols
= ecalloc(zend_hash_num_elements(ht
), sizeof(*tmp
));
856 zend_hash_apply_with_argument(ht
, apply_to_col
, &arg
);
858 if (SUCCESS
== arg
.status
) {
866 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_map
, 0, 0, 0)
867 ZEND_ARG_INFO(0, keys
)
868 ZEND_ARG_INFO(0, vals
)
869 ZEND_ARG_INFO(0, fetch_type
)
871 static PHP_METHOD(pqres
, map
) {
872 zend_error_handling zeh
;
873 zval
*zkeys
= 0, *zvals
= 0;
874 zend_long fetch_type
= -1;
877 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
878 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|z/!z/!l", &zkeys
, &zvals
, &fetch_type
);
879 zend_restore_error_handling(&zeh
);
882 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
885 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
888 php_pqres_col_t def
= {PQfname(obj
->intern
->res
, 0), 0}, *keys
= NULL
, *vals
= NULL
;
891 convert_to_array(zkeys
);
893 if ((ks
= zend_hash_num_elements(Z_ARRVAL_P(zkeys
)))) {
894 keys
= php_pqres_convert_to_cols(obj
, Z_ARRVAL_P(zkeys
));
904 convert_to_array(zvals
);
906 if ((vs
= zend_hash_num_elements(Z_ARRVAL_P(zvals
)))) {
907 vals
= php_pqres_convert_to_cols(obj
, Z_ARRVAL_P(zvals
));
911 if (fetch_type
== -1) {
912 fetch_type
= php_pqres_fetch_type(obj
->intern
);
919 switch (fetch_type
) {
920 case PHP_PQRES_FETCH_ARRAY
:
921 case PHP_PQRES_FETCH_ASSOC
:
922 array_init(return_value
);
924 case PHP_PQRES_FETCH_OBJECT
:
925 object_init(return_value
);
928 for (r
= 0, rows
= PQntuples(obj
->intern
->res
); r
< rows
; ++r
) {
933 for (k
= 0; k
< ks
; ++k
) {
934 char *key
= PQgetvalue(obj
->intern
->res
, r
, keys
[k
].num
);
935 int len
= PQgetlength(obj
->intern
->res
, r
, keys
[k
].num
);
937 if (!(ptr
= zend_symtable_str_find(HASH_OF(cur
), key
, len
))) {
940 switch (fetch_type
) {
941 case PHP_PQRES_FETCH_ARRAY
:
942 case PHP_PQRES_FETCH_ASSOC
:
945 case PHP_PQRES_FETCH_OBJECT
:
949 if (!(ptr
= zend_symtable_str_update(HASH_OF(cur
), key
, len
, &tmp
))) {
950 throw_exce(EX_RUNTIME
, "Failed to create map");
958 for (v
= 0; v
< vs
; ++v
) {
959 char *val
= PQgetvalue(obj
->intern
->res
, r
, vals
[v
].num
);
960 int len
= PQgetlength(obj
->intern
->res
, r
, vals
[v
].num
);
962 switch (fetch_type
) {
963 case PHP_PQRES_FETCH_ARRAY
:
964 add_index_stringl(cur
, vals
[v
].num
, val
, len
);
966 case PHP_PQRES_FETCH_ASSOC
:
967 add_assoc_stringl(cur
, vals
[v
].name
, val
, len
);
969 case PHP_PQRES_FETCH_OBJECT
:
970 add_property_stringl(cur
, vals
[v
].name
, val
, len
);
975 php_pqres_row_to_zval(obj
->intern
->res
, r
, fetch_type
, cur
);
981 if (keys
&& keys
!= &def
) {
991 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all
, 0, 0, 0)
992 ZEND_ARG_INFO(0, fetch_type
)
994 static PHP_METHOD(pqres
, fetchAll
) {
995 zend_error_handling zeh
;
996 zend_long fetch_type
= -1;
999 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
1000 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type
);
1001 zend_restore_error_handling(&zeh
);
1003 if (SUCCESS
== rv
) {
1004 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
1007 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
1009 int r
, rows
= PQntuples(obj
->intern
->res
);
1012 if (fetch_type
== -1) {
1013 fetch_type
= php_pqres_fetch_type(obj
->intern
);
1016 array_init(return_value
);
1017 for (r
= 0; r
< rows
; ++r
) {
1019 add_next_index_zval(return_value
, php_pqres_row_to_zval(obj
->intern
->res
, r
, fetch_type
, &tmp
));
1025 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count
, 0, 0, 0)
1026 ZEND_END_ARG_INFO();
1027 static PHP_METHOD(pqres
, count
) {
1028 zend_error_handling zeh
;
1029 ZEND_RESULT_CODE rv
;
1031 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
1032 rv
= zend_parse_parameters_none();
1033 zend_restore_error_handling(&zeh
);
1035 if (SUCCESS
== rv
) {
1038 if (SUCCESS
!= php_pqres_count_elements(getThis(), &count
)) {
1039 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
1046 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_desc
, 0, 0, 0)
1047 ZEND_END_ARG_INFO();
1048 static PHP_METHOD(pqres
, desc
) {
1049 zend_error_handling zeh
;
1050 ZEND_RESULT_CODE rv
;
1052 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
1053 rv
= zend_parse_parameters_none();
1054 zend_restore_error_handling(&zeh
);
1056 if (SUCCESS
== rv
) {
1057 php_pqres_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
1060 throw_exce(EX_UNINITIALIZED
, "pq\\Result not initialized");
1064 array_init(return_value
);
1065 for (p
= 0, params
= PQnparams(obj
->intern
->res
); p
< params
; ++p
) {
1066 add_next_index_long(return_value
, PQparamtype(obj
->intern
->res
, p
));
1072 static zend_function_entry php_pqres_methods
[] = {
1073 PHP_ME(pqres
, bind
, ai_pqres_bind
, ZEND_ACC_PUBLIC
)
1074 PHP_ME(pqres
, fetchBound
, ai_pqres_fetch_bound
, ZEND_ACC_PUBLIC
)
1075 PHP_ME(pqres
, fetchRow
, ai_pqres_fetch_row
, ZEND_ACC_PUBLIC
)
1076 PHP_ME(pqres
, fetchCol
, ai_pqres_fetch_col
, ZEND_ACC_PUBLIC
)
1077 PHP_ME(pqres
, fetchAll
, ai_pqres_fetch_all
, ZEND_ACC_PUBLIC
)
1078 PHP_ME(pqres
, fetchAllCols
, ai_pqres_fetch_all_cols
, ZEND_ACC_PUBLIC
)
1079 PHP_ME(pqres
, count
, ai_pqres_count
, ZEND_ACC_PUBLIC
)
1080 PHP_ME(pqres
, map
, ai_pqres_map
, ZEND_ACC_PUBLIC
)
1081 PHP_ME(pqres
, desc
, ai_pqres_desc
, ZEND_ACC_PUBLIC
)
1085 PHP_MSHUTDOWN_FUNCTION(pqres
)
1087 zend_hash_destroy(&php_pqres_object_prophandlers
);
1091 PHP_MINIT_FUNCTION(pqres
)
1093 zend_class_entry ce
= {0};
1094 php_pq_object_prophandler_t ph
= {0};
1096 INIT_NS_CLASS_ENTRY(ce
, "pq", "Result", php_pqres_methods
);
1097 php_pqres_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
1098 php_pqres_class_entry
->create_object
= php_pqres_create_object
;
1099 php_pqres_class_entry
->get_iterator
= php_pqres_iterator_init
;
1100 zend_class_implements(php_pqres_class_entry
, 2, zend_ce_traversable
, spl_ce_Countable
);
1102 memcpy(&php_pqres_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1103 php_pqres_object_handlers
.offset
= XtOffsetOf(php_pqres_object_t
, zo
);
1104 php_pqres_object_handlers
.free_obj
= php_pqres_object_free
;
1105 php_pqres_object_handlers
.read_property
= php_pq_object_read_prop
;
1106 php_pqres_object_handlers
.write_property
= php_pq_object_write_prop
;
1107 php_pqres_object_handlers
.clone_obj
= NULL
;
1108 php_pqres_object_handlers
.get_property_ptr_ptr
= NULL
;
1109 php_pqres_object_handlers
.get_gc
= php_pq_object_get_gc
;
1110 php_pqres_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
1111 php_pqres_object_handlers
.get_properties
= php_pq_object_properties
;
1112 php_pqres_object_handlers
.count_elements
= php_pqres_count_elements
;
1114 zend_hash_init(&php_pqres_object_prophandlers
, 8, NULL
, php_pq_object_prophandler_dtor
, 1);
1116 zend_declare_property_null(php_pqres_class_entry
, ZEND_STRL("status"), ZEND_ACC_PUBLIC
);
1117 ph
.read
= php_pqres_object_read_status
;
1118 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "status", sizeof("status")-1, (void *) &ph
, sizeof(ph
));
1120 zend_declare_property_null(php_pqres_class_entry
, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC
);
1121 ph
.read
= php_pqres_object_read_status_message
;
1122 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "statusMessage", sizeof("statusMessage")-1, (void *) &ph
, sizeof(ph
));
1124 zend_declare_property_null(php_pqres_class_entry
, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC
);
1125 ph
.read
= php_pqres_object_read_error_message
;
1126 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "errorMessage", sizeof("errorMessage")-1, (void *) &ph
, sizeof(ph
));
1128 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC
);
1129 ph
.read
= php_pqres_object_read_num_rows
;
1130 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "numRows", sizeof("numRows")-1, (void *) &ph
, sizeof(ph
));
1132 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC
);
1133 ph
.read
= php_pqres_object_read_num_cols
;
1134 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "numCols", sizeof("numCols")-1, (void *) &ph
, sizeof(ph
));
1136 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC
);
1137 ph
.read
= php_pqres_object_read_affected_rows
;
1138 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "affectedRows", sizeof("affectedRows")-1, (void *) &ph
, sizeof(ph
));
1140 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY
, ZEND_ACC_PUBLIC
);
1141 ph
.read
= php_pqres_object_read_fetch_type
;
1142 ph
.write
= php_pqres_object_write_fetch_type
;
1143 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "fetchType", sizeof("fetchType")-1, (void *) &ph
, sizeof(ph
));
1146 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("autoConvert"), PHP_PQRES_CONV_ALL
, ZEND_ACC_PUBLIC
);
1147 ph
.read
= php_pqres_object_read_auto_conv
;
1148 ph
.write
= php_pqres_object_write_auto_conv
;
1149 zend_hash_str_add_mem(&php_pqres_object_prophandlers
, "autoConvert", sizeof("autoConvert")-1, (void *) &ph
, sizeof(ph
));
1152 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY
);
1153 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK
);
1154 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK
);
1155 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT
);
1156 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COPY_IN"), PGRES_COPY_IN
);
1157 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE
);
1158 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR
);
1159 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR
);
1160 #ifdef HAVE_PGRES_COPY_BOTH
1161 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH
);
1163 #ifdef HAVE_PGRES_SINGLE_TUPLE
1164 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE
);
1167 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY
);
1168 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC
);
1169 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT
);
1171 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_BOOL"), PHP_PQRES_CONV_BOOL
);
1172 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_INT"), PHP_PQRES_CONV_INT
);
1173 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_FLOAT"), PHP_PQRES_CONV_FLOAT
);
1174 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR
);
1175 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY
);
1176 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME
);
1177 #if PHP_PQ_HAVE_PHP_JSON_H
1178 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_JSON"), PHP_PQRES_CONV_JSON
);
1180 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL
);
1190 * vim600: noet sw=4 ts=4 fdm=marker
1191 * vim<600: noet sw=4 ts=4