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 #include <libpq-events.h>
23 #include "php_pq_misc.h"
24 #include "php_pq_object.h"
25 #include "php_pqexc.h"
26 #include "php_pqres.h"
28 #include "php_pq_type.h"
30 zend_class_entry
*php_pqres_class_entry
;
31 static zend_object_handlers php_pqres_object_handlers
;
32 static HashTable php_pqres_object_prophandlers
;
33 static zend_object_iterator_funcs php_pqres_iterator_funcs
;
35 static zend_object_iterator
*php_pqres_iterator_init(zend_class_entry
*ce
, zval
*object
, int by_ref TSRMLS_DC
)
37 php_pqres_iterator_t
*iter
;
38 zval
*prop
, *zfetch_type
;
40 iter
= ecalloc(1, sizeof(*iter
));
41 iter
->zi
.funcs
= &php_pqres_iterator_funcs
;
42 iter
->zi
.data
= object
;
43 /* do not addref, because the iterator lives inside this object anyway */
45 zfetch_type
= prop
= zend_read_property(ce
, object
, ZEND_STRL("fetchType"), 0 TSRMLS_CC
);
46 if (Z_TYPE_P(zfetch_type
) != IS_LONG
) {
47 convert_to_long_ex(&zfetch_type
);
49 iter
->fetch_type
= Z_LVAL_P(zfetch_type
);
50 if (zfetch_type
!= prop
) {
51 zval_ptr_dtor(&zfetch_type
);
53 if (Z_REFCOUNT_P(prop
)) {
60 return (zend_object_iterator
*) iter
;
63 static void php_pqres_iterator_dtor(zend_object_iterator
*i TSRMLS_DC
)
65 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
67 if (iter
->current_val
) {
68 zval_ptr_dtor(&iter
->current_val
);
69 iter
->current_val
= NULL
;
74 static STATUS
php_pqres_iterator_valid(zend_object_iterator
*i TSRMLS_DC
)
76 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
77 php_pqres_object_t
*obj
= zend_object_store_get_object(iter
->zi
.data TSRMLS_CC
);
79 switch (PQresultStatus(obj
->intern
->res
)) {
81 case PGRES_SINGLE_TUPLE
:
82 if (PQntuples(obj
->intern
->res
) <= iter
->index
) {
93 zval
*php_pqres_typed_zval(php_pqres_t
*res
, char *val
, size_t len
, Oid typ TSRMLS_DC
)
99 if (SUCCESS
== zend_hash_index_find(&res
->converters
, typ
, (void *) &zconv
)) {
102 ZVAL_STRINGL(zv
, val
, len
, 1);
103 zend_call_method_with_1_params(zconv
, NULL
, NULL
, "convertfromstring", &tmp
, zv
);
114 case PHP_PQ_OID_BOOL
:
115 if (!(res
->auto_convert
& PHP_PQRES_CONV_BOOL
)) {
118 ZVAL_BOOL(zv
, *val
== 't');
121 case PHP_PQ_OID_INT8
:
124 case PHP_PQ_OID_INT4
:
125 case PHP_PQ_OID_INT2
:
128 if (!(res
->auto_convert
& PHP_PQRES_CONV_INT
)) {
131 ZVAL_LONG(zv
, zend_atol(val
, len
));
134 case PHP_PQ_OID_FLOAT4
:
135 case PHP_PQ_OID_FLOAT8
:
136 if (!(res
->auto_convert
& PHP_PQRES_CONV_FLOAT
)) {
139 ZVAL_DOUBLE(zv
, zend_strtod(val
, NULL
));
142 case PHP_PQ_OID_DATE
:
143 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
146 php_pqdt_from_string(val
, len
, "Y-m-d", zv TSRMLS_CC
);
149 case PHP_PQ_OID_ABSTIME
:
150 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
153 php_pqdt_from_string(val
, len
, "Y-m-d H:i:s", zv TSRMLS_CC
);
156 case PHP_PQ_OID_TIMESTAMP
:
157 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
160 php_pqdt_from_string(val
, len
, "Y-m-d H:i:s.u", zv TSRMLS_CC
);
163 case PHP_PQ_OID_TIMESTAMPTZ
:
164 if (!(res
->auto_convert
& PHP_PQRES_CONV_DATETIME
)) {
167 php_pqdt_from_string(val
, len
, "Y-m-d H:i:s.uO", zv TSRMLS_CC
);
171 if (!(res
->auto_convert
& PHP_PQRES_CONV_ARRAY
)) {
174 if (PHP_PQ_TYPE_IS_ARRAY(typ
) && (Z_ARRVAL_P(zv
) = php_pq_parse_array(res
, val
, len
, PHP_PQ_TYPE_OF_ARRAY(typ
) TSRMLS_CC
))) {
175 Z_TYPE_P(zv
) = IS_ARRAY
;
178 ZVAL_STRINGL(zv
, val
, len
, 1);
186 static inline zval
*php_pqres_get_col(php_pqres_t
*r
, unsigned row
, unsigned col TSRMLS_DC
)
190 if (PQgetisnull(r
->res
, row
, col
)) {
194 zv
= php_pqres_typed_zval(r
, PQgetvalue(r
->res
, row
, col
), PQgetlength(r
->res
, row
, col
), PQftype(r
->res
, col
) TSRMLS_CC
);
200 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 TSRMLS_DC
)
202 if (PQgetisnull(r
->res
, row
, col
)) {
203 switch (fetch_type
) {
204 case PHP_PQRES_FETCH_OBJECT
:
205 add_property_null(data
, PQfname(r
->res
, col
));
208 case PHP_PQRES_FETCH_ASSOC
:
209 add_assoc_null(data
, PQfname(r
->res
, col
));
212 case PHP_PQRES_FETCH_ARRAY
:
213 add_index_null(data
, col
);
219 zv
= php_pqres_typed_zval(r
, PQgetvalue(r
->res
, row
, col
), PQgetlength(r
->res
, row
, col
), PQftype(r
->res
, col
) TSRMLS_CC
);
221 switch (fetch_type
) {
222 case PHP_PQRES_FETCH_OBJECT
:
223 add_property_zval(data
, PQfname(r
->res
, col
), zv
);
227 case PHP_PQRES_FETCH_ASSOC
:
228 add_assoc_zval(data
, PQfname(r
->res
, col
), zv
);
231 case PHP_PQRES_FETCH_ARRAY
:
232 add_index_zval(data
, col
, zv
);
238 zval
*php_pqres_row_to_zval(PGresult
*res
, unsigned row
, php_pqres_fetch_t fetch_type
, zval
**data_ptr TSRMLS_DC
)
242 php_pqres_object_t
*res_obj
= PQresultInstanceData(res
, php_pqconn_event
);
249 if (PHP_PQRES_FETCH_OBJECT
== fetch_type
) {
259 if (PQntuples(res
) > row
) {
260 for (c
= 0, cols
= PQnfields(res
); c
< cols
; ++c
) {
261 php_pqres_add_col_to_zval(res_obj
->intern
, row
, c
, fetch_type
, data TSRMLS_CC
);
268 static void php_pqres_iterator_current(zend_object_iterator
*i
, zval
***data_ptr TSRMLS_DC
)
270 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
271 php_pqres_object_t
*obj
= zend_object_store_get_object(iter
->zi
.data TSRMLS_CC
);
273 if (!iter
->current_val
) {
274 iter
->current_val
= php_pqres_row_to_zval(obj
->intern
->res
, iter
->index
, iter
->fetch_type
, NULL TSRMLS_CC
);
276 *data_ptr
= &iter
->current_val
;
279 #if PHP_VERSION_ID >= 50500
280 static void php_pqres_iterator_key(zend_object_iterator
*i
, zval
*key TSRMLS_DC
)
282 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
284 ZVAL_LONG(key
, iter
->index
);
287 static int php_pqres_iterator_key(zend_object_iterator
*i
, char **key_str
, uint
*key_len
, ulong
*key_num TSRMLS_DC
)
289 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
291 *key_num
= (ulong
) iter
->index
;
293 return HASH_KEY_IS_LONG
;
297 static void php_pqres_iterator_invalidate(zend_object_iterator
*i TSRMLS_DC
)
299 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
301 if (iter
->current_val
) {
302 zval_ptr_dtor(&iter
->current_val
);
303 iter
->current_val
= NULL
;
307 static void php_pqres_iterator_next(zend_object_iterator
*i TSRMLS_DC
)
309 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
311 php_pqres_iterator_invalidate(i TSRMLS_CC
);
315 static void php_pqres_iterator_rewind(zend_object_iterator
*i TSRMLS_DC
)
317 php_pqres_iterator_t
*iter
= (php_pqres_iterator_t
*) i
;
319 php_pqres_iterator_invalidate(i TSRMLS_CC
);
323 static zend_object_iterator_funcs php_pqres_iterator_funcs
= {
324 php_pqres_iterator_dtor
,
325 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
326 php_pqres_iterator_valid
,
327 /* fetch the item data for the current element */
328 php_pqres_iterator_current
,
329 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
330 php_pqres_iterator_key
,
331 /* step forwards to next element */
332 php_pqres_iterator_next
,
333 /* rewind to start of data (optional, may be NULL) */
334 php_pqres_iterator_rewind
,
335 /* invalidate current value/key (optional, may be NULL) */
336 php_pqres_iterator_invalidate
339 static int php_pqres_count_elements(zval
*object
, long *count TSRMLS_DC
)
341 php_pqres_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
346 *count
= (long) PQntuples(obj
->intern
->res
);
351 STATUS
php_pqres_success(PGresult
*res TSRMLS_DC
)
355 switch (PQresultStatus(res
)) {
356 case PGRES_BAD_RESPONSE
:
357 case PGRES_NONFATAL_ERROR
:
358 case PGRES_FATAL_ERROR
:
359 zexc
= throw_exce(EX_SQL TSRMLS_CC
, "%s", PHP_PQresultErrorMessage(res
));
360 zend_update_property_string(Z_OBJCE_P(zexc
), zexc
, ZEND_STRL("sqlstate"), PQresultErrorField(res
, PG_DIAG_SQLSTATE
) TSRMLS_CC
);
367 void php_pqres_init_instance_data(PGresult
*res
, php_pqconn_object_t
*conn_obj
, php_pqres_object_t
**ptr TSRMLS_DC
)
369 php_pqres_object_t
*obj
;
370 php_pqres_t
*r
= ecalloc(1, sizeof(*r
));
373 zend_hash_init(&r
->bound
, 0, 0, ZVAL_PTR_DTOR
, 0);
374 zend_hash_init(&r
->converters
, 0, 0, ZVAL_PTR_DTOR
, 0);
375 zend_hash_copy(&r
->converters
, &conn_obj
->intern
->converters
, (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
377 r
->auto_convert
= conn_obj
->intern
->default_auto_convert
;
378 r
->default_fetch_type
= conn_obj
->intern
->default_fetch_type
;
380 php_pqres_create_object_ex(php_pqres_class_entry
, r
, &obj TSRMLS_CC
);
381 PQresultSetInstanceData(res
, php_pqconn_event
, obj
);
388 static void php_pqres_object_free(void *o TSRMLS_DC
)
390 php_pqres_object_t
*obj
= o
;
392 fprintf(stderr
, "FREE res(#%d) %p\n", obj
->zv
.handle
, obj
);
395 if (obj
->intern
->res
) {
396 PQresultSetInstanceData(obj
->intern
->res
, php_pqconn_event
, NULL
);
397 PQclear(obj
->intern
->res
);
398 obj
->intern
->res
= NULL
;
401 if (obj
->intern
->iter
) {
402 php_pqres_iterator_dtor((zend_object_iterator
*) obj
->intern
->iter TSRMLS_CC
);
403 obj
->intern
->iter
= NULL
;
406 zend_hash_destroy(&obj
->intern
->bound
);
407 zend_hash_destroy(&obj
->intern
->converters
);
412 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
416 zend_object_value
php_pqres_create_object_ex(zend_class_entry
*ce
, php_pqres_t
*intern
, php_pqres_object_t
**ptr TSRMLS_DC
)
418 php_pqres_object_t
*o
;
420 o
= ecalloc(1, sizeof(*o
));
421 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
422 object_properties_init((zend_object
*) o
, ce
);
423 o
->prophandler
= &php_pqres_object_prophandlers
;
433 o
->zv
.handle
= zend_objects_store_put((zend_object
*) o
, NULL
, php_pqres_object_free
, NULL TSRMLS_CC
);
434 o
->zv
.handlers
= &php_pqres_object_handlers
;
439 static zend_object_value
php_pqres_create_object(zend_class_entry
*class_type TSRMLS_DC
)
441 return php_pqres_create_object_ex(class_type
, NULL
, NULL TSRMLS_CC
);
444 static void php_pqres_object_read_status(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
446 php_pqres_object_t
*obj
= o
;
448 RETVAL_LONG(PQresultStatus(obj
->intern
->res
));
451 static void php_pqres_object_read_status_message(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
453 php_pqres_object_t
*obj
= o
;
455 RETVAL_STRING(PQresStatus(PQresultStatus(obj
->intern
->res
))+sizeof("PGRES"), 1);
458 static void php_pqres_object_read_error_message(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
460 php_pqres_object_t
*obj
= o
;
461 char *error
= PHP_PQresultErrorMessage(obj
->intern
->res
);
464 RETVAL_STRING(error
, 1);
470 static void php_pqres_object_read_num_rows(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
472 php_pqres_object_t
*obj
= o
;
474 RETVAL_LONG(PQntuples(obj
->intern
->res
));
477 static void php_pqres_object_read_num_cols(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
479 php_pqres_object_t
*obj
= o
;
481 RETVAL_LONG(PQnfields(obj
->intern
->res
));
484 static void php_pqres_object_read_affected_rows(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
486 php_pqres_object_t
*obj
= o
;
488 RETVAL_LONG(atoi(PQcmdTuples(obj
->intern
->res
)));
491 static void php_pqres_object_read_fetch_type(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
493 php_pqres_object_t
*obj
= o
;
495 if (obj
->intern
->iter
) {
496 RETVAL_LONG(obj
->intern
->iter
->fetch_type
);
498 RETVAL_LONG(obj
->intern
->default_fetch_type
);
502 static void php_pqres_object_write_fetch_type(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
504 php_pqres_object_t
*obj
= o
;
505 zval
*zfetch_type
= value
;
507 if (Z_TYPE_P(value
) != IS_LONG
) {
508 if (Z_REFCOUNT_P(value
) > 1) {
511 ZVAL_ZVAL(tmp
, zfetch_type
, 1, 0);
512 convert_to_long(tmp
);
515 convert_to_long_ex(&zfetch_type
);
519 if (!obj
->intern
->iter
) {
520 obj
->intern
->iter
= (php_pqres_iterator_t
*) php_pqres_iterator_init(Z_OBJCE_P(object
), object
, 0 TSRMLS_CC
);
521 obj
->intern
->iter
->zi
.funcs
->rewind((zend_object_iterator
*) obj
->intern
->iter TSRMLS_CC
);
523 obj
->intern
->iter
->fetch_type
= Z_LVAL_P(zfetch_type
);
525 if (zfetch_type
!= value
) {
526 zval_ptr_dtor(&zfetch_type
);
530 static void php_pqres_object_read_auto_conv(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
532 php_pqres_object_t
*obj
= o
;
534 RETVAL_LONG(obj
->intern
->auto_convert
);
537 static void php_pqres_object_write_auto_conv(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
539 php_pqres_object_t
*obj
= o
;
540 zval
*zauto_conv
= value
;
542 if (Z_TYPE_P(value
) != IS_LONG
) {
543 if (Z_REFCOUNT_P(value
) > 1) {
546 ZVAL_ZVAL(tmp
, zauto_conv
, 1, 0);
547 convert_to_long(tmp
);
550 convert_to_long_ex(&zauto_conv
);
554 obj
->intern
->auto_convert
= Z_LVAL_P(zauto_conv
);
556 if (zauto_conv
!= value
) {
557 zval_ptr_dtor(&zauto_conv
);
561 static STATUS
php_pqres_iteration(zval
*this_ptr
, php_pqres_object_t
*obj
, php_pqres_fetch_t fetch_type
, zval
***row TSRMLS_DC
)
564 php_pqres_fetch_t orig_fetch
;
567 obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
570 if (obj
->intern
->iter
) {
571 obj
->intern
->iter
->zi
.funcs
->move_forward((zend_object_iterator
*) obj
->intern
->iter TSRMLS_CC
);
573 obj
->intern
->iter
= (php_pqres_iterator_t
*) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC
);
574 obj
->intern
->iter
->zi
.funcs
->rewind((zend_object_iterator
*) obj
->intern
->iter TSRMLS_CC
);
576 orig_fetch
= obj
->intern
->iter
->fetch_type
;
577 obj
->intern
->iter
->fetch_type
= fetch_type
;
578 if (SUCCESS
== (rv
= obj
->intern
->iter
->zi
.funcs
->valid((zend_object_iterator
*) obj
->intern
->iter TSRMLS_CC
))) {
579 obj
->intern
->iter
->zi
.funcs
->get_current_data((zend_object_iterator
*) obj
->intern
->iter
, row TSRMLS_CC
);
581 obj
->intern
->iter
->fetch_type
= orig_fetch
;
586 typedef struct php_pqres_col
{
591 static STATUS
column_nn(php_pqres_object_t
*obj
, zval
*zcol
, php_pqres_col_t
*col TSRMLS_DC
)
596 switch (Z_TYPE_P(zcol
)) {
598 index
= Z_LVAL_P(zcol
);
602 convert_to_string(zcol
);
606 if (!is_numeric_string(Z_STRVAL_P(zcol
), Z_STRLEN_P(zcol
), &index
, NULL
, 0)) {
607 name
= Z_STRVAL_P(zcol
);
614 col
->num
= PQfnumber(obj
->intern
->res
, name
);
616 col
->name
= PQfname(obj
->intern
->res
, index
);
621 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to find column at index %ld", index
);
624 if (col
->num
== -1) {
625 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to find column with name '%s'", name
);
631 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind
, 0, 0, 2)
632 ZEND_ARG_INFO(0, col
)
633 ZEND_ARG_INFO(1, ref
)
635 static PHP_METHOD(pqres
, bind
) {
638 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z/z", &zcol
, &zref
)) {
639 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
642 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
646 if (SUCCESS
!= column_nn(obj
, zcol
, &col TSRMLS_CC
)) {
651 if (SUCCESS
!= zend_hash_index_update(&obj
->intern
->bound
, col
.num
, (void *) &zref
, sizeof(zval
*), NULL
)) {
652 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to bind column %s@%d", col
.name
, col
.num
);
655 zend_hash_sort(&obj
->intern
->bound
, zend_qsort
, compare_index
, 0 TSRMLS_CC
);
663 static int apply_bound(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
665 zval
**zvalue
, **zbound
= p
;
666 zval
**zrow
= va_arg(argv
, zval
**);
667 STATUS
*rv
= va_arg(argv
, STATUS
*);
669 if (SUCCESS
!= zend_hash_index_find(Z_ARRVAL_PP(zrow
), key
->h
, (void *) &zvalue
)) {
670 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to find column ad index %lu", key
->h
);
672 return ZEND_HASH_APPLY_STOP
;
675 ZVAL_COPY_VALUE(*zbound
, *zvalue
);
677 zval_ptr_dtor(zvalue
);
681 return ZEND_HASH_APPLY_KEEP
;
685 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound
, 0, 0, 0)
687 static PHP_METHOD(pqres
, fetchBound
) {
688 zend_error_handling zeh
;
691 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
692 rv
= zend_parse_parameters_none();
693 zend_restore_error_handling(&zeh TSRMLS_CC
);
696 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
699 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
703 if (SUCCESS
== php_pqres_iteration(getThis(), obj
, PHP_PQRES_FETCH_ARRAY
, &row TSRMLS_CC
) && row
) {
704 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh TSRMLS_CC
);
705 zend_hash_apply_with_arguments(&obj
->intern
->bound TSRMLS_CC
, apply_bound
, 2, row
, &rv
);
706 zend_restore_error_handling(&zeh TSRMLS_CC
);
711 RETVAL_ZVAL(*row
, 1, 0);
718 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row
, 0, 0, 0)
719 ZEND_ARG_INFO(0, fetch_type
)
721 static PHP_METHOD(pqres
, fetchRow
) {
722 zend_error_handling zeh
;
723 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
724 long fetch_type
= -1;
727 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
728 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &fetch_type
);
729 zend_restore_error_handling(&zeh TSRMLS_CC
);
733 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
737 if (fetch_type
== -1) {
738 fetch_type
= obj
->intern
->iter
? obj
->intern
->iter
->fetch_type
: obj
->intern
->default_fetch_type
;
741 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh TSRMLS_CC
);
742 php_pqres_iteration(getThis(), obj
, fetch_type
, &row TSRMLS_CC
);
743 zend_restore_error_handling(&zeh TSRMLS_CC
);
746 RETVAL_ZVAL(*row
, 1, 0);
752 static zval
**column_at(zval
*row
, int col TSRMLS_DC
)
755 HashTable
*ht
= HASH_OF(row
);
756 int count
= zend_hash_num_elements(ht
);
759 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Column index %d exceeds column count %d", col
, count
);
761 zend_hash_internal_pointer_reset(ht
);
763 zend_hash_move_forward(ht
);
765 zend_hash_get_current_data(ht
, (void *) &data
);
770 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col
, 0, 0, 2)
771 ZEND_ARG_INFO(0, col
)
772 ZEND_ARG_INFO(1, ref
)
774 static PHP_METHOD(pqres
, fetchCol
) {
775 zend_error_handling zeh
;
779 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
780 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z/z", &zcol
, &zref
);
781 zend_restore_error_handling(&zeh TSRMLS_CC
);
784 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
787 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
791 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh TSRMLS_CC
);
792 php_pqres_iteration(getThis(), obj
, obj
->intern
->iter
? obj
->intern
->iter
->fetch_type
: 0, &row TSRMLS_CC
);
798 if (SUCCESS
!= column_nn(obj
, zcol
, &col TSRMLS_CC
)) {
801 zval
**zres
= column_at(*row
, col
.num TSRMLS_CC
);
807 ZVAL_ZVAL(zref
, *zres
, 1, 0);
812 zend_restore_error_handling(&zeh TSRMLS_CC
);
817 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all_cols
, 0, 0, 1)
818 ZEND_ARG_INFO(0, col
)
820 static PHP_METHOD(pqres
, fetchAllCols
) {
821 zend_error_handling zeh
;
825 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
826 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z", &zcol
);
827 zend_restore_error_handling(&zeh TSRMLS_CC
);
830 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
833 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
837 zend_replace_error_handling(EH_THROW
, exce(EX_RUNTIME
), &zeh TSRMLS_CC
);
839 if (SUCCESS
== column_nn(obj
, zcol
, &col TSRMLS_CC
)) {
840 int r
, rows
= PQntuples(obj
->intern
->res
);
842 array_init(return_value
);
843 for (r
= 0; r
< rows
; ++r
) {
844 add_next_index_zval(return_value
, php_pqres_get_col(obj
->intern
, r
, col
.num TSRMLS_CC
));
848 zend_restore_error_handling(&zeh TSRMLS_CC
);
853 static int apply_to_col(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
856 php_pqres_object_t
*obj
= va_arg(argv
, php_pqres_object_t
*);
857 php_pqres_col_t
*col
, **cols
= va_arg(argv
, php_pqres_col_t
**);
858 STATUS
*rv
= va_arg(argv
, STATUS
*);
862 if (SUCCESS
!= column_nn(obj
, *c
, col TSRMLS_CC
)) {
864 return ZEND_HASH_APPLY_STOP
;
868 return ZEND_HASH_APPLY_KEEP
;
872 static php_pqres_col_t
*php_pqres_convert_to_cols(php_pqres_object_t
*obj
, HashTable
*ht TSRMLS_DC
)
874 php_pqres_col_t
*tmp
, *cols
= ecalloc(zend_hash_num_elements(ht
), sizeof(*cols
));
878 zend_hash_apply_with_arguments(ht TSRMLS_CC
, apply_to_col
, 2, obj
, &tmp
, &rv
);
888 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_map
, 0, 0, 0)
889 ZEND_ARG_INFO(0, keys
)
890 ZEND_ARG_INFO(0, vals
)
891 ZEND_ARG_INFO(0, fetch_type
)
893 static PHP_METHOD(pqres
, map
) {
894 zend_error_handling zeh
;
895 zval
*zkeys
= 0, *zvals
= 0;
896 long fetch_type
= -1;
899 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
900 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|z/!z/!l", &zkeys
, &zvals
, &fetch_type
);
901 zend_restore_error_handling(&zeh TSRMLS_CC
);
904 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
907 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
910 php_pqres_col_t def
= {PQfname(obj
->intern
->res
, 0), 0}, *keys
= NULL
, *vals
= NULL
;
913 convert_to_array(zkeys
);
915 if ((ks
= zend_hash_num_elements(Z_ARRVAL_P(zkeys
)))) {
916 keys
= php_pqres_convert_to_cols(obj
, Z_ARRVAL_P(zkeys
) TSRMLS_CC
);
926 convert_to_array(zvals
);
928 if ((vs
= zend_hash_num_elements(Z_ARRVAL_P(zvals
)))) {
929 vals
= php_pqres_convert_to_cols(obj
, Z_ARRVAL_P(zvals
) TSRMLS_CC
);
933 if (fetch_type
== -1) {
934 fetch_type
= obj
->intern
->iter
? obj
->intern
->iter
->fetch_type
: obj
->intern
->default_fetch_type
;
941 switch (fetch_type
) {
942 case PHP_PQRES_FETCH_ARRAY
:
943 case PHP_PQRES_FETCH_ASSOC
:
944 array_init(return_value
);
946 case PHP_PQRES_FETCH_OBJECT
:
947 object_init(return_value
);
950 for (r
= 0, rows
= PQntuples(obj
->intern
->res
); r
< rows
; ++r
) {
954 for (k
= 0; k
< ks
; ++k
) {
955 char *key
= PQgetvalue(obj
->intern
->res
, r
, keys
[k
].num
);
956 int len
= PQgetlength(obj
->intern
->res
, r
, keys
[k
].num
);
958 if (SUCCESS
!= zend_symtable_find(HASH_OF(*cur
), key
, len
+ 1, (void *) &cur
)) {
962 switch (fetch_type
) {
963 case PHP_PQRES_FETCH_ARRAY
:
964 case PHP_PQRES_FETCH_ASSOC
:
967 case PHP_PQRES_FETCH_OBJECT
:
971 if (SUCCESS
!= zend_symtable_update(HASH_OF(*cur
), key
, len
+ 1, (void *) &tmp
, sizeof(zval
*), (void *) &cur
)) {
972 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to create map");
978 for (v
= 0; v
< vs
; ++v
) {
979 char *val
= PQgetvalue(obj
->intern
->res
, r
, vals
[v
].num
);
980 int len
= PQgetlength(obj
->intern
->res
, r
, vals
[v
].num
);
982 switch (fetch_type
) {
983 case PHP_PQRES_FETCH_ARRAY
:
984 add_index_stringl(*cur
, vals
[v
].num
, val
, len
, 1);
986 case PHP_PQRES_FETCH_ASSOC
:
987 add_assoc_stringl(*cur
, vals
[v
].name
, val
, len
, 1);
989 case PHP_PQRES_FETCH_OBJECT
:
990 add_property_stringl(*cur
, vals
[v
].name
, val
, len
, 1);
995 php_pqres_row_to_zval(obj
->intern
->res
, r
, fetch_type
, cur TSRMLS_CC
);
1001 if (keys
&& keys
!= &def
) {
1011 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all
, 0, 0, 0)
1012 ZEND_ARG_INFO(0, fetch_type
)
1013 ZEND_END_ARG_INFO();
1014 static PHP_METHOD(pqres
, fetchAll
) {
1015 zend_error_handling zeh
;
1016 long fetch_type
= -1;
1019 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
1020 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &fetch_type
);
1021 zend_restore_error_handling(&zeh TSRMLS_CC
);
1023 if (SUCCESS
== rv
) {
1024 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1026 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
1028 int r
, rows
= PQntuples(obj
->intern
->res
);
1030 if (fetch_type
== -1) {
1031 fetch_type
= obj
->intern
->iter
? obj
->intern
->iter
->fetch_type
: obj
->intern
->default_fetch_type
;
1034 array_init(return_value
);
1035 for (r
= 0; r
< rows
; ++r
) {
1036 add_next_index_zval(return_value
, php_pqres_row_to_zval(obj
->intern
->res
, r
, fetch_type
, NULL TSRMLS_CC
));
1042 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count
, 0, 0, 0)
1043 ZEND_END_ARG_INFO();
1044 static PHP_METHOD(pqres
, count
) {
1045 if (SUCCESS
== zend_parse_parameters_none()) {
1048 if (SUCCESS
!= php_pqres_count_elements(getThis(), &count TSRMLS_CC
)) {
1049 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
1056 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_desc
, 0, 0, 0)
1057 ZEND_END_ARG_INFO();
1058 static PHP_METHOD(pqres
, desc
) {
1059 if (SUCCESS
== zend_parse_parameters_none()) {
1060 php_pqres_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1063 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Result not initialized");
1067 array_init(return_value
);
1068 for (p
= 0, params
= PQnparams(obj
->intern
->res
); p
< params
; ++p
) {
1069 add_next_index_long(return_value
, PQparamtype(obj
->intern
->res
, p
));
1075 static zend_function_entry php_pqres_methods
[] = {
1076 PHP_ME(pqres
, bind
, ai_pqres_bind
, ZEND_ACC_PUBLIC
)
1077 PHP_ME(pqres
, fetchBound
, ai_pqres_fetch_bound
, ZEND_ACC_PUBLIC
)
1078 PHP_ME(pqres
, fetchRow
, ai_pqres_fetch_row
, ZEND_ACC_PUBLIC
)
1079 PHP_ME(pqres
, fetchCol
, ai_pqres_fetch_col
, ZEND_ACC_PUBLIC
)
1080 PHP_ME(pqres
, fetchAll
, ai_pqres_fetch_all
, ZEND_ACC_PUBLIC
)
1081 PHP_ME(pqres
, fetchAllCols
, ai_pqres_fetch_all_cols
, ZEND_ACC_PUBLIC
)
1082 PHP_ME(pqres
, count
, ai_pqres_count
, ZEND_ACC_PUBLIC
)
1083 PHP_ME(pqres
, map
, ai_pqres_map
, ZEND_ACC_PUBLIC
)
1084 PHP_ME(pqres
, desc
, ai_pqres_desc
, ZEND_ACC_PUBLIC
)
1088 PHP_MSHUTDOWN_FUNCTION(pqres
)
1090 zend_hash_destroy(&php_pqres_object_prophandlers
);
1094 PHP_MINIT_FUNCTION(pqres
)
1096 zend_class_entry ce
= {0};
1097 php_pq_object_prophandler_t ph
= {0};
1099 INIT_NS_CLASS_ENTRY(ce
, "pq", "Result", php_pqres_methods
);
1100 php_pqres_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
1101 php_pqres_class_entry
->create_object
= php_pqres_create_object
;
1102 php_pqres_class_entry
->iterator_funcs
.funcs
= &php_pqres_iterator_funcs
;
1103 php_pqres_class_entry
->get_iterator
= php_pqres_iterator_init
;
1104 zend_class_implements(php_pqres_class_entry TSRMLS_CC
, 2, zend_ce_traversable
, spl_ce_Countable
);
1106 memcpy(&php_pqres_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1107 php_pqres_object_handlers
.read_property
= php_pq_object_read_prop
;
1108 php_pqres_object_handlers
.write_property
= php_pq_object_write_prop
;
1109 php_pqres_object_handlers
.clone_obj
= NULL
;
1110 php_pqres_object_handlers
.get_property_ptr_ptr
= NULL
;
1111 php_pqres_object_handlers
.get_gc
= NULL
;
1112 php_pqres_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
1113 php_pqres_object_handlers
.get_properties
= php_pq_object_properties
;
1114 php_pqres_object_handlers
.count_elements
= php_pqres_count_elements
;
1116 zend_hash_init(&php_pqres_object_prophandlers
, 6, NULL
, NULL
, 1);
1118 zend_declare_property_null(php_pqres_class_entry
, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1119 ph
.read
= php_pqres_object_read_status
;
1120 zend_hash_add(&php_pqres_object_prophandlers
, "status", sizeof("status"), (void *) &ph
, sizeof(ph
), NULL
);
1122 zend_declare_property_null(php_pqres_class_entry
, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1123 ph
.read
= php_pqres_object_read_status_message
;
1124 zend_hash_add(&php_pqres_object_prophandlers
, "statusMessage", sizeof("statusMessage"), (void *) &ph
, sizeof(ph
), NULL
);
1126 zend_declare_property_null(php_pqres_class_entry
, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1127 ph
.read
= php_pqres_object_read_error_message
;
1128 zend_hash_add(&php_pqres_object_prophandlers
, "errorMessage", sizeof("errorMessage"), (void *) &ph
, sizeof(ph
), NULL
);
1130 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1131 ph
.read
= php_pqres_object_read_num_rows
;
1132 zend_hash_add(&php_pqres_object_prophandlers
, "numRows", sizeof("numRows"), (void *) &ph
, sizeof(ph
), NULL
);
1134 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1135 ph
.read
= php_pqres_object_read_num_cols
;
1136 zend_hash_add(&php_pqres_object_prophandlers
, "numCols", sizeof("numCols"), (void *) &ph
, sizeof(ph
), NULL
);
1138 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1139 ph
.read
= php_pqres_object_read_affected_rows
;
1140 zend_hash_add(&php_pqres_object_prophandlers
, "affectedRows", sizeof("affectedRows"), (void *) &ph
, sizeof(ph
), NULL
);
1142 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY
, ZEND_ACC_PUBLIC TSRMLS_CC
);
1143 ph
.read
= php_pqres_object_read_fetch_type
;
1144 ph
.write
= php_pqres_object_write_fetch_type
;
1145 zend_hash_add(&php_pqres_object_prophandlers
, "fetchType", sizeof("fetchType"), (void *) &ph
, sizeof(ph
), NULL
);
1148 zend_declare_property_long(php_pqres_class_entry
, ZEND_STRL("autoConvert"), PHP_PQRES_FETCH_ARRAY
, ZEND_ACC_PUBLIC TSRMLS_CC
);
1149 ph
.read
= php_pqres_object_read_auto_conv
;
1150 ph
.write
= php_pqres_object_write_auto_conv
;
1151 zend_hash_add(&php_pqres_object_prophandlers
, "autoConvert", sizeof("autoConvert"), (void *) &ph
, sizeof(ph
), NULL
);
1154 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC
);
1155 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC
);
1156 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC
);
1157 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC
);
1158 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC
);
1159 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC
);
1160 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC
);
1161 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC
);
1162 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC
);
1163 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC
);
1165 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC
);
1166 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC
);
1167 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC
);
1169 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_BOOL"), PHP_PQRES_CONV_BOOL TSRMLS_CC
);
1170 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_INT"), PHP_PQRES_CONV_INT TSRMLS_CC
);
1171 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_FLOAT"), PHP_PQRES_CONV_FLOAT TSRMLS_CC
);
1172 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR TSRMLS_CC
);
1173 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY TSRMLS_CC
);
1174 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME TSRMLS_CC
);
1175 zend_declare_class_constant_long(php_pqres_class_entry
, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL TSRMLS_CC
);
1185 * vim600: noet sw=4 ts=4 fdm=marker
1186 * vim<600: noet sw=4 ts=4