+typedef struct php_pqres_iterator {
+ zend_object_iterator zi;
+ zval *current_val;
+ unsigned index;
+ php_pqres_fetch_t fetch_type;
+} php_pqres_iterator_t;
+
+typedef struct php_pqres_object {
+ zend_object zo;
+ PGresult *res;
+ HashTable *prophandler;
+
+ php_pqres_iterator_t *iter;
+} php_pqres_object_t;
+
+typedef struct php_pqstm_object {
+ zend_object zo;
+ char *name;
+ HashTable *prophandler;
+
+ zval *conn;
+} php_pqstm_object_t;
+
+static HashTable php_pqconn_object_prophandlers;
+static HashTable php_pqres_object_prophandlers;
+static HashTable php_pqstm_object_prophandlers;
+
+typedef void (*php_pq_object_prophandler_func_t)(zval *object, void *o, zval *return_value TSRMLS_DC);
+
+typedef struct php_pq_object_prophandler {
+ php_pq_object_prophandler_func_t read;
+ php_pq_object_prophandler_func_t write;
+} php_pq_object_prophandler_t;
+
+static zend_object_iterator_funcs php_pqres_iterator_funcs;
+
+static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter;
+ zval *prop, *zfetch_type;
+
+ iter = ecalloc(1, sizeof(*iter));
+ iter->zi.funcs = &php_pqres_iterator_funcs;
+ iter->zi.data = object;
+ Z_ADDREF_P(object);
+
+ zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC);
+ if (Z_TYPE_P(zfetch_type) != IS_LONG) {
+ convert_to_long_ex(&zfetch_type);
+ }
+ iter->fetch_type = Z_LVAL_P(zfetch_type);
+ if (zfetch_type != prop) {
+ zval_ptr_dtor(&zfetch_type);
+ }
+ if (Z_REFCOUNT_P(prop)) {
+ zval_ptr_dtor(&prop);
+ } else {
+ zval_dtor(prop);
+ FREE_ZVAL(prop);
+ }
+
+ return (zend_object_iterator *) iter;
+}
+
+static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+
+ if (iter->current_val) {
+ zval_ptr_dtor(&iter->current_val);
+ iter->current_val = NULL;
+ }
+ zval_ptr_dtor((zval **) &iter->zi.data);
+ efree(iter);
+}
+
+static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+ php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
+
+ if (PQresultStatus(obj->res) != PGRES_TUPLES_OK) {
+ return FAILURE;
+ }
+ if (PQntuples(obj->res) <= iter->index) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+static zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type TSRMLS_DC)
+{
+ zval *data;
+ int c, cols;
+
+ MAKE_STD_ZVAL(data);
+ if (PHP_PQRES_FETCH_OBJECT == fetch_type) {
+ object_init(data);
+ } else {
+ array_init(data);
+ }
+
+ for (c = 0, cols = PQnfields(res); c < cols; ++c) {
+ if (PQgetisnull(res, row, c)) {
+ switch (fetch_type) {
+ case PHP_PQRES_FETCH_OBJECT:
+ add_property_null(data, PQfname(res, c));
+ break;
+
+ case PHP_PQRES_FETCH_ASSOC:
+ add_assoc_null(data, PQfname(res, c));
+ break;
+
+ case PHP_PQRES_FETCH_ARRAY:
+ add_index_null(data, c);
+ break;
+ }
+ } else {
+ char *val = PQgetvalue(res, row, c);
+ int len = PQgetlength(res, row, c);
+
+ switch (fetch_type) {
+ case PHP_PQRES_FETCH_OBJECT:
+ add_property_stringl(data, PQfname(res, c), val, len, 1);
+ break;
+
+ case PHP_PQRES_FETCH_ASSOC:
+ add_assoc_stringl(data, PQfname(res, c), val, len, 1);
+ break;
+
+ case PHP_PQRES_FETCH_ARRAY:
+ add_index_stringl(data, c, val, len ,1);
+ break;
+ }
+ }
+ }
+
+ return data;
+}
+
+static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+ php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
+
+ if (iter->current_val) {
+ zval_ptr_dtor(&iter->current_val);
+ }
+ iter->current_val = php_pqres_row_to_zval(obj->res, iter->index, iter->fetch_type TSRMLS_CC);
+ *data_ptr = &iter->current_val;
+}
+
+static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint *key_len, ulong *key_num TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+
+ *key_num = (ulong) iter->index;
+
+ return HASH_KEY_IS_LONG;
+}
+
+static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+
+ ++iter->index;
+}
+
+static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+
+ iter->index = 0;
+}
+
+static zend_object_iterator_funcs php_pqres_iterator_funcs = {
+ php_pqres_iterator_dtor,
+ /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
+ php_pqres_iterator_valid,
+ /* fetch the item data for the current element */
+ php_pqres_iterator_current,
+ /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
+ php_pqres_iterator_key,
+ /* step forwards to next element */
+ php_pqres_iterator_next,
+ /* rewind to start of data (optional, may be NULL) */
+ php_pqres_iterator_rewind,
+ /* invalidate current value/key (optional, may be NULL) */
+ NULL
+};
+
+static void php_pq_callback_dtor(php_pq_callback_t *cb) {
+ if (cb->fci.size > 0) {
+ zend_fcall_info_args_clear(&cb->fci, 1);
+ zval_ptr_dtor(&cb->fci.function_name);
+ if (cb->fci.object_ptr) {
+ zval_ptr_dtor(&cb->fci.object_ptr);
+ }
+ }
+ cb->fci.size = 0;
+}
+
+static void php_pq_callback_addref(php_pq_callback_t *cb)
+{
+ Z_ADDREF_P(cb->fci.function_name);
+ if (cb->fci.object_ptr) {
+ Z_ADDREF_P(cb->fci.object_ptr);
+ }
+}
+