package.xml0000644000076500000240000002704214560227740012017 0ustar mikestaff pq pecl.php.net PostgreSQL client library (libpq) binding Documents: https://mdref.m6w6.name/pq Highlights: * Nearly complete support for asynchronous usage: https://mdref.m6w6.name/pq/Connection/%3A%20Asynchronous%20Usage * Extended type support by pg_type: https://mdref.m6w6.name/pq/Types/%3A%20Overview * Fetching simple multi-dimensional array maps: https://mdref.m6w6.name/pq/Result/map * Working Gateway implementation: https://mdref.m6w6.name/pq-gateway Michael Wallner mike mike@php.net yes Chris Wright daverandom daverandom@php.net yes Remi Collet remi remi@php.net yes 2024-02-05 2.2.3 2.1.0 stable stable BSD-2-Clause * Fix incompatible pointer types (32-bit) (see hg issue #52) 7.0.0 1.10.0 raphf pecl.php.net 2.0.0 raphf pq pq-2.2.3/scripts/gen_pq_type.sh0000755000076500000240000000011514560227740015312 0ustar mikestaff#!/bin/sh CWD=$(dirname $0) $CWD/php_pq_type-pg11.php >$CWD/../php_pq_type.h pq-2.2.3/scripts/php_pq_type.awk0000755000076500000240000000203214560227740015500 0ustar mikestaff#!/usr/bin/awk -f BEGIN { printf "#ifndef PHP_PQ_TYPE\n" printf "# define PHP_PQ_TYPE(t,o)\n" printf "#endif\n" } END { printf "#ifndef PHP_PQ_TYPE_IS_ARRAY\n" printf "# define PHP_PQ_TYPE_IS_ARRAY(oid) (\\\n\t\t0 \\\n" for (oid in arrays) { printf "\t||\t((oid) == %d) \\\n", oid } printf ")\n#endif\n" printf "#ifndef PHP_PQ_TYPE_OF_ARRAY\n" printf "# define PHP_PQ_TYPE_OF_ARRAY(oid) (" for (oid in arrays) { printf "\\\n\t(oid) == %d ? %s : ", oid, arrays[oid] } printf "0 \\\n)\n#endif\n" printf "#ifndef PHP_PQ_DELIM_OF_ARRAY\n" printf "# define PHP_PQ_DELIM_OF_ARRAY(oid) (" for (oid in delims) { printf "\\\n\t(oid) == %d ? '%s' : ", oid, delims[oid] } printf "\\\n\t0 \\\n)\n#endif\n" } /^DATA/ { oid = $4 name = toupper($6) adelim = $15 atypoid = $17 if (sub("^_", "", name)) { arrays[oid] = atypoid name = name "ARRAY" } delims[oid] = adelim printf "#ifndef PHP_PQ_OID_%s\n", name printf "# define PHP_PQ_OID_%s %d\n", name, oid printf "#endif\n" printf "PHP_PQ_TYPE(\"%s\", %d)\n", name, oid } pq-2.2.3/src/php_pq_callback.c0000644000076500000240000000757614560227740015032 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "php_pq_callback.h" void php_pq_callback_dtor(php_pq_callback_t *cb) { if (cb->recursion) { php_pq_callback_dtor(cb->recursion); efree(cb->recursion); cb->recursion = NULL; } if (cb->fci.size > 0) { zend_fcall_info_args_clear(&cb->fci, 1); zval_ptr_dtor(&cb->fci.function_name); if (cb->fci.object) { zval tmp; ZVAL_OBJ(&tmp, cb->fci.object); zval_ptr_dtor(&tmp); } cb->fci.size = 0; } } void php_pq_callback_addref(php_pq_callback_t *cb) { Z_TRY_ADDREF(cb->fci.function_name); if (cb->fci.object) { #ifdef GC_ADDREF GC_ADDREF(cb->fci.object); #else ++GC_REFCOUNT(cb->fci.object); #endif } } zval *php_pq_callback_to_zval(php_pq_callback_t *cb, zval *tmp) { php_pq_callback_addref(cb); if (cb->fci.object) { zval zo; array_init_size(tmp, 2); ZVAL_OBJ(&zo, cb->fci.object); add_next_index_zval(tmp, &zo); add_next_index_zval(tmp, &cb->fci.function_name); return tmp; } return &cb->fci.function_name; } zval *php_pq_callback_to_zval_no_addref(php_pq_callback_t *cb, zval *tmp) { if (cb->fci.object) { zval zo; array_init_size(tmp, 2); ZVAL_OBJ(&zo, cb->fci.object); add_next_index_zval(tmp, &zo); add_next_index_zval(tmp, &cb->fci.function_name); return tmp; } return &cb->fci.function_name; } zend_bool php_pq_callback_is_locked(php_pq_callback_t *cb) { /* TODO: fixed in php7? if (php_pq_callback_is_enabled(cb)) { const zend_function *closure; const zend_execute_data *ex; if (Z_TYPE_P(cb->fci.function_name) != IS_OBJECT) { return 0; } closure = zend_get_closure_method_def(cb->fci.function_name); if (closure->type != ZEND_USER_FUNCTION) { return 0; } for (ex = EG(current_execute_data); ex; ex = ex->prev_execute_data) { if (ex->op_array == &closure->op_array) { return 1; } } } if (!php_pq_callback_is_recurrent(cb)) { return 0; } return php_pq_callback_is_locked(cb->recursion); */ return 0; } void php_pq_callback_recurse(php_pq_callback_t *old, php_pq_callback_t *new) { if (php_pq_callback_is_locked(old)) { php_pq_callback_recurse_ex(old, new); } else { php_pq_callback_dtor(old); if (php_pq_callback_is_enabled(new)) { php_pq_callback_addref(new); memcpy(old, new, sizeof(*old)); new->fci.size = 0; } } } extern zend_bool php_pq_callback_is_enabled(php_pq_callback_t *cb) { return cb && cb->fci.size > 0; } extern zend_bool php_pq_callback_is_recurrent(php_pq_callback_t *cb) { return cb && cb->recursion != NULL; } extern void php_pq_callback_disable(php_pq_callback_t *cb) { if (php_pq_callback_is_enabled(cb)) { php_pq_callback_recurse_ex(cb, NULL); } } extern void php_pq_callback_recurse_ex(php_pq_callback_t *old, php_pq_callback_t *new) { php_pq_callback_t *tmp = emalloc(sizeof(*tmp)); if (new) { memcpy(tmp, old, sizeof(*tmp)); memcpy(old, new, sizeof(*old)); old->recursion = tmp; php_pq_callback_addref(old); php_pq_callback_disable(tmp); } else { memcpy(tmp, old, sizeof(*tmp)); memset(old, 0, sizeof(*old)); old->recursion = tmp; } } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_callback.h0000644000076500000240000000342114560227740015020 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQ_CALLBACK_H #define PHP_PQ_CALLBACK_H #include typedef struct php_pq_callback { zend_fcall_info fci; zend_fcall_info_cache fcc; struct php_pq_callback *recursion; } php_pq_callback_t; #define PHP_PQ_CALLBACK_INIT {{0},{0},NULL} extern void php_pq_callback_dtor(php_pq_callback_t *cb); extern void php_pq_callback_addref(php_pq_callback_t *cb); extern zval *php_pq_callback_to_zval(php_pq_callback_t *cb, zval *tmp); extern zval *php_pq_callback_to_zval_no_addref(php_pq_callback_t *cb, zval *tmp); extern zend_bool php_pq_callback_is_locked(php_pq_callback_t *cb); extern void php_pq_callback_recurse(php_pq_callback_t *old, php_pq_callback_t *new); extern zend_bool php_pq_callback_is_enabled(php_pq_callback_t *cb); extern void php_pq_callback_disable(php_pq_callback_t *cb); extern void php_pq_callback_recurse_ex(php_pq_callback_t *old, php_pq_callback_t *new); extern zend_bool php_pq_callback_is_recurrent(php_pq_callback_t *cb); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqcancel.c0000644000076500000240000001335714560227740014356 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqcancel.h" zend_class_entry *php_pqcancel_class_entry; static zend_object_handlers php_pqcancel_object_handlers; static HashTable php_pqcancel_object_prophandlers; static void php_pqcancel_object_free(zend_object *o) { php_pqcancel_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE cancel(#%d) %p (conn(#%d): %p)\n", obj->zo.handle, obj, obj->intern->conn->zo.handle, obj->intern->conn); #endif if (obj->intern) { PQfreeCancel(obj->intern->cancel); php_pq_object_delref(obj->intern->conn); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqcancel_object_t *php_pqcancel_create_object_ex(zend_class_entry *ce, php_pqcancel_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqcancel_object_t), &php_pqcancel_object_handlers, &php_pqcancel_object_prophandlers); } static zend_object *php_pqcancel_create_object(zend_class_entry *class_type) { return &php_pqcancel_create_object_ex(class_type, NULL)->zo; } static void php_pqcancel_object_read_connection(void *o, zval *return_value) { php_pqcancel_object_t *obj = o; php_pq_object_to_zval(obj->intern->conn, return_value); } static void php_pqcancel_object_gc_connection(void *o, zval *return_value) { php_pqcancel_object_t *obj = o; zval zconn; php_pq_object_to_zval_no_addref(obj->intern->conn, &zconn); add_next_index_zval(return_value, &zconn); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_construct, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcancel, __construct) { zend_error_handling zeh; zval *zconn; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zconn, php_pqconn_class_entry); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = PHP_PQ_OBJ(zconn, NULL); if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGcancel *cancel = PQgetCancel(conn_obj->intern->conn); if (!cancel) { throw_exce(EX_RUNTIME, "Failed to acquire cancel (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } else { php_pqcancel_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->cancel = cancel; php_pq_object_addref(conn_obj); obj->intern->conn = conn_obj; } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_cancel, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcancel, cancel) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqcancel_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Cancel not initialized"); } else { char err[256] = {0}; if (!PQcancel(obj->intern->cancel, err, sizeof(err))) { throw_exce(EX_RUNTIME, "Failed to request cancellation (%s)", err); } } } } static zend_function_entry php_pqcancel_methods[] = { PHP_ME(pqcancel, __construct, ai_pqcancel_construct, ZEND_ACC_PUBLIC) PHP_ME(pqcancel, cancel, ai_pqcancel_cancel, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqcancel) { zend_hash_destroy(&php_pqcancel_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqcancel) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Cancel", php_pqcancel_methods); php_pqcancel_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqcancel_class_entry->create_object = php_pqcancel_create_object; memcpy(&php_pqcancel_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqcancel_object_handlers.offset = XtOffsetOf(php_pqcancel_object_t, zo); php_pqcancel_object_handlers.free_obj = php_pqcancel_object_free; php_pqcancel_object_handlers.read_property = php_pq_object_read_prop; php_pqcancel_object_handlers.write_property = php_pq_object_write_prop; php_pqcancel_object_handlers.clone_obj = NULL; php_pqcancel_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqcancel_object_handlers.get_gc = php_pq_object_get_gc; php_pqcancel_object_handlers.get_properties = php_pq_object_properties; php_pqcancel_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqcancel_object_prophandlers, 1, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqcancel_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC); ph.read = php_pqcancel_object_read_connection; ph.gc = php_pqcancel_object_gc_connection; zend_hash_str_add_mem(&php_pqcancel_object_prophandlers, ZEND_STRL("connection"), (void *) &ph, sizeof(ph)); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqcancel.h0000644000076500000240000000246214560227740014356 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQCANCEL_H #define PHP_PQCANCEL_H #include "php_pqconn.h" typedef struct php_pqcancel { PGcancel *cancel; php_pqconn_object_t *conn; } php_pqcancel_t; typedef struct php_pqcancel_object { PHP_PQ_OBJ_DECL(php_pqcancel_t *) } php_pqcancel_object_t; extern zend_class_entry *php_pqcancel_class_entry; extern php_pqcancel_object_t *php_pqcancel_create_object_ex(zend_class_entry *ce, php_pqcancel_t *intern); extern PHP_MINIT_FUNCTION(pqcancel); extern PHP_MSHUTDOWN_FUNCTION(pqcancel); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqconn.c0000644000076500000240000021036414560227740014063 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqconn.h" #include "php_pqconn_event.h" #include "php_pqres.h" #include "php_pqstm.h" #include "php_pqtxn.h" #include "php_pqcur.h" zend_class_entry *php_pqconn_class_entry; static zend_object_handlers php_pqconn_object_handlers; static HashTable php_pqconn_object_prophandlers; static void php_pq_callback_hash_dtor(zval *p) { php_pq_callback_dtor(Z_PTR_P(p)); efree(Z_PTR_P(p)); } /* static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, unsigned long id) { zval **evhs; if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) { zend_hash_index_del(Z_ARRVAL_PP(evhs), id); } } */ static zend_long php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, php_pq_callback_t *cb) { zend_long h; zval *zevhs; if (!(zevhs = zend_hash_str_find(&obj->intern->eventhandlers, type_str, type_len))) { HashTable *evhs; zval tmp; ALLOC_HASHTABLE(evhs); zend_hash_init(evhs, 1, NULL, php_pq_callback_hash_dtor, 0); ZVAL_ARR(&tmp, evhs); zevhs = zend_hash_str_add(&obj->intern->eventhandlers, type_str, type_len, &tmp); } php_pq_callback_addref(cb); h = zend_hash_next_free_element(Z_ARRVAL_P(zevhs)); zend_hash_index_update_mem(Z_ARRVAL_P(zevhs), h, (void *) cb, sizeof(*cb)); return h; } static void php_pqconn_object_free(zend_object *o) { php_pqconn_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE conn(#%d) %p\n", obj->zo.handle, obj); #endif if (obj->intern) { php_pq_callback_dtor(&obj->intern->onevent); php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn); php_resource_factory_dtor(&obj->intern->factory); zend_hash_destroy(&obj->intern->listeners); zend_hash_destroy(&obj->intern->statements); zend_hash_destroy(&obj->intern->converters); zend_hash_destroy(&obj->intern->eventhandlers); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqconn_object_t *php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqconn_object_t), &php_pqconn_object_handlers, &php_pqconn_object_prophandlers); } static zend_object *php_pqconn_create_object(zend_class_entry *class_type) { return &php_pqconn_create_object_ex(class_type, NULL)->zo; } static void php_pqconn_object_read_status(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(PQstatus(obj->intern->conn)); } static void php_pqconn_object_read_transaction_status(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(PQtransactionStatus(obj->intern->conn)); } static void php_pqconn_object_read_error_message(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *error = PHP_PQerrorMessage(obj->intern->conn); if (error) { RETVAL_STRING(error); } else { RETVAL_NULL(); } } static int apply_notify_listener(zval *p, void *arg) { php_pq_callback_t *listener = Z_PTR_P(p); PGnotify *nfy = arg; zval zpid, zchannel, zmessage; ZVAL_LONG(&zpid, nfy->be_pid); ZVAL_STRING(&zchannel, nfy->relname); ZVAL_STRING(&zmessage, nfy->extra); zend_fcall_info_argn(&listener->fci, 3, &zchannel, &zmessage, &zpid); zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL); zend_fcall_info_args_clear(&listener->fci, 0); zval_ptr_dtor(&zchannel); zval_ptr_dtor(&zmessage); zval_ptr_dtor(&zpid); return ZEND_HASH_APPLY_KEEP; } static int apply_notify_listeners(zval *p, int argc, va_list argv, zend_hash_key *key) { HashTable *listeners = Z_ARRVAL_P(p); PGnotify *nfy = va_arg(argv, PGnotify *); if (0 == fnmatch(key->key->val, nfy->relname, 0)) { zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy); } return ZEND_HASH_APPLY_KEEP; } void php_pqconn_notify_listeners(php_pqconn_object_t *obj) { PGnotify *nfy; while ((nfy = PQnotifies(obj->intern->conn))) { zend_hash_apply_with_arguments(&obj->intern->listeners, apply_notify_listeners, 1, nfy); PQfreemem(nfy); } } static void php_pqconn_object_read_busy(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(PQisBusy(obj->intern->conn)); } static void php_pqconn_object_read_encoding(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn))); } static void php_pqconn_object_write_encoding(void *o, zval *value) { php_pqconn_object_t *obj = o; zend_string *zenc = zval_get_string(value); if (0 > PQsetClientEncoding(obj->intern->conn, zenc->val)) { php_error(E_NOTICE, "Unrecognized encoding '%s'", zenc->val); } zend_string_release(zenc); } static void php_pqconn_object_read_unbuffered(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(obj->intern->unbuffered); } static void php_pqconn_object_write_unbuffered(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->unbuffered = z_is_true(value); } static void php_pqconn_object_read_nonblocking(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(PQisnonblocking(obj->intern->conn)); } static void php_pqconn_object_write_nonblocking(void *o, zval *value) { php_pqconn_object_t *obj = o; PQsetnonblocking(obj->intern->conn, z_is_true(value)); } static void php_pqconn_object_read_db(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *db = PQdb(obj->intern->conn); if (db) { RETVAL_STRING(db); } else { RETVAL_EMPTY_STRING(); } } static void php_pqconn_object_read_user(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *user = PQuser(obj->intern->conn); if (user) { RETVAL_STRING(user); } else { RETVAL_EMPTY_STRING(); } } static void php_pqconn_object_read_pass(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *pass = PQpass(obj->intern->conn); if (pass) { RETVAL_STRING(pass); } else { RETVAL_EMPTY_STRING(); } } static void php_pqconn_object_read_host(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *host = PQhost(obj->intern->conn); if (host) { RETVAL_STRING(host); } else { RETVAL_EMPTY_STRING(); } } static void php_pqconn_object_read_port(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *port = PQport(obj->intern->conn); if (port) { RETVAL_STRING(port); } else { RETVAL_EMPTY_STRING(); } } #if HAVE_PQCONNINFO static void php_pqconn_object_read_params(void *o, zval *return_value) { php_pqconn_object_t *obj = o; PQconninfoOption *ptr, *params = PQconninfo(obj->intern->conn); array_init(return_value); if (params) { for (ptr = params; ptr->keyword; ++ptr) { if (ptr->val) { add_assoc_string(return_value, ptr->keyword, ptr->val); } else { add_assoc_null(return_value, ptr->keyword); } } PQconninfoFree(params); } } #endif static void php_pqconn_object_read_options(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *options = PQoptions(obj->intern->conn); if (options) { RETVAL_STRING(options); } else { RETVAL_EMPTY_STRING(); } } static int apply_read_callback_ex(zval *p, void *arg) { HashTable *rv = arg; zval zcb; zend_hash_next_index_insert(rv, php_pq_callback_to_zval(Z_PTR_P(p), &zcb)); return ZEND_HASH_APPLY_KEEP; } static int apply_read_callbacks(zval *p, int argc, va_list argv, zend_hash_key *key) { HashTable *evhs = Z_ARRVAL_P(p), *rv = va_arg(argv, HashTable *); zval entry, *entry_ptr; array_init_size(&entry, zend_hash_num_elements(evhs)); if (key->key->len) { entry_ptr = zend_hash_add(rv, key->key, &entry); } else { entry_ptr = zend_hash_index_update(rv, key->h, &entry); } zend_hash_apply_with_argument(evhs, apply_read_callback_ex, Z_ARRVAL_P(entry_ptr)); return ZEND_HASH_APPLY_KEEP; } static void php_pqconn_object_read_event_handlers(void *o, zval *return_value) { php_pqconn_object_t *obj = o; array_init(return_value); zend_hash_apply_with_arguments(&obj->intern->eventhandlers, apply_read_callbacks, 1, Z_ARRVAL_P(return_value)); } static void php_pqconn_object_gc_event_handlers(void *o, zval *return_value) { php_pqconn_object_t *obj = o; zval *evhs; ZEND_HASH_FOREACH_VAL(&obj->intern->eventhandlers, evhs) { zval *evh; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(evhs), evh) { zval zcb; add_next_index_zval(return_value, php_pq_callback_to_zval_no_addref(Z_PTR_P(evh), &zcb)); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END(); } static void php_pqconn_object_read_listeners(void *o, zval *return_value) { php_pqconn_object_t *obj = o; array_init(return_value); zend_hash_apply_with_arguments(&obj->intern->listeners, apply_read_callbacks, 1, Z_ARRVAL_P(return_value)); } static void php_pqconn_object_gc_listeners(void *o, zval *return_value) { php_pqconn_object_t *obj = o; zval *listeners; ZEND_HASH_FOREACH_VAL(&obj->intern->listeners, listeners) { zval *listener; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(listeners), listener) { zval zcb; add_next_index_zval(return_value, php_pq_callback_to_zval_no_addref(Z_PTR_P(listener), &zcb)); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END(); } static void php_pqconn_object_read_converters(void *o, zval *return_value) { php_pqconn_object_t *obj = o; array_init(return_value); zend_hash_copy(Z_ARRVAL_P(return_value), &obj->intern->converters, zval_add_ref); } static void php_pqconn_object_gc_converters(void *o, zval *return_value) { php_pqconn_object_t *obj = o; zval *converter; ZEND_HASH_FOREACH_VAL(&obj->intern->converters, converter) { add_next_index_zval(return_value, converter); } ZEND_HASH_FOREACH_END(); } static void php_pqconn_object_read_def_fetch_type(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(obj->intern->default_fetch_type); } static void php_pqconn_object_write_def_fetch_type(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_fetch_type = zval_get_long(value) & 0x3; /* two bits only */ } static void php_pqconn_object_read_def_txn_isolation(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(obj->intern->default_txn_isolation); } static void php_pqconn_object_write_def_txn_isolation(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_txn_isolation = zval_get_long(value) & 0x3; /* two bits only */ } static void php_pqconn_object_read_def_txn_readonly(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(obj->intern->default_txn_readonly); } static void php_pqconn_object_write_def_txn_readonly(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_txn_readonly = z_is_true(value); } static void php_pqconn_object_read_def_txn_deferrable(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(obj->intern->default_txn_deferrable); } static void php_pqconn_object_write_def_txn_deferrable(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_txn_deferrable = zend_is_true(value); } static void php_pqconn_object_read_def_auto_conv(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(obj->intern->default_auto_convert); } static void php_pqconn_object_write_def_auto_conv(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_auto_convert = zval_get_long(value) & PHP_PQRES_CONV_ALL; } #ifdef HAVE_PQLIBVERSION static void php_pqconn_object_read_lib_version(void *o, zval *return_value) { char ver[16]; php_pq_version_to_string(PQlibVersion(), ver, sizeof(ver)); RETVAL_STRING(ver); } #endif #ifdef HAVE_PQPROTOCOLVERSION static void php_pqconn_object_read_protocol_version(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(PQprotocolVersion(obj->intern->conn)); } #endif #ifdef HAVE_PQSERVERVERSION static void php_pqconn_object_read_server_version(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char ver[16]; php_pq_version_to_string(PQserverVersion(obj->intern->conn), ver, sizeof(ver)); RETVAL_STRING(ver); } #endif static ZEND_RESULT_CODE php_pqconn_update_socket(zval *zobj, php_pqconn_object_t *obj) { zval zsocket, zmember; php_stream *stream; ZEND_RESULT_CODE retval; int socket; if (!obj) { obj = PHP_PQ_OBJ(zobj, NULL); } ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1); if ((CONNECTION_BAD != PQstatus(obj->intern->conn)) && (-1 < (socket = PQsocket(obj->intern->conn))) && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) { stream->flags |= PHP_STREAM_FLAG_NO_CLOSE; php_stream_to_zval(stream, &zsocket); retval = SUCCESS; } else { ZVAL_NULL(&zsocket); retval = FAILURE; } #if PHP_VERSION_ID >= 80000 zend_std_write_property(Z_OBJ_P(zobj), Z_STR(zmember), &zsocket, NULL); #else zend_std_write_property(zobj, &zmember, &zsocket, NULL); #endif zval_ptr_dtor(&zsocket); zval_ptr_dtor(&zmember); return retval; } static void *php_pqconn_resource_factory_ctor(void *data, void *init_arg) { php_pqconn_resource_factory_data_t *o = init_arg; PGconn *conn = NULL;; if (o->flags & PHP_PQCONN_ASYNC) { conn = PQconnectStart(o->dsn); } else { conn = PQconnectdb(o->dsn); } if (conn) { PQregisterEventProc(conn, php_pqconn_event, "ext-pq", NULL); } return conn; } static void php_pqconn_resource_factory_dtor(void *opaque, void *handle) { php_pqconn_event_data_t *evdata = PQinstanceData(handle, php_pqconn_event); /* we don't care for anything, except free'ing evdata */ if (evdata) { PQsetInstanceData(handle, php_pqconn_event, NULL); memset(evdata, 0, sizeof(*evdata)); efree(evdata); } PQfinish(handle); } static php_resource_factory_ops_t php_pqconn_resource_factory_ops = { php_pqconn_resource_factory_ctor, NULL, php_pqconn_resource_factory_dtor }; php_resource_factory_ops_t *php_pqconn_get_resource_factory_ops(void) { return &php_pqconn_resource_factory_ops; } static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle) { PGresult *res = PQexec(*handle, ""); php_pqres_clear(res); if (CONNECTION_OK != PQstatus(*handle)) { PQreset(*handle); } } static inline PGresult *unlisten(PGconn *conn, const char *channel_str, size_t channel_len) { char *quoted_channel = PQescapeIdentifier(conn, channel_str, channel_len); PGresult *res = NULL; if (quoted_channel) { smart_str cmd = {0}; smart_str_appends(&cmd, "UNLISTEN "); smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); res = php_pq_exec(conn, smart_str_v(&cmd)); smart_str_free(&cmd); PQfreemem(quoted_channel); } return res; } static int apply_unlisten(zval *p, int argc, va_list argv, zend_hash_key *key) { php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *); PGresult *res = unlisten(obj->intern->conn, key->key->val, key->key->len); if (res) { php_pqres_clear(res); } return ZEND_HASH_APPLY_REMOVE; } static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle) { php_pqconn_event_data_t *evdata = PQinstanceData(*handle, php_pqconn_event); PGcancel *cancel; PGresult *res; /* go away */ PQsetInstanceData(*handle, php_pqconn_event, NULL); /* ignore notices */ PQsetNoticeReceiver(*handle, php_pqconn_notice_ignore, NULL); /* cancel async queries */ if (PQisBusy(*handle) && (cancel = PQgetCancel(*handle))) { char err[256] = {0}; PQcancel(cancel, err, sizeof(err)); PQfreeCancel(cancel); } /* clean up async results */ while ((res = PQgetResult(*handle))) { php_pqres_clear(res); } /* clean up transaction & session */ switch (PQtransactionStatus(*handle)) { case PQTRANS_IDLE: res = PQexec(*handle, "RESET ALL"); break; default: res = PQexec(*handle, "ROLLBACK; RESET ALL"); break; } if (res) { php_pqres_clear(res); } if (evdata) { /* clean up notify listeners */ zend_hash_apply_with_arguments(&evdata->obj->intern->listeners, apply_unlisten, 1, evdata->obj); /* release instance data */ efree(evdata); } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1) ZEND_ARG_INFO(0, dsn) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, __construct) { zend_error_handling zeh; char *dsn_str = ""; size_t dsn_len = 0; zend_long flags = 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &dsn_str, &dsn_len, &flags); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (obj->intern) { throw_exce(EX_BAD_METHODCALL, "pq\\Connection already initialized"); } else { php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj); php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags}; obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->default_auto_convert = PHP_PQRES_CONV_ALL; zend_hash_init(&obj->intern->listeners, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&obj->intern->statements, 0, NULL, NULL, 0); zend_hash_init(&obj->intern->converters, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0); if (flags & PHP_PQCONN_PERSISTENT) { zend_string *dsn = zend_string_init(dsn_str, dsn_len, 0); php_persistent_handle_factory_t *phf = php_persistent_handle_concede(NULL, PHP_PQ_G->connection.name, dsn, php_pqconn_wakeup, php_pqconn_retire); php_persistent_handle_resource_factory_init(&obj->intern->factory, phf); zend_string_release(dsn); } else { php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL); } if (flags & PHP_PQCONN_ASYNC) { obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll; } obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata); PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata); PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata); if (SUCCESS != php_pqconn_update_socket(getThis(), obj)) { throw_exce(EX_CONNECTION_FAILED, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn)); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, reset) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PQreset(obj->intern->conn); if (CONNECTION_OK != PQstatus(obj->intern->conn)) { throw_exce(EX_CONNECTION_FAILED, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn)); } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, resetAsync) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { if (!PQresetStart(obj->intern->conn)) { throw_exce(EX_IO, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { obj->intern->poller = (int (*)(PGconn*)) PQresetPoll; } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unlisten, 0, 0, 1) ZEND_ARG_INFO(0, channel) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, unlisten) { zend_error_handling zeh; char *channel_str; size_t channel_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &channel_str, &channel_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else if (SUCCESS == zend_hash_str_del(&obj->intern->listeners, channel_str, channel_len)) { PGresult *res = unlisten(obj->intern->conn, channel_str, channel_len); if (res) { php_pqres_success(res); php_pqres_clear(res); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unlisten_async, 0, 0, 1) ZEND_ARG_INFO(0, channel) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, unlistenAsync) { zend_error_handling zeh; char *channel_str; size_t channel_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &channel_str, &channel_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len); if (!quoted_channel) { throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { smart_str cmd = {0}; smart_str_appends(&cmd, "UNLISTEN "); smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); if (!PQsendQuery(obj->intern->conn, smart_str_v(&cmd))) { throw_exce(EX_IO, "Failed to uninstall listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { obj->intern->poller = PQconsumeInput; zend_hash_str_del(&obj->intern->listeners, channel_str, channel_len); } smart_str_free(&cmd); PQfreemem(quoted_channel); php_pqconn_notify_listeners(obj); } } } } static void php_pqconn_add_listener(php_pqconn_object_t *obj, const char *channel_str, size_t channel_len, php_pq_callback_t *listener) { zval *existing; php_pq_callback_addref(listener); if ((existing = zend_hash_str_find(&obj->intern->listeners, channel_str, channel_len))) { zend_hash_next_index_insert_mem(Z_ARRVAL_P(existing), (void *) listener, sizeof(*listener)); } else { zval tmp; HashTable *ht; ALLOC_HASHTABLE(ht); zend_hash_init(ht, 0, NULL, php_pq_callback_hash_dtor, 0); zend_hash_next_index_insert_mem(ht, (void *) listener, sizeof(*listener)); ZVAL_ARR(&tmp, ht); zend_hash_str_add(&obj->intern->listeners, channel_str, channel_len, &tmp); } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 2) ZEND_ARG_INFO(0, channel) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, listen) { zend_error_handling zeh; char *channel_str = NULL; size_t channel_len = 0; php_pq_callback_t listener = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len); if (!quoted_channel) { throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { PGresult *res; smart_str cmd = {0}; smart_str_appends(&cmd, "LISTEN "); smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); res = php_pq_exec(obj->intern->conn, smart_str_v(&cmd)); smart_str_free(&cmd); PQfreemem(quoted_channel); if (!res) { throw_exce(EX_RUNTIME, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { obj->intern->poller = PQconsumeInput; php_pqconn_add_listener(obj, channel_str, channel_len, &listener); } php_pqres_clear(res); } php_pqconn_notify_listeners(obj); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async, 0, 0, 0) ZEND_ARG_INFO(0, channel) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, listenAsync) { zend_error_handling zeh; char *channel_str = NULL; size_t channel_len = 0; php_pq_callback_t listener = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len); if (!quoted_channel) { throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { smart_str cmd = {0}; smart_str_appends(&cmd, "LISTEN "); smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); if (!PQsendQuery(obj->intern->conn, smart_str_v(&cmd))) { throw_exce(EX_IO, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { obj->intern->poller = PQconsumeInput; php_pqconn_add_listener(obj, channel_str, channel_len, &listener); } smart_str_free(&cmd); PQfreemem(quoted_channel); php_pqconn_notify_listeners(obj); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2) ZEND_ARG_INFO(0, channel) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, notify) { zend_error_handling zeh; char *channel_str, *message_str; size_t channel_len, message_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &channel_str, &channel_len, &message_str, &message_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res; char *params[2] = {channel_str, message_str}; res = php_pq_exec_params(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0); if (!res) { throw_exce(EX_RUNTIME, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { php_pqres_success(res); php_pqres_clear(res); } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async, 0, 0, 2) ZEND_ARG_INFO(0, channel) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, notifyAsync) { zend_error_handling zeh; char *channel_str, *message_str; size_t channel_len, message_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &channel_str, &channel_len, &message_str, &message_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *params[2] = {channel_str, message_str}; if (!PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) { throw_exce(EX_IO, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { obj->intern->poller = PQconsumeInput; } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, poll) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else if (!obj->intern->poller) { throw_exce(EX_RUNTIME, "No asynchronous operation active"); } else { if (obj->intern->poller == PQconsumeInput) { RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK); } else { RETVAL_LONG(obj->intern->poller(obj->intern->conn)); } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_flush, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, flush) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else if (!obj->intern->poller) { throw_exce(EX_RUNTIME, "No asynchronous operation active"); } else { switch (PQflush(obj->intern->conn)) { case -1: default: throw_exce(EX_RUNTIME, "Failed to flush connection: %s", PHP_PQerrorMessage(obj->intern->conn)); break; case 0: RETVAL_TRUE; break; case 1: RETVAL_FALSE; break; } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1) ZEND_ARG_INFO(0, query) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, exec) { zend_error_handling zeh; char *query_str; size_t query_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query_str, &query_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res = php_pq_exec(obj->intern->conn, query_str); if (!res) { throw_exce(EX_RUNTIME, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else if (SUCCESS == php_pqres_success(res)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); } else { php_pqres_clear(res); } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, getResult) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res = PQgetResult(obj->intern->conn); php_pq_object_t *res_obj; if (res && (res_obj = PQresultInstanceData(res, php_pqconn_event))) { php_pq_object_to_zval_no_addref(res_obj, return_value); } else { RETVAL_NULL(); } php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1) ZEND_ARG_INFO(0, query) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, execAsync) { zend_error_handling zeh; php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; char *query_str; size_t query_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else if (!PQsendQuery(obj->intern->conn, query_str)) { throw_exce(EX_IO, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); #if HAVE_PQSETSINGLEROWMODE } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { throw_exce(EX_RUNTIME, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); #endif } else { php_pq_callback_recurse(&obj->intern->onevent, &resolver); obj->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2) ZEND_ARG_INFO(0, query) ZEND_ARG_ARRAY_INFO(0, params, 0) ZEND_ARG_ARRAY_INFO(0, types, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, execParams) { zend_error_handling zeh; char *query_str; size_t query_len; zval *zparams; zval *ztypes = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sa/|a/!", &query_str, &query_len, &zparams, &ztypes); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res; php_pq_params_t *params; params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams)); res = php_pq_exec_params(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); php_pq_params_free(¶ms); if (!res) { throw_exce(EX_RUNTIME, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); } else { php_pqres_clear(res); } php_pqconn_notify_listeners(obj); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2) ZEND_ARG_INFO(0, query) ZEND_ARG_ARRAY_INFO(0, params, 0) ZEND_ARG_ARRAY_INFO(0, types, 1) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, execParamsAsync) { zend_error_handling zeh; php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; char *query_str; size_t query_len; zval *zparams; zval *ztypes = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { int rc; php_pq_params_t *params; params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams)); rc = PQsendQueryParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); php_pq_params_free(¶ms); if (!rc) { throw_exce(EX_IO, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); #if HAVE_PQSETSINGLEROWMODE } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { throw_exce(EX_RUNTIME, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); #endif } else { php_pq_callback_recurse(&obj->intern->onevent, &resolver); obj->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj); } } } zend_restore_error_handling(&zeh); } ZEND_RESULT_CODE php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params) { PGresult *res; ZEND_RESULT_CODE rv; if (!obj) { obj = PHP_PQ_OBJ(object, NULL); } res = php_pq_prepare(obj->intern->conn, name, query, params->type.count, params->type.oids); if (!res) { rv = FAILURE; throw_exce(EX_RUNTIME, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = php_pqres_success(res); php_pqres_clear(res); php_pqconn_notify_listeners(obj); } return rv; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, query) ZEND_ARG_ARRAY_INFO(0, types, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, prepare) { zend_error_handling zeh; zval *ztypes = NULL; char *name_str, *query_str; size_t name_len, *query_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL); if (SUCCESS != php_pqconn_prepare(getThis(), obj, name_str, query_str, params)) { php_pq_params_free(¶ms); } else { php_pqstm_t *stm = php_pqstm_init(obj, name_str, query_str, params); RETVAL_OBJ(&php_pqstm_create_object_ex(php_pqstm_class_entry, stm)->zo); } } } } ZEND_RESULT_CODE php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params) { ZEND_RESULT_CODE rv; if (!obj) { obj = PHP_PQ_OBJ(object, NULL); } if (!PQsendPrepare(obj->intern->conn, name, query, params->type.count, params->type.oids)) { rv = FAILURE; throw_exce(EX_IO, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = SUCCESS; obj->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj); } return rv; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, query) ZEND_ARG_ARRAY_INFO(0, types, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, prepareAsync) { zend_error_handling zeh; zval *ztypes = NULL; char *name_str, *query_str; size_t name_len, *query_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL); if (SUCCESS != php_pqconn_prepare_async(getThis(), obj, name_str, query_str, params)) { php_pq_params_free(¶ms); } else { php_pqstm_t *stm = php_pqstm_init(obj, name_str, query_str, params); RETVAL_OBJ(&php_pqstm_create_object_ex(php_pqstm_class_entry, stm)->zo); } } } } ZEND_RESULT_CODE php_pqconn_declare(zval *object, php_pqconn_object_t *obj, const char *decl) { PGresult *res; ZEND_RESULT_CODE rv; if (!obj) { obj = PHP_PQ_OBJ(object, NULL); } res = php_pq_exec(obj->intern->conn, decl); if (!res) { rv = FAILURE; throw_exce(EX_RUNTIME, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = php_pqres_success(res); php_pqres_clear(res); php_pqconn_notify_listeners(obj); } return rv; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare, 0, 0, 3) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, flags) ZEND_ARG_INFO(0, query) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, declare) { zend_error_handling zeh; char *name_str, *query_str; size_t name_len, query_len; zend_long flags; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &name_str, &name_len, &flags, &query_str, &query_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { int query_offset; char *decl = php_pqcur_declare_str(name_str, name_len, flags, query_str, query_len, &query_offset); if (SUCCESS != php_pqconn_declare(getThis(), obj, decl)) { efree(decl); } else { php_pqcur_t *cur = php_pqcur_init(obj, name_str, decl, query_offset, flags); RETVAL_OBJ(&php_pqcur_create_object_ex(php_pqcur_class_entry, cur)->zo); } } } } ZEND_RESULT_CODE php_pqconn_declare_async(zval *object, php_pqconn_object_t *obj, const char *decl) { ZEND_RESULT_CODE rv; if (!obj) { obj = PHP_PQ_OBJ(object, NULL); } if (!PQsendQuery(obj->intern->conn, decl)) { rv = FAILURE; throw_exce(EX_IO, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = SUCCESS; obj->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj); } return rv; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare_async, 0, 0, 2) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, flags) ZEND_ARG_INFO(0, query) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, declareAsync) { zend_error_handling zeh; char *name_str, *query_str; size_t name_len, query_len; zend_long flags; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &name_str, &name_len, &flags, &query_str, &query_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { int query_offset; char *decl = php_pqcur_declare_str(name_str, name_len, flags, query_str, query_len, &query_offset); if (SUCCESS != php_pqconn_declare_async(getThis(), obj, decl)) { efree(decl); } else { php_pqcur_t *cur = php_pqcur_init(obj, name_str, decl, query_offset, flags); RETVAL_OBJ(&php_pqcur_create_object_ex(php_pqcur_class_entry, cur)->zo); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1) ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, quote) { char *str; size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *quoted = PQescapeLiteral(obj->intern->conn, str, len); if (!quoted) { php_error_docref(NULL, E_WARNING, "Failed to quote string (%s)", PHP_PQerrorMessage(obj->intern->conn)); RETVAL_FALSE; } else { RETVAL_STRING(quoted); PQfreemem(quoted); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, quoteName) { char *str; size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *quoted = PQescapeIdentifier(obj->intern->conn, str, len); if (!quoted) { php_error_docref(NULL, E_WARNING, "Failed to quote name (%s)", PHP_PQerrorMessage(obj->intern->conn)); RETVAL_FALSE; } else { RETVAL_STRING(quoted); PQfreemem(quoted); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1) ZEND_ARG_INFO(0, bytea) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, escapeBytea) { char *str; size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { size_t escaped_len; char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len); if (!escaped_str) { php_error_docref(NULL, E_WARNING, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn)); RETVAL_FALSE; } else { RETVAL_STRINGL(escaped_str, escaped_len - 1); PQfreemem(escaped_str); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1) ZEND_ARG_INFO(0, bytea) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, unescapeBytea) { char *str; size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { size_t unescaped_len; char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len); if (!unescaped_str) { php_error_docref(NULL, E_WARNING, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn)); RETVAL_FALSE; } else { RETVAL_STRINGL(unescaped_str, unescaped_len); PQfreemem(unescaped_str); } } } } ZEND_RESULT_CODE php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable) { ZEND_RESULT_CODE rv = FAILURE; if (!conn_obj) { conn_obj = PHP_PQ_OBJ(zconn, NULL); } if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res; smart_str cmd = {0}; const char *il = php_pq_isolation_level(&isolation); smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL "); smart_str_appends(&cmd, il); smart_str_appends(&cmd, ", READ "); smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE"); smart_str_appends(&cmd, ","); smart_str_appends(&cmd, deferrable ? "" : " NOT"); smart_str_appends(&cmd, " DEFERRABLE"); smart_str_0(&cmd); res = php_pq_exec(conn_obj->intern->conn, smart_str_v(&cmd)); if (!res) { throw_exce(EX_RUNTIME, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } else { rv = php_pqres_success(res); php_pqres_clear(res); php_pqconn_notify_listeners(conn_obj); } smart_str_free(&cmd); } return rv; } ZEND_RESULT_CODE php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable) { ZEND_RESULT_CODE rv = FAILURE; if (!conn_obj) { conn_obj = PHP_PQ_OBJ(zconn, NULL); } if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { smart_str cmd = {0}; const char *il = php_pq_isolation_level(&isolation); smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL "); smart_str_appends(&cmd, il); smart_str_appends(&cmd, ", READ "); smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE"); smart_str_appends(&cmd, ","); smart_str_appends(&cmd, deferrable ? "" : "NOT "); smart_str_appends(&cmd, " DEFERRABLE"); smart_str_0(&cmd); if (!PQsendQuery(conn_obj->intern->conn, smart_str_v(&cmd))) { throw_exce(EX_IO, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } else { rv = SUCCESS; conn_obj->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(conn_obj); } smart_str_free(&cmd); } return rv; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0) ZEND_ARG_INFO(0, isolation) ZEND_ARG_INFO(0, readonly) ZEND_ARG_INFO(0, deferrable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, startTransaction) { zend_error_handling zeh; php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); zend_long isolation = obj->intern ? obj->intern->default_txn_isolation : PHP_PQTXN_READ_COMMITTED; zend_bool readonly = obj->intern ? obj->intern->default_txn_readonly : 0; zend_bool deferrable = obj->intern ? obj->intern->default_txn_deferrable : 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|lbb", &isolation, &readonly, &deferrable); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable); if (SUCCESS == rv) { php_pqtxn_t *txn = ecalloc(1, sizeof(*txn)); php_pq_object_addref(obj); txn->conn = obj; txn->open = 1; txn->isolation = isolation; txn->readonly = readonly; txn->deferrable = deferrable; RETVAL_OBJ(&php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn)->zo); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0) ZEND_ARG_INFO(0, isolation) ZEND_ARG_INFO(0, readonly) ZEND_ARG_INFO(0, deferrable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, startTransactionAsync) { zend_error_handling zeh; php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); zend_long isolation = obj->intern ? obj->intern->default_txn_isolation : PHP_PQTXN_READ_COMMITTED; zend_bool readonly = obj->intern ? obj->intern->default_txn_readonly : 0; zend_bool deferrable = obj->intern ? obj->intern->default_txn_deferrable : 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|lbb", &isolation, &readonly, &deferrable); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable); if (SUCCESS == rv) { php_pqtxn_t *txn = ecalloc(1, sizeof(*txn)); php_pq_object_addref(obj); txn->conn = obj; txn->open = 1; txn->isolation = isolation; txn->readonly = readonly; txn->deferrable = deferrable; RETVAL_OBJ(&php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn)->zo); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0) ZEND_ARG_INFO(0, stdio_stream) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, trace) { zval *zstream = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &zstream)) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { if (!zstream) { PQuntrace(obj->intern->conn); RETVAL_TRUE; } else { FILE *fp; php_stream *stream = NULL; php_stream_from_zval(stream, zstream); if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) { RETVAL_FALSE; } else { stream->flags |= PHP_STREAM_FLAG_NO_CLOSE; PQtrace(obj->intern->conn, fp); RETVAL_TRUE; } } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_off, 0, 0, 1) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, off) { zend_error_handling zeh; zend_string *type; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "S", &type); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { RETURN_BOOL(SUCCESS == zend_hash_del(&obj->intern->eventhandlers, type)); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_on, 0, 0, 2) ZEND_ARG_INFO(0, type) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, on) { zend_error_handling zeh; char *type_str; size_t type_len; php_pq_callback_t cb = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &type_str, &type_len, &cb.fci, &cb.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { RETVAL_LONG(php_pqconn_add_eventhandler(obj, type_str, type_len, &cb)); } } } struct apply_set_converter_arg { HashTable *ht; zval *zconv; unsigned add:1; }; static int apply_set_converter(zval *zoid, void *a) { zend_long oid = zval_get_long(zoid); struct apply_set_converter_arg *arg = a; if (arg->add) { Z_ADDREF_P(arg->zconv); zend_hash_index_update(arg->ht, oid, arg->zconv); } else { zend_hash_index_del(arg->ht, oid); } return ZEND_HASH_APPLY_KEEP; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_set_converter, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, converter, pq\\Converter, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, setConverter) { ZEND_RESULT_CODE rv; zend_error_handling zeh; zval *zcnv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcnv, php_pqconv_class_entry); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { zval tmp, zoids; struct apply_set_converter_arg arg = {NULL}; ZVAL_NULL(&zoids); php_pq_call_method(zcnv, "converttypes", 0, &zoids); ZVAL_DUP(&tmp, &zoids); convert_to_array(&tmp); arg.ht = &obj->intern->converters; arg.zconv = zcnv; arg.add = 1; zend_hash_apply_with_argument(Z_ARRVAL(tmp), apply_set_converter, &arg); zval_ptr_dtor(&tmp); zval_ptr_dtor(&zoids); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unset_converter, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, converter, pq\\Converter, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, unsetConverter) { ZEND_RESULT_CODE rv; zend_error_handling zeh; zval *zcnv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcnv, php_pqconv_class_entry); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { zval tmp, zoids; struct apply_set_converter_arg arg = {NULL}; ZVAL_NULL(&zoids); php_pq_call_method(zcnv, "converttypes", 0, &zoids); ZVAL_DUP(&tmp, &zoids); convert_to_array(&tmp); arg.ht = &obj->intern->converters; arg.zconv = zcnv; arg.add = 0; zend_hash_apply_with_argument(Z_ARRVAL(tmp), apply_set_converter, &arg); zval_ptr_dtor(&tmp); zval_ptr_dtor(&zoids); } } } static zend_function_entry php_pqconn_methods[] = { PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC) PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC) PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC) PHP_ME(pqconn, flush, ai_pqconn_flush, ZEND_ACC_PUBLIC) PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC) PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC) PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC) PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, declare, ai_pqconn_declare, ZEND_ACC_PUBLIC) PHP_ME(pqconn, declareAsync, ai_pqconn_declare_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, unlisten, ai_pqconn_unlisten, ZEND_ACC_PUBLIC) PHP_ME(pqconn, unlistenAsync, ai_pqconn_unlisten_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC) PHP_ME(pqconn, listenAsync, ai_pqconn_listen_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC) PHP_ME(pqconn, notifyAsync, ai_pqconn_notify_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC) PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC) PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC) PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC) PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC) PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC) PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC) PHP_ME(pqconn, off, ai_pqconn_off, ZEND_ACC_PUBLIC) PHP_ME(pqconn, on, ai_pqconn_on, ZEND_ACC_PUBLIC) PHP_ME(pqconn, setConverter, ai_pqconn_set_converter, ZEND_ACC_PUBLIC) PHP_ME(pqconn, unsetConverter, ai_pqconn_unset_converter, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqconn) { php_persistent_handle_cleanup(PHP_PQ_G->connection.name, NULL); zend_string_release(PHP_PQ_G->connection.name); zend_hash_destroy(&php_pqconn_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqconn) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods); php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqconn_class_entry->create_object = php_pqconn_create_object; memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqconn_object_handlers.offset = XtOffsetOf(php_pqconn_object_t, zo); php_pqconn_object_handlers.free_obj = php_pqconn_object_free; php_pqconn_object_handlers.read_property = php_pq_object_read_prop; php_pqconn_object_handlers.write_property = php_pq_object_write_prop; php_pqconn_object_handlers.clone_obj = NULL; php_pqconn_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqconn_object_handlers.get_gc = php_pq_object_get_gc; php_pqconn_object_handlers.get_properties = php_pq_object_properties; php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqconn_object_prophandlers, 23, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_status; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "status", sizeof("status")-1, (void *) &ph, sizeof(ph)); zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_transaction_status; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC); ph.read = NULL; /* forward to std prophandler */ zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "socket", sizeof("socket")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_error_message; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage")-1, (void *) &ph, sizeof(ph)); zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_busy; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "busy", sizeof("busy")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_encoding; ph.write = php_pqconn_object_write_encoding; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_unbuffered; ph.write = php_pqconn_object_write_unbuffered; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("nonblocking"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_nonblocking; ph.write = php_pqconn_object_write_nonblocking; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "nonblocking", sizeof("nonblocking")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_db; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "db", sizeof("db")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_user; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "user", sizeof("user")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_pass; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "pass", sizeof("pass")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_host; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "host", sizeof("host")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_port; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "port", sizeof("port")-1, (void *) &ph, sizeof(ph)); #if HAVE_PQCONNINFO zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_params; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "params", sizeof("params")-1, (void *) &ph, sizeof(ph)); #endif zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_options; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "options", sizeof("options")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_event_handlers; ph.gc = php_pqconn_object_gc_event_handlers; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("listeners"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_listeners; ph.gc = php_pqconn_object_gc_listeners; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "listeners", sizeof("listeners")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("converters"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_converters; ph.gc = php_pqconn_object_gc_converters; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "converters", sizeof("converters")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultFetchType"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_fetch_type; ph.write = php_pqconn_object_write_def_fetch_type; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultFetchType", sizeof("defaultFetchType")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultTransactionIsolation"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_txn_isolation; ph.write = php_pqconn_object_write_def_txn_isolation; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionIsolation", sizeof("defaultTransactionIsolation")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("defaultTransactionReadonly"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_txn_readonly; ph.write = php_pqconn_object_write_def_txn_readonly; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionReadonly", sizeof("defaultTransactionReadonly")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("defaultTransactionDeferrable"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_txn_deferrable; ph.write = php_pqconn_object_write_def_txn_deferrable; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionDeferrable", sizeof("defaultTransactionDeferrable")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultAutoConvert"), PHP_PQRES_CONV_ALL, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_auto_conv; ph.write = php_pqconn_object_write_def_auto_conv; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultAutoConvert", sizeof("defaultAutoConvert")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; #ifdef HAVE_PQLIBVERSION zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("libraryVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY); ph.read = php_pqconn_object_read_lib_version; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("libraryVersion"), (void *) &ph, sizeof(ph)); #endif #ifdef HAVE_PQPROTOCOLVERSION zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("protocolVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY); ph.read = php_pqconn_object_read_protocol_version; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("protocolVersion"), (void *) &ph, sizeof(ph)); #endif #ifdef HAVE_PQSERVERVERSION zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("serverVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY); ph.read = php_pqconn_object_read_server_version; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("serverVersion"), (void *) &ph, sizeof(ph)); #endif zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV); #ifdef HAVE_CONNECTION_CHECK_WRITABLE zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("CHECK_WRITABLE"), CONNECTION_CHECK_WRITABLE); #endif #ifdef HAVE_CONNECTION_CONSUME zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("CONSUME"), CONNECTION_CONSUME); #endif #ifdef HAVE_CONNECTION_GSS_STARTUP zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("GSS_STARTUP"), CONNECTION_GSS_STARTUP); #endif zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK); zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_NOTICE"), ZEND_STRL("notice")); zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESULT"), ZEND_STRL("result")); zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESET"), ZEND_STRL("reset")); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("ASYNC"), 0x1); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("PERSISTENT"), 0x2); PHP_PQ_G->connection.name = zend_string_init(ZEND_STRL("pq\\Connection"), 1); return php_persistent_handle_provide(PHP_PQ_G->connection.name, php_pqconn_get_resource_factory_ops(), NULL, NULL); } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqconn_event.c0000644000076500000240000001304614560227740015262 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqconn_event.h" #include "php_pqstm.h" #include "php_pqres.h" static int apply_event(zval *p, void *a) { php_pq_callback_t *cb = Z_PTR_P(p); zval *args = a; zval rv; ZVAL_NULL(&rv); zend_fcall_info_args(&cb->fci, args); zend_fcall_info_call(&cb->fci, &cb->fcc, &rv, NULL); zend_fcall_info_args_clear(&cb->fci, 0); zval_ptr_dtor(&rv); return ZEND_HASH_APPLY_KEEP; } static inline PGresult *relisten(PGconn *conn, const char *channel_str, size_t channel_len) { char *quoted_channel = PQescapeIdentifier(conn, channel_str, channel_len); PGresult *res = NULL; if (quoted_channel) { smart_str cmd = {0}; smart_str_appends(&cmd, "LISTEN "); smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); res = php_pq_exec(conn, smart_str_v(&cmd)); smart_str_free(&cmd); PQfreemem(quoted_channel); } return res; } static int apply_relisten(zval *p, int argc, va_list argv, zend_hash_key *key) { php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *); PGresult *res = relisten(obj->intern->conn, key->key->val, key->key->len); if (res) { php_pqres_clear(res); } return ZEND_HASH_APPLY_KEEP; } static int apply_reprepare(zval *p, int argc, va_list argv, zend_hash_key *key) { php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *); php_pqstm_t *stm = Z_PTR_P(p); php_pqconn_prepare(NULL, obj, stm->name, stm->query, stm->params); return ZEND_HASH_APPLY_KEEP; } static void php_pqconn_event_connreset(PGEventConnReset *event) { php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event); if (data) { zval *zevhs; /* restore listeners */ zend_hash_apply_with_arguments(&data->obj->intern->listeners, apply_relisten, 1, data->obj); /* restore statements */ zend_hash_apply_with_arguments(&data->obj->intern->statements, apply_reprepare, 1, data->obj); /* eventhandler */ if ((zevhs = zend_hash_str_find(&data->obj->intern->eventhandlers, ZEND_STRL("reset")))) { zval args, connection; array_init(&args); php_pq_object_to_zval(data->obj, &connection); add_next_index_zval(&args, &connection); zend_hash_apply_with_argument(Z_ARRVAL_P(zevhs), apply_event, &args); zval_ptr_dtor(&args); } } } static void php_pqconn_event_resultcreate(PGEventResultCreate *event) { php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event); if (data) { php_pqres_object_t *obj = php_pqres_init_instance_data(event->result, data->obj); zval *zevhs; /* event listener */ if ((zevhs = zend_hash_str_find(&data->obj->intern->eventhandlers, ZEND_STRL("result")))) { zval args, connection, res; array_init(&args); php_pq_object_to_zval(data->obj, &connection); add_next_index_zval(&args, &connection); php_pq_object_to_zval(obj, &res); add_next_index_zval(&args, &res); zend_hash_apply_with_argument(Z_ARRVAL_P(zevhs), apply_event, &args); zval_ptr_dtor(&args); } /* async callback */ if (php_pq_callback_is_enabled(&data->obj->intern->onevent)) { zval res; php_pq_object_to_zval(obj, &res); zend_fcall_info_argn(&data->obj->intern->onevent.fci, 1, &res); zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL); zval_ptr_dtor(&res); } } } static void php_pqconn_event_resultdestroy(PGEventResultDestroy *event) { php_pqres_object_t *obj = PQresultInstanceData(event->result, php_pqconn_event); if (obj) { obj->intern->res = NULL; assert(GC_REFCOUNT(&obj->zo)); php_pq_object_delref(obj); } } int php_pqconn_event(PGEventId id, void *e, void *data) { switch (id) { case PGEVT_CONNRESET: php_pqconn_event_connreset(e); break; case PGEVT_RESULTCREATE: php_pqconn_event_resultcreate(e); break; case PGEVT_RESULTDESTROY: php_pqconn_event_resultdestroy(e); break; default: break; } return 1; } php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj) { php_pqconn_event_data_t *data = emalloc(sizeof(*data)); data->obj = obj; data->res = NULL; return data; } void php_pqconn_notice_recv(void *p, const PGresult *res) { php_pqconn_event_data_t *data = p; if (data) { zval *zevhs; if ((zevhs = zend_hash_str_find(&data->obj->intern->eventhandlers, ZEND_STRL("notice")))) { zval args, connection; array_init(&args); php_pq_object_to_zval(data->obj, &connection); add_next_index_zval(&args, &connection); add_next_index_string(&args, PHP_PQresultErrorMessage(res)); zend_hash_apply_with_argument(Z_ARRVAL_P(zevhs), apply_event, &args); zval_ptr_dtor(&args); } } } void php_pqconn_notice_ignore(void *p, const PGresult *res) { } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqconn_event.h0000644000076500000240000000252114560227740015263 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQCONN_EVENT_H #define PHP_PQCONN_EVENT_H #include #include "php_pqconn.h" #include "php_pqres.h" typedef struct php_pqconn_event_data { php_pqconn_object_t *obj; php_pqres_object_t *res; } php_pqconn_event_data_t; extern php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj); extern void php_pqconn_notice_recv(void *p, const PGresult *res); extern void php_pqconn_notice_ignore(void *p, const PGresult *res); extern int php_pqconn_event(PGEventId id, void *e, void *data); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqconn.h0000644000076500000240000000556714560227740014077 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQCONN_H #define PHP_PQCONN_H #define PHP_PQCONN_ASYNC 0x01 #define PHP_PQCONN_PERSISTENT 0x02 #include #include "php_pq_object.h" #include "php_pq_callback.h" #include "php_pq_object.h" #include "php_pq_params.h" typedef struct php_pqconn { PGconn *conn; int (*poller)(PGconn *); php_resource_factory_t factory; HashTable listeners; HashTable statements; HashTable converters; HashTable eventhandlers; php_pq_callback_t onevent; unsigned unbuffered:1; unsigned default_fetch_type:2; unsigned default_txn_isolation:2; unsigned default_txn_readonly:1; unsigned default_txn_deferrable:1; unsigned default_auto_convert:16; } php_pqconn_t; typedef struct php_pqconn_object { PHP_PQ_OBJ_DECL(php_pqconn_t *) } php_pqconn_object_t; typedef struct php_pqconn_resource_factory_data { char *dsn; unsigned long flags; } php_pqconn_resource_factory_data_t; extern php_resource_factory_ops_t *php_pqconn_get_resource_factory_ops(void); extern zend_class_entry *php_pqconn_class_entry; extern php_pqconn_object_t *php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern); extern void php_pqconn_notify_listeners(php_pqconn_object_t *obj); extern ZEND_RESULT_CODE php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params); extern ZEND_RESULT_CODE php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params); extern ZEND_RESULT_CODE php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable); extern ZEND_RESULT_CODE php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable); extern ZEND_RESULT_CODE php_pqconn_declare(zval *object, php_pqconn_object_t *obj, const char *decl); extern ZEND_RESULT_CODE php_pqconn_declare_async(zval *object, php_pqconn_object_t *obj, const char *decl); extern PHP_MINIT_FUNCTION(pqconn); extern PHP_MSHUTDOWN_FUNCTION(pqconn); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqcopy.c0000644000076500000240000002662114560227740014101 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqres.h" #include "php_pqconn.h" #include "php_pqcopy.h" zend_class_entry *php_pqcopy_class_entry; static zend_object_handlers php_pqcopy_object_handlers; static HashTable php_pqcopy_object_prophandlers; static void php_pqcopy_object_free(zend_object *o) { php_pqcopy_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE copy(#%d) %p (conn(#%d): %p)\n", obj->zo.handle, obj, obj->intern->conn->zo.handle, obj->intern->conn); #endif if (obj->intern) { efree(obj->intern->expression); efree(obj->intern->options); php_pq_object_delref(obj->intern->conn); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqcopy_object_t *php_pqcopy_create_object_ex(zend_class_entry *ce, php_pqcopy_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqcopy_object_t), &php_pqcopy_object_handlers, &php_pqcopy_object_prophandlers); } static zend_object *php_pqcopy_create_object(zend_class_entry *class_type) { return &php_pqcopy_create_object_ex(class_type, NULL)->zo; } static void php_pqcopy_object_read_connection(void *o, zval *return_value) { php_pqcopy_object_t *obj = o; php_pq_object_to_zval(obj->intern->conn, return_value); } static void php_pqcopy_object_gc_connection(void *o, zval *return_value) { php_pqcopy_object_t *obj = o; zval zconn; php_pq_object_to_zval_no_addref(obj->intern->conn, &zconn); add_next_index_zval(return_value, &zconn); } static void php_pqcopy_object_read_direction(void *o, zval *return_value) { php_pqcopy_object_t *obj = o; RETVAL_LONG(obj->intern->direction); } static void php_pqcopy_object_read_expression(void *o, zval *return_value) { php_pqcopy_object_t *obj = o; RETURN_STRING(obj->intern->expression); } static void php_pqcopy_object_read_options(void *o, zval *return_value) { php_pqcopy_object_t *obj = o; RETURN_STRING(obj->intern->options); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_construct, 0, 0, 3) ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) ZEND_ARG_INFO(0, expression) ZEND_ARG_INFO(0, direction) ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcopy, __construct) { zend_error_handling zeh; zval *zconn; char *expr_str, *opt_str = ""; size_t expr_len, opt_len = 0; zend_long direction; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "Osl|s", &zconn, php_pqconn_class_entry, &expr_str, &expr_len, &direction, &opt_str, &opt_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = PHP_PQ_OBJ(zconn, NULL); if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { php_pqcopy_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); smart_str cmd = {0}; PGresult *res; smart_str_appends(&cmd, "COPY "); smart_str_appendl(&cmd, expr_str, expr_len); switch (direction) { case PHP_PQCOPY_FROM_STDIN: smart_str_appends(&cmd, " FROM STDIN "); break; case PHP_PQCOPY_TO_STDOUT: smart_str_appends(&cmd, " TO STDOUT "); break; default: throw_exce(EX_RUNTIME, "Invalid COPY direction, expected one of FROM_STDIN (%d) TO_STDOUT (%d), got %ld", PHP_PQCOPY_FROM_STDIN, PHP_PQCOPY_TO_STDOUT, direction); smart_str_free(&cmd); return; } smart_str_appendl(&cmd, opt_str, opt_len); smart_str_0(&cmd); res = php_pq_exec(conn_obj->intern->conn, smart_str_v(&cmd)); if (!res) { throw_exce(EX_RUNTIME, "Failed to start %s (%s)", smart_str_v(&cmd), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->direction = direction; obj->intern->expression = estrdup(expr_str); obj->intern->options = estrdup(opt_str); obj->intern->conn = conn_obj; php_pq_object_addref(conn_obj); } php_pqres_clear(res); } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_put, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcopy, put) { zend_error_handling zeh; char *data_str; size_t data_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqcopy_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\COPY not initialized"); } else if (obj->intern->direction != PHP_PQCOPY_FROM_STDIN) { throw_exce(EX_BAD_METHODCALL, "pq\\COPY was not initialized with FROM_STDIN"); } else { if (1 != PQputCopyData(obj->intern->conn->intern->conn, data_str, data_len)) { throw_exce(EX_RUNTIME, "Failed to put COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_end, 0, 0, 0) ZEND_ARG_INFO(0, error) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcopy, end) { zend_error_handling zeh; char *error_str = NULL; size_t error_len = 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &error_str, &error_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqcopy_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\COPY not intitialized"); } else if (obj->intern->direction != PHP_PQCOPY_FROM_STDIN) { throw_exce(EX_BAD_METHODCALL, "pq\\COPY was not intitialized with FROM_STDIN"); } else { if (1 != PQputCopyEnd(obj->intern->conn->intern->conn, error_str)) { throw_exce(EX_RUNTIME, "Failed to end COPY (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { PGresult *res = PQgetResult(obj->intern->conn->intern->conn); if (!res) { throw_exce(EX_RUNTIME, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res); php_pqres_clear(res); } } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_get, 0, 0, 1) ZEND_ARG_INFO(1, data) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcopy, get) { zend_error_handling zeh; zval *zdata; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zdata); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqcopy_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\COPY not initialized"); } else if (obj->intern->direction != PHP_PQCOPY_TO_STDOUT) { throw_exce(EX_RUNTIME, "pq\\COPY was not intialized with TO_STDOUT"); } else { PGresult *res; char *buffer = NULL; int bytes = PQgetCopyData(obj->intern->conn->intern->conn, &buffer, 0); switch (bytes) { case -2: throw_exce(EX_RUNTIME, "Failed to fetch COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); break; case -1: res = PQgetResult(obj->intern->conn->intern->conn); if (!res) { throw_exce(EX_RUNTIME, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res); php_pqres_clear(res); RETVAL_FALSE; } break; default: ZVAL_DEREF(zdata); zval_dtor(zdata); if (buffer) { ZVAL_STRINGL(zdata, buffer, bytes); } else { ZVAL_EMPTY_STRING(zdata); } RETVAL_TRUE; break; } if (buffer) { PQfreemem(buffer); } } } } static zend_function_entry php_pqcopy_methods[] = { PHP_ME(pqcopy, __construct, ai_pqcopy_construct, ZEND_ACC_PUBLIC) PHP_ME(pqcopy, put, ai_pqcopy_put, ZEND_ACC_PUBLIC) PHP_ME(pqcopy, end, ai_pqcopy_end, ZEND_ACC_PUBLIC) PHP_ME(pqcopy, get, ai_pqcopy_get, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqcopy) { zend_hash_destroy(&php_pqcopy_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqcopy) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "COPY", php_pqcopy_methods); php_pqcopy_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqcopy_class_entry->create_object = php_pqcopy_create_object; memcpy(&php_pqcopy_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqcopy_object_handlers.offset = XtOffsetOf(php_pqcopy_object_t, zo); php_pqcopy_object_handlers.free_obj = php_pqcopy_object_free; php_pqcopy_object_handlers.read_property = php_pq_object_read_prop; php_pqcopy_object_handlers.write_property = php_pq_object_write_prop; php_pqcopy_object_handlers.clone_obj = NULL; php_pqcopy_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqcopy_object_handlers.get_gc = php_pq_object_get_gc; php_pqcopy_object_handlers.get_properties = php_pq_object_properties; php_pqcopy_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqcopy_object_prophandlers, 4, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC); ph.read = php_pqcopy_object_read_connection; ph.gc = php_pqcopy_object_gc_connection; zend_hash_str_add_mem(&php_pqcopy_object_prophandlers, "connection", sizeof("connection")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("expression"), ZEND_ACC_PUBLIC); ph.read = php_pqcopy_object_read_expression; zend_hash_str_add_mem(&php_pqcopy_object_prophandlers, "expression", sizeof("expression")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("direction"), ZEND_ACC_PUBLIC); ph.read = php_pqcopy_object_read_direction; zend_hash_str_add_mem(&php_pqcopy_object_prophandlers, "direction", sizeof("direction")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC); ph.read = php_pqcopy_object_read_options; zend_hash_str_add_mem(&php_pqcopy_object_prophandlers, "options", sizeof("options")-1, (void *) &ph, sizeof(ph)); zend_declare_class_constant_long(php_pqcopy_class_entry, ZEND_STRL("FROM_STDIN"), PHP_PQCOPY_FROM_STDIN); zend_declare_class_constant_long(php_pqcopy_class_entry, ZEND_STRL("TO_STDOUT"), PHP_PQCOPY_TO_STDOUT); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqcopy.h0000644000076500000240000000304614560227740014102 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQCOPY_H #define PHP_PQCOPY_H #include "php_pqconn.h" typedef enum php_pqcopy_direction { PHP_PQCOPY_FROM_STDIN, PHP_PQCOPY_TO_STDOUT } php_pqcopy_direction_t; typedef enum php_pqcopy_status { PHP_PQCOPY_FAIL, PHP_PQCOPY_CONT, PHP_PQCOPY_DONE } php_pqcopy_status_t; typedef struct php_pqcopy { php_pqcopy_direction_t direction; char *expression; char *options; php_pqconn_object_t *conn; } php_pqcopy_t; typedef struct php_pqcopy_object { PHP_PQ_OBJ_DECL(php_pqcopy_t *) } php_pqcopy_object_t; extern zend_class_entry *php_pqcopy_class_entry; extern php_pqcopy_object_t *php_pqcopy_create_object_ex(zend_class_entry *ce, php_pqcopy_t *intern); extern PHP_MINIT_FUNCTION(pqcopy); extern PHP_MSHUTDOWN_FUNCTION(pqcopy); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqcur.c0000644000076500000240000003562414560227740013723 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqconn.h" #include "php_pqres.h" #include "php_pqcur.h" zend_class_entry *php_pqcur_class_entry; static zend_object_handlers php_pqcur_object_handlers; static HashTable php_pqcur_object_prophandlers; static void cur_close(php_pqcur_object_t *obj, zend_bool async, zend_bool silent) { if (obj->intern->open && obj->intern->conn->intern) { PGresult *res; smart_str cmd = {0}; smart_str_appends(&cmd, "CLOSE "); smart_str_appends(&cmd, obj->intern->name); smart_str_0(&cmd); if (async) { if (PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd))) { obj->intern->conn->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj->intern->conn); } else if (!silent) { throw_exce(EX_IO, "Failed to close cursor (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } } else { if ((res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)))) { php_pqres_clear(res); } else if (!silent) { throw_exce(EX_RUNTIME, "Failed to close cursor (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } } smart_str_free(&cmd); obj->intern->open = 0; } } static void cur_open(INTERNAL_FUNCTION_PARAMETERS, zend_bool async) { zend_error_handling zeh; ZEND_RESULT_CODE rv; php_pqcur_object_t *obj; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (rv == FAILURE) { return; } obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Cursor not initialized"); return; } else if (obj->intern->open) { return; } if (async) { rv = php_pqconn_declare_async(NULL, obj->intern->conn, obj->intern->decl); } else { rv = php_pqconn_declare(NULL, obj->intern->conn, obj->intern->decl); } if (rv == SUCCESS) { obj->intern->open = 1; } } static void cur_fetch_or_move(INTERNAL_FUNCTION_PARAMETERS, const char *action, zend_bool async) { char *spec_str = "1"; size_t spec_len = 1; ZEND_RESULT_CODE rv; php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; zend_error_handling zeh; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), async ? "|sf" : "|s", &spec_str, &spec_len, &resolver.fci, &resolver.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqcur_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Cursor not initialized"); } else { smart_str cmd = {0}; smart_str_appends(&cmd, *action == 'f' ? "FETCH " : "MOVE "); smart_str_appendl(&cmd, spec_str, spec_len); smart_str_appends(&cmd, " FROM "); smart_str_appends(&cmd, obj->intern->name); smart_str_0(&cmd); if (async) { int rc = PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd)); if (!rc) { throw_exce(EX_IO, "Failed to %s cursor (%s)", *action == 'f' ? "fetch from" : "move in", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); #if HAVE_PQSETSINGLEROWMODE } else if (obj->intern->conn->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn->intern->conn)) { throw_exce(EX_RUNTIME, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); #endif } else { php_pq_callback_recurse(&obj->intern->conn->intern->onevent, &resolver); obj->intern->conn->intern->poller = PQconsumeInput; } } else { PGresult *res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)); if (!res) { throw_exce(EX_RUNTIME, "Failed to %s cursor (%s)", *action == 'f' ? "fetch from" : "move in", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else if (SUCCESS == php_pqres_success(res)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); } } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } static void php_pqcur_object_free(zend_object *o) { php_pqcur_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE cur(#%d) %p (conn: %p)\n", obj->zo.handle, obj, obj->intern->conn); #endif if (obj->intern) { cur_close(obj, 0, 1); php_pq_object_delref(obj->intern->conn); efree(obj->intern->decl); efree(obj->intern->name); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqcur_object_t *php_pqcur_create_object_ex(zend_class_entry *ce, php_pqcur_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqcur_object_t), &php_pqcur_object_handlers, &php_pqcur_object_prophandlers); } static zend_object *php_pqcur_create_object(zend_class_entry *class_type) { return &php_pqcur_create_object_ex(class_type, NULL)->zo; } static void php_pqcur_object_read_name(void *o, zval *return_value) { php_pqcur_object_t *obj = o; RETVAL_STRING(obj->intern->name); } static void php_pqcur_object_read_connection(void *o, zval *return_value) { php_pqcur_object_t *obj = o; php_pq_object_to_zval(obj->intern->conn, return_value); } static void php_pqcur_object_gc_connection(void *o, zval *return_value) { php_pqcur_object_t *obj = o; zval zconn; php_pq_object_to_zval_no_addref(obj->intern->conn, &zconn); add_next_index_zval(return_value, &zconn); } static void php_pqcur_object_read_query(void *o, zval *return_value) { php_pqcur_object_t *obj = o; RETVAL_STRING(obj->intern->decl + obj->intern->query_offset); } static void php_pqcur_object_read_flags(void *o, zval *return_value) { php_pqcur_object_t *obj = o; RETVAL_LONG(obj->intern->flags); } char *php_pqcur_declare_str(const char *name_str, size_t name_len, unsigned flags, const char *query_str, size_t query_len, int *query_offset) { size_t decl_len = name_len + query_len + sizeof("DECLARE BINARY INSENSITIVE NO SCROLL CURSOR WITH HOLD FOR "); char *decl_str; decl_str = emalloc(decl_len); decl_len = slprintf(decl_str, decl_len, "DECLARE %s %s %s %s CURSOR %s FOR %s", name_str, (flags & PHP_PQ_DECLARE_BINARY) ? "BINARY" : "", (flags & PHP_PQ_DECLARE_INSENSITIVE) ? "INSENSITIVE" : "", (flags & PHP_PQ_DECLARE_NO_SCROLL) ? "NO SCROLL" : (flags & PHP_PQ_DECLARE_SCROLL) ? "SCROLL" : "", (flags & PHP_PQ_DECLARE_WITH_HOLD) ? "WITH HOLD" : "", query_str ); if (query_offset) { /* sizeof() includes the terminating null byte, so no need for spaces in the string literals */ *query_offset = sizeof("DECLARE") + (name_len + 1) + ((flags & PHP_PQ_DECLARE_BINARY) ? sizeof("BINARY") : 1) + ((flags & PHP_PQ_DECLARE_INSENSITIVE) ? sizeof("INSENSITIVE") : 1) + ((flags & PHP_PQ_DECLARE_NO_SCROLL) ? sizeof("NO SCROLL") : (flags & PHP_PQ_DECLARE_SCROLL) ? sizeof("SCROLL") : 1) + sizeof("CURSOR") + ((flags & PHP_PQ_DECLARE_WITH_HOLD) ? sizeof("WITH HOLD") : 1) + sizeof("FOR"); } return decl_str; } php_pqcur_t *php_pqcur_init(php_pqconn_object_t *conn, const char *name, char *decl, int query_offset, long flags) { php_pqcur_t *cur = ecalloc(1, sizeof(*cur)); php_pq_object_addref(conn); cur->conn = conn; cur->name = estrdup(name); cur->decl = decl; cur->query_offset = query_offset; cur->flags = flags; cur->open = 1; return cur; } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur___construct, 0, 0, 4) ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, flags) ZEND_ARG_INFO(0, query) ZEND_ARG_INFO(0, async) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, __construct) { zend_error_handling zeh; char *name_str, *query_str; size_t name_len, query_len; zend_long flags; zval *zconn; ZEND_RESULT_CODE rv; zend_bool async = 0; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "Osls|b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &flags, &query_str, &query_len, &async); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqcur_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); php_pqconn_object_t *conn_obj = PHP_PQ_OBJ(zconn, NULL); if (obj->intern) { throw_exce(EX_BAD_METHODCALL, "pq\\Cursor already initialized"); } if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { int query_offset; char *decl = php_pqcur_declare_str(name_str, name_len, flags, query_str, query_len, &query_offset); if (async) { rv = php_pqconn_declare_async(zconn, conn_obj, decl); } else { rv = php_pqconn_declare(zconn, conn_obj, decl); } if (SUCCESS != rv) { efree(decl); } else { obj->intern = php_pqcur_init(conn_obj, name_str, decl, query_offset, flags); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_open, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, open) { cur_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_openAsync, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, openAsync) { cur_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_close, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, close) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (rv == SUCCESS) { php_pqcur_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Cursor not initialized"); } else { cur_close(obj, 0, 0); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_closeAsync, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, closeAsync) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (rv == SUCCESS) { php_pqcur_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Cursor not initialized"); } else { cur_close(obj, 1, 0); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_fetch, 0, 0, 1) ZEND_ARG_INFO(0, spec) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, fetch) { cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "fetch", 0); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_move, 0, 0, 0) ZEND_ARG_INFO(0, spec) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, move) { cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "move", 0); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_fetchAsync, 0, 0, 0) ZEND_ARG_INFO(0, spec) ZEND_ARG_INFO(0, callback) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, fetchAsync) { cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "fetch", 1); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_moveAsync, 0, 0, 0) ZEND_ARG_INFO(0, spec) ZEND_ARG_INFO(0, callback) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcur, moveAsync) { cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "move", 1); } static zend_function_entry php_pqcur_methods[] = { PHP_ME(pqcur, __construct, ai_pqcur___construct, ZEND_ACC_PUBLIC) PHP_ME(pqcur, open, ai_pqcur_open, ZEND_ACC_PUBLIC) PHP_ME(pqcur, openAsync, ai_pqcur_openAsync, ZEND_ACC_PUBLIC) PHP_ME(pqcur, close, ai_pqcur_close, ZEND_ACC_PUBLIC) PHP_ME(pqcur, closeAsync, ai_pqcur_closeAsync, ZEND_ACC_PUBLIC) PHP_ME(pqcur, fetch, ai_pqcur_fetch, ZEND_ACC_PUBLIC) PHP_ME(pqcur, move, ai_pqcur_move, ZEND_ACC_PUBLIC) PHP_ME(pqcur, fetchAsync, ai_pqcur_fetchAsync, ZEND_ACC_PUBLIC) PHP_ME(pqcur, moveAsync, ai_pqcur_moveAsync, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqcur) { zend_hash_destroy(&php_pqcur_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqcur) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Cursor", php_pqcur_methods); php_pqcur_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqcur_class_entry->create_object = php_pqcur_create_object; memcpy(&php_pqcur_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqcur_object_handlers.offset = XtOffsetOf(php_pqcur_object_t, zo); php_pqcur_object_handlers.free_obj = php_pqcur_object_free; php_pqcur_object_handlers.read_property = php_pq_object_read_prop; php_pqcur_object_handlers.write_property = php_pq_object_write_prop; php_pqcur_object_handlers.clone_obj = NULL; php_pqcur_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqcur_object_handlers.get_gc = php_pq_object_get_gc; php_pqcur_object_handlers.get_properties = php_pq_object_properties; php_pqcur_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqcur_object_prophandlers, 4, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("BINARY"), PHP_PQ_DECLARE_BINARY); zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("INSENSITIVE"), PHP_PQ_DECLARE_INSENSITIVE); zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("WITH_HOLD"), PHP_PQ_DECLARE_WITH_HOLD); zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("SCROLL"), PHP_PQ_DECLARE_SCROLL); zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("NO_SCROLL"), PHP_PQ_DECLARE_NO_SCROLL); zend_declare_property_null(php_pqcur_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC); ph.read = php_pqcur_object_read_name; zend_hash_str_add_mem(&php_pqcur_object_prophandlers, "name", sizeof("name")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqcur_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC); ph.read = php_pqcur_object_read_connection; ph.gc = php_pqcur_object_gc_connection; zend_hash_str_add_mem(&php_pqcur_object_prophandlers, "connection", sizeof("connection")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_null(php_pqcur_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC); ph.read = php_pqcur_object_read_query; zend_hash_str_add_mem(&php_pqcur_object_prophandlers, "query", sizeof("query")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqcur_class_entry, ZEND_STRL("flags"), ZEND_ACC_PUBLIC); ph.read = php_pqcur_object_read_flags; zend_hash_str_add_mem(&php_pqcur_object_prophandlers, "flags", sizeof("flags")-1, (void *) &ph, sizeof(ph)); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqcur.h0000644000076500000240000000344614560227740013725 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQCUR_H #define PHP_PQCUR_H #include "php_pqconn.h" #define PHP_PQ_DECLARE_BINARY 0x01 #define PHP_PQ_DECLARE_INSENSITIVE 0x02 #define PHP_PQ_DECLARE_WITH_HOLD 0x04 #define PHP_PQ_DECLARE_SCROLL 0x10 #define PHP_PQ_DECLARE_NO_SCROLL 0x20 typedef struct php_pqcur { php_pqconn_object_t *conn; char *name; char *decl; unsigned open:1; int query_offset; long flags; } php_pqcur_t; typedef struct php_pqcur_object { PHP_PQ_OBJ_DECL(php_pqcur_t *) } php_pqcur_object_t; extern zend_class_entry *php_pqcur_class_entry; extern php_pqcur_object_t *php_pqcur_create_object_ex(zend_class_entry *ce, php_pqcur_t *intern); extern char *php_pqcur_declare_str(const char *name_str, size_t name_len, unsigned flags, const char *query_str, size_t query_len, int *query_offset); extern php_pqcur_t *php_pqcur_init(php_pqconn_object_t *conn, const char *name, char *decl, int query_offset, long flags); extern PHP_MINIT_FUNCTION(pqcur); extern PHP_MSHUTDOWN_FUNCTION(pqcur); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqexc.c0000644000076500000240000001114114560227740013675 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "php_pq.h" #include "php_pq_object.h" #include "php_pqexc.h" static zend_class_entry *php_pqexc_interface_class_entry; static zend_class_entry *php_pqexc_invalid_argument_class_entry; static zend_class_entry *php_pqexc_runtime_class_entry; static zend_class_entry *php_pqexc_bad_methodcall_class_entry; static zend_class_entry *php_pqexc_domain_class_entry; static zend_function_entry php_pqexc_methods[] = { {0} }; zend_class_entry *exce(php_pqexc_type_t type) { switch (type) { default: case EX_INVALID_ARGUMENT: return php_pqexc_invalid_argument_class_entry; case EX_RUNTIME: case EX_CONNECTION_FAILED: case EX_IO: case EX_ESCAPE: return php_pqexc_runtime_class_entry; case EX_UNINITIALIZED: case EX_BAD_METHODCALL: return php_pqexc_bad_methodcall_class_entry; case EX_DOMAIN: case EX_SQL: return php_pqexc_domain_class_entry; } } zend_object *throw_exce(php_pqexc_type_t type, const char *fmt, ...) { char *msg; zend_object *zexc; va_list argv; va_start(argv, fmt); vspprintf(&msg, 0, fmt, argv); va_end(argv); zexc = zend_throw_exception(exce(type), msg, type); efree(msg); return zexc; } PHP_MINIT_FUNCTION(pqexc) { zend_class_entry ce = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Exception", php_pqexc_methods); php_pqexc_interface_class_entry = zend_register_internal_interface(&ce); zend_class_implements(php_pqexc_interface_class_entry, 1, zend_ce_throwable); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("INVALID_ARGUMENT"), EX_INVALID_ARGUMENT); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("RUNTIME"), EX_RUNTIME); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("CONNECTION_FAILED"), EX_CONNECTION_FAILED); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("IO"), EX_IO); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("ESCAPE"), EX_ESCAPE); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("BAD_METHODCALL"), EX_BAD_METHODCALL); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("UNINITIALIZED"), EX_UNINITIALIZED); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("DOMAIN"), EX_DOMAIN); zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("SQL"), EX_SQL); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "InvalidArgumentException", php_pqexc_methods); php_pqexc_invalid_argument_class_entry = zend_register_internal_class_ex(&ce, spl_ce_InvalidArgumentException); zend_class_implements(php_pqexc_invalid_argument_class_entry, 1, php_pqexc_interface_class_entry); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "RuntimeException", php_pqexc_methods); php_pqexc_runtime_class_entry = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException); zend_class_implements(php_pqexc_runtime_class_entry, 1, php_pqexc_interface_class_entry); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "BadMethodCallException", php_pqexc_methods); php_pqexc_bad_methodcall_class_entry = zend_register_internal_class_ex(&ce, spl_ce_BadMethodCallException); zend_class_implements(php_pqexc_bad_methodcall_class_entry, 1, php_pqexc_interface_class_entry); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "DomainException", php_pqexc_methods); php_pqexc_domain_class_entry = zend_register_internal_class_ex(&ce, spl_ce_DomainException); zend_class_implements(php_pqexc_domain_class_entry, 1, php_pqexc_interface_class_entry); zend_declare_property_null(php_pqexc_domain_class_entry, ZEND_STRL("sqlstate"), ZEND_ACC_PUBLIC); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqexc.h0000644000076500000240000000230614560227740013705 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQEXC_H #define PHP_PQEXC_H typedef enum php_pqexc_type { EX_INVALID_ARGUMENT, EX_RUNTIME, EX_CONNECTION_FAILED, EX_IO, EX_ESCAPE, EX_BAD_METHODCALL, EX_UNINITIALIZED, EX_DOMAIN, EX_SQL } php_pqexc_type_t; extern zend_class_entry *exce(php_pqexc_type_t type); extern zend_object *throw_exce(php_pqexc_type_t type, const char *fmt, ...); extern PHP_MINIT_FUNCTION(pqexc); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqlob.c0000644000076500000240000003751214560227740013704 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqlob.h" zend_class_entry *php_pqlob_class_entry; static zend_object_handlers php_pqlob_object_handlers; static HashTable php_pqlob_object_prophandlers; static void php_pqlob_object_free(zend_object *o) { php_pqlob_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE lob(#%d) %p (txn(#%d): %p)\n", obj->zo.handle, obj, obj->intern->txn->zo.handle, obj->intern->txn); #endif if (obj->intern) { if (obj->intern->lofd) { lo_close(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd); } /* invalidate the stream */ if (obj->intern->stream) { zend_list_delete(obj->intern->stream->res); obj->intern->stream = NULL; } php_pq_object_delref(obj->intern->txn); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqlob_object_t *php_pqlob_create_object_ex(zend_class_entry *ce, php_pqlob_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqlob_object_t), &php_pqlob_object_handlers, &php_pqlob_object_prophandlers); } static zend_object *php_pqlob_create_object(zend_class_entry *class_type) { return &php_pqlob_create_object_ex(class_type, NULL)->zo; } static void php_pqlob_object_read_transaction(void *o, zval *return_value) { php_pqlob_object_t *obj = o; php_pq_object_to_zval(obj->intern->txn, return_value); } static void php_pqlob_object_gc_transaction(void *o, zval *return_value) { php_pqlob_object_t *obj = o; zval ztxn; php_pq_object_to_zval_no_addref(obj->intern->txn, &ztxn); add_next_index_zval(return_value, &ztxn); } static void php_pqlob_object_read_oid(void *o, zval *return_value) { php_pqlob_object_t *obj = o; RETVAL_LONG(obj->intern->loid); } static void php_pqlob_object_update_stream(php_pqlob_object_t *obj, zval *zstream); static void php_pqlob_object_read_stream(void *o, zval *return_value) { php_pqlob_object_t *obj = o; zval zstream; if (!obj->intern->stream) { php_pqlob_object_update_stream(obj, &zstream); } else { php_stream_to_zval(obj->intern->stream, &zstream); } RETVAL_ZVAL(&zstream, 1, 0); } #if PHP_VERSION_ID < 70400 static size_t php_pqlob_stream_write(php_stream *stream, const char *buffer, size_t length) #else static ssize_t php_pqlob_stream_write(php_stream *stream, const char *buffer, size_t length) #endif { php_pqlob_object_t *obj = stream->abstract; ssize_t written = 0; if (obj) { written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length); if (written < 0) { php_error_docref(NULL, E_WARNING, "Failed to write to LOB with oid=%u (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } #if PHP_VERSION_ID < 70400 return (written < 0 ? 0 : written); #else return written; #endif } #if PHP_VERSION_ID < 70400 static size_t php_pqlob_stream_read(php_stream *stream, char *buffer, size_t length) #else static ssize_t php_pqlob_stream_read(php_stream *stream, char *buffer, size_t length) #endif { php_pqlob_object_t *obj = stream->abstract; ssize_t read = 0; if (obj) { if (!buffer && !length) { if (lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd) == lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, 0, SEEK_CUR)) { return EOF; } } else { read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length); if (read < 0) { php_error_docref(NULL, E_WARNING, "Failed to read from LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } #if PHP_VERSION_ID < 70400 return (read < 0 ? 0 : read); #else return read; #endif } static ZEND_RESULT_CODE php_pqlob_stream_close(php_stream *stream, int close_handle) { return SUCCESS; } static int php_pqlob_stream_flush(php_stream *stream) { return SUCCESS; } static ZEND_RESULT_CODE php_pqlob_stream_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) { ZEND_RESULT_CODE rv = FAILURE; php_pqlob_object_t *obj = stream->abstract; if (obj) { int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence); if (position < 0) { php_error_docref(NULL, E_WARNING, "Failed to seek offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); rv = FAILURE; } else { *newoffset = position; rv = SUCCESS; } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } return rv; } static php_stream_ops php_pqlob_stream_ops = { /* stdio like functions - these are mandatory! */ php_pqlob_stream_write, php_pqlob_stream_read, php_pqlob_stream_close, php_pqlob_stream_flush, "pq\\LOB stream", /* these are optional */ php_pqlob_stream_seek, NULL, /* cast */ NULL, /* stat */ NULL, /* set_option */ }; static void php_pqlob_object_update_stream(php_pqlob_object_t *obj, zval *zstream) { zval zobj, zmember; ZVAL_STRINGL(&zmember, "stream", sizeof("stream")-1); obj->intern->stream = php_stream_alloc(&php_pqlob_stream_ops, obj, NULL, "r+b"); obj->intern->stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; php_stream_to_zval(obj->intern->stream, zstream); #if PHP_VERSION_ID >= 80000 zend_std_write_property(&obj->zo, Z_STR(zmember), zstream, NULL); #else ZVAL_OBJ(&zobj, &obj->zo); zend_std_write_property(&zobj, &zmember, zstream, NULL); #endif zval_ptr_dtor(&zmember); } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, transaction, pq\\Transaction, 0) ZEND_ARG_INFO(0, oid) ZEND_ARG_INFO(0, mode) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, __construct) { zend_error_handling zeh; zval *ztxn; zend_long mode = INV_WRITE|INV_READ, loid = InvalidOid; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &ztxn, php_pqtxn_class_entry, &loid, &mode); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqlob_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); php_pqtxn_object_t *txn_obj = PHP_PQ_OBJ(ztxn, NULL); if (obj->intern) { throw_exce(EX_BAD_METHODCALL, "pq\\LOB already initialized"); } else if (!txn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!txn_obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transation already closed"); } else { if (loid == InvalidOid) { loid = lo_creat(txn_obj->intern->conn->intern->conn, mode); } if (loid == InvalidOid) { throw_exce(EX_RUNTIME, "Failed to create large object with mode '%s' (%s)", php_pq_strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)); } else { int lofd = lo_open(txn_obj->intern->conn->intern->conn, loid, mode); if (lofd < 0) { throw_exce(EX_RUNTIME, "Failed to open large object with oid=%u with mode '%s' (%s)", loid, php_pq_strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)); } else { obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->lofd = lofd; obj->intern->loid = loid; php_pq_object_addref(txn_obj); obj->intern->txn = txn_obj; } } php_pqconn_notify_listeners(txn_obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, write) { zend_error_handling zeh; char *data_str; size_t data_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqlob_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\LOB not initialized"); } else { int written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, data_str, data_len); if (written < 0) { throw_exce(EX_RUNTIME, "Failed to write to LOB with oid=%u (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { RETVAL_LONG(written); } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read, 0, 0, 0) ZEND_ARG_INFO(0, length) ZEND_ARG_INFO(1, read) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, read) { zend_error_handling zeh; zend_long length = 0x1000; zval *zread = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|lz!", &length, &zread); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqlob_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\LOB not initialized"); } else { zend_string *buffer = zend_string_alloc(length, 0); int read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, &buffer->val[0], length); if (read < 0) { zend_string_release(buffer); throw_exce(EX_RUNTIME, "Failed to read from LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { if (zread) { ZVAL_DEREF(zread); zval_dtor(zread); ZVAL_LONG(zread, read); } buffer->val[buffer->len = read] = '\0'; RETVAL_STR(buffer); } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek, 0, 0, 1) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, whence) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, seek) { zend_error_handling zeh; zend_long offset, whence = SEEK_SET; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &offset, &whence); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqlob_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\LOB not initialized"); } else { int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence); if (position < 0) { throw_exce(EX_RUNTIME, "Failed to seek offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { RETVAL_LONG(position); } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, tell) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqlob_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\LOB not initialized"); } else { int position = lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd); if (position < 0) { throw_exce(EX_RUNTIME, "Failed to tell offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { RETVAL_LONG(position); } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate, 0, 0, 0) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, truncate) { zend_error_handling zeh; zend_long length = 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &length); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqlob_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\LOB not initialized"); } else { int rc = lo_truncate(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, length); if (rc != 0) { throw_exce(EX_RUNTIME, "Failed to truncate LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } php_pqconn_notify_listeners(obj->intern->txn->intern->conn); } } } static zend_function_entry php_pqlob_methods[] = { PHP_ME(pqlob, __construct, ai_pqlob_construct, ZEND_ACC_PUBLIC) PHP_ME(pqlob, write, ai_pqlob_write, ZEND_ACC_PUBLIC) PHP_ME(pqlob, read, ai_pqlob_read, ZEND_ACC_PUBLIC) PHP_ME(pqlob, seek, ai_pqlob_seek, ZEND_ACC_PUBLIC) PHP_ME(pqlob, tell, ai_pqlob_tell, ZEND_ACC_PUBLIC) PHP_ME(pqlob, truncate, ai_pqlob_truncate, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqlob) { zend_hash_destroy(&php_pqlob_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqlob) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "LOB", php_pqlob_methods); php_pqlob_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqlob_class_entry->create_object = php_pqlob_create_object; memcpy(&php_pqlob_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqlob_object_handlers.offset = XtOffsetOf(php_pqlob_object_t, zo); php_pqlob_object_handlers.free_obj = php_pqlob_object_free; php_pqlob_object_handlers.read_property = php_pq_object_read_prop; php_pqlob_object_handlers.write_property = php_pq_object_write_prop; php_pqlob_object_handlers.clone_obj = NULL; php_pqlob_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqlob_object_handlers.get_gc = php_pq_object_get_gc; php_pqlob_object_handlers.get_properties = php_pq_object_properties; php_pqlob_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqlob_object_prophandlers, 3, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC); ph.read = php_pqlob_object_read_transaction; ph.gc = php_pqlob_object_gc_transaction; zend_hash_str_add_mem(&php_pqlob_object_prophandlers, "transaction", sizeof("transaction")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_long(php_pqlob_class_entry, ZEND_STRL("oid"), InvalidOid, ZEND_ACC_PUBLIC); ph.read = php_pqlob_object_read_oid; zend_hash_str_add_mem(&php_pqlob_object_prophandlers, "oid", sizeof("oid")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("stream"), ZEND_ACC_PUBLIC); ph.read = php_pqlob_object_read_stream; zend_hash_str_add_mem(&php_pqlob_object_prophandlers, "stream", sizeof("stream")-1, (void *) &ph, sizeof(ph)); zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("INVALID_OID"), InvalidOid); zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("R"), INV_READ); zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("W"), INV_WRITE); zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("RW"), INV_READ|INV_WRITE); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqlob.h0000644000076500000240000000244014560227740013701 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQLOB_H #define PHP_PQLOB_H #include "php_pqtxn.h" typedef struct php_pqlob { int lofd; Oid loid; php_stream *stream; php_pqtxn_object_t *txn; } php_pqlob_t; typedef struct php_pqlob_object { PHP_PQ_OBJ_DECL(php_pqlob_t *) } php_pqlob_object_t; extern zend_class_entry *php_pqlob_class_entry; extern php_pqlob_object_t *php_pqlob_create_object_ex(zend_class_entry *ce, php_pqlob_t *intern); extern PHP_MINIT_FUNCTION(pqlob); extern PHP_MSHUTDOWN_FUNCTION(pqlob); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_misc.c0000644000076500000240000002750114560227740014217 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "php_pq.h" #include "php_pqexc.h" #include "php_pq_misc.h" #include "php_pqconn_event.h" #undef PHP_PQ_TYPE #include "php_pq_type.h" /* convert version to string */ extern void php_pq_version_to_string(int version, char *buffer, int len) { if (version < 100000) { slprintf(buffer, len, "%d.%d.%d", version/10000, version/100%100, version%100); } else { /* since version 10 */ slprintf(buffer, len, "%d.%d", version/10000, version%100); } } /* clear result object associated with a result handle */ void php_pqres_clear(PGresult *r) { php_pq_object_t *o = PQresultInstanceData(r, php_pqconn_event); if (o) { php_pq_object_delref(o); } else { PQclear(r); } } /* clear any asynchronous results */ void php_pqconn_clear(PGconn *conn) { PGresult *r; php_pqconn_event_data_t *evdata = PQinstanceData(conn, php_pqconn_event); while ((r = PQgetResult(conn))) { php_pqres_clear(r); } if (evdata && evdata->obj) { if (php_pq_callback_is_enabled(&evdata->obj->intern->onevent)) { if (php_pq_callback_is_locked(&evdata->obj->intern->onevent)) { php_pq_callback_disable(&evdata->obj->intern->onevent); } else { php_pq_callback_dtor(&evdata->obj->intern->onevent); } } } } /* safe wrappers to clear any asynchronous wrappers before querying synchronously */ PGresult *php_pq_exec(PGconn *conn, const char *query) { php_pqconn_clear(conn); return PQexec(conn, query); } PGresult *php_pq_exec_params(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { php_pqconn_clear(conn); return PQexecParams(conn, command, nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat); } PGresult *php_pq_prepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes) { php_pqconn_clear(conn); return PQprepare(conn, stmtName, query, nParams, paramTypes); } PGresult *php_pq_exec_prepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { php_pqconn_clear(conn); return PQexecPrepared(conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat); } char *php_pq_rtrim(char *e) { size_t l = strlen(e); while (l-- > 0 && e[l] == '\n') { e[l] = '\0'; } return e; } const char *php_pq_strmode(long mode) { switch (mode & (INV_READ|INV_WRITE)) { case INV_READ|INV_WRITE: return "rw"; case INV_READ: return "r"; case INV_WRITE: return "w"; default: return "-"; } } static inline int compare_index(zend_ulong l, zend_ulong r) { if (l < r) { return -1; } if (l > r) { return 1; } return 0; } #if PHP_VERSION_ID >= 80000 int php_pq_compare_index(Bucket *lptr, Bucket *rptr) { return compare_index(lptr->h, rptr->h); } #else int php_pq_compare_index(const void *lptr, const void *rptr) { return compare_index(((const Bucket *) lptr)->h, ((const Bucket *) rptr)->h); } #endif void php_pq_hash_ptr_dtor(zval *p) { efree(Z_PTR_P(p)); } zend_class_entry *php_pqdt_class_entry; #if PHP_VERSION_ID >= 80100 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_pqdt_jsonserialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() #else #define ai_pqdt_jsonserialize ai_pqdt_to_string #endif #if PHP_VERSION_ID >= 80200 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_pqdt_to_string, 0, 0, IS_STRING, 0) #else ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_to_string, 0, 0, 0) #endif ZEND_END_ARG_INFO(); static PHP_METHOD(pqdt, __toString) { zval rv, tmp; ZVAL_NULL(&rv); php_pq_call_method(getThis(), "format", 1, &rv, php_pq_read_property(getThis(), "format", &tmp)); RETVAL_ZVAL(&rv, 1, 1); } #if PHP_VERSION_ID >= 80100 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(ai_pqdt_create_from_format, 0, 2, DateTime, MAY_BE_FALSE) #else ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_create_from_format, 0, 0, 2) #endif ZEND_ARG_INFO(0, format) ZEND_ARG_INFO(0, datetime) #if PHP_VERSION_ID >= 70200 ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 1) #else ZEND_ARG_INFO(0, timezone) #endif ZEND_END_ARG_INFO(); static PHP_METHOD(pqdt, createFromFormat) { zend_error_handling zeh; char *fmt_str, *dt_str; size_t fmt_len, dt_len; zval *ztz = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss|O", &fmt_str, &fmt_len, &dt_str, &dt_len, &ztz, php_date_get_timezone_ce()); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqdt_from_string(return_value, fmt_str, dt_str, dt_len, "Y-m-d H:i:s.uO", ztz); } } static zend_function_entry php_pqdt_methods[] = { PHP_ME(pqdt, createFromFormat, ai_pqdt_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(pqdt, __toString, ai_pqdt_to_string, ZEND_ACC_PUBLIC) PHP_MALIAS(pqdt, jsonSerialize, __toString, ai_pqdt_jsonserialize, ZEND_ACC_PUBLIC) {0} }; zval *php_pqdt_from_string(zval *zv, char *input_fmt, char *dt_str, size_t dt_len, const char *output_fmt, zval *ztimezone) { php_date_obj *dobj; php_date_instantiate(php_pqdt_class_entry, zv); dobj = php_date_obj_from_obj(Z_OBJ_P(zv)); if (!php_date_initialize(dobj, dt_str, dt_len, input_fmt, ztimezone, 1)) { zval_dtor(zv); ZVAL_NULL(zv); } else if (output_fmt) { zval fmt; ZVAL_STRING(&fmt, output_fmt); php_pq_update_property(zv, "format", &fmt); zval_ptr_dtor(&fmt); } return zv; } zend_string *php_pqdt_to_string(zval *zdt, const char *format) { zval rv; ZVAL_NULL(&rv); if (php_pq_cast_object(zdt, IS_STRING, &rv)) { return Z_STR(rv); } else if (instanceof_function(Z_OBJCE_P(zdt), php_date_get_date_ce())) { zval rv, zfmt; ZVAL_NULL(&rv); ZVAL_STRING(&zfmt, format); php_pq_call_method(zdt, "format", 1, &rv, &zfmt); zval_ptr_dtor(&zfmt); if (Z_TYPE(rv) == IS_STRING) { return Z_STR(rv); } zval_ptr_dtor(&rv); } return NULL; } zend_class_entry *php_pqconv_class_entry; ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_types, 0, 0, 0) ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_from_string, 0, 0, 2) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_to_string, 0, 0, 2) ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO(); zend_function_entry php_pqconv_methods[] = { PHP_ABSTRACT_ME(pqconv, convertTypes, ai_pqconv_convert_types) PHP_ABSTRACT_ME(pqconv, convertFromString, ai_pqconv_convert_from_string) PHP_ABSTRACT_ME(pqconv, convertToString, ai_pqconv_convert_to_string) {0} }; PHP_MINIT_FUNCTION(pq_misc) { zend_class_entry *json, ce = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Converter", php_pqconv_methods); php_pqconv_class_entry = zend_register_internal_interface(&ce); memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce ,"pq", "DateTime", php_pqdt_methods); php_pqdt_class_entry = zend_register_internal_class_ex(&ce, php_date_get_date_ce()); zend_declare_property_stringl(php_pqdt_class_entry, ZEND_STRL("format"), ZEND_STRL("Y-m-d H:i:s.uO"), ZEND_ACC_PUBLIC); /* stop reading this file right here! */ if ((json = zend_hash_str_find_ptr(CG(class_table), ZEND_STRL("jsonserializable")))) { zend_class_implements(php_pqdt_class_entry, 1, json); } return SUCCESS; } typedef struct _HashTableList { zval arr; struct _HashTableList *parent; } HashTableList; typedef struct _ArrayParserState { const char *ptr, *end; HashTableList *list; php_pqres_t *res; Oid typ; unsigned quotes:1; unsigned escaped:1; } ArrayParserState; static char caa(ArrayParserState *a, const char *any, unsigned advance) { const char *p = any; do { if (*p == *a->ptr) { a->ptr += advance; return *p; } } while (*++p); php_error_docref(NULL, E_WARNING, "Failed to parse array: expected one of '%s', got '%c'", any, *a->ptr); \ return 0; } static ZEND_RESULT_CODE add_element(ArrayParserState *a, const char *start) { zval zelem; zend_string *zstr = zend_string_init(start, a->ptr - start, 0); if (a->quotes) { php_stripslashes(zstr); ZVAL_STR(&zelem, zstr); } else if (!zend_string_equals_literal(zstr, "NULL")) { ZVAL_STR(&zelem, zstr); } else { zend_string_release(zstr); ZVAL_NULL(&zelem); } if (!ZVAL_IS_NULL(&zelem)) { php_pqres_typed_zval(a->res, a->typ, &zelem); } add_next_index_zval(&a->list->arr, &zelem); return SUCCESS; } static ZEND_RESULT_CODE parse_array(ArrayParserState *a); static ZEND_RESULT_CODE parse_element(ArrayParserState *a, char delim) { const char *el; switch (*a->ptr) { case '{': return parse_array(a); case '}': return SUCCESS; case '"': a->quotes = 1; ++a->ptr; break; } for (el = a->ptr; a->ptr < a->end; ++a->ptr) { switch (*a->ptr) { case '\\': a->escaped = !a->escaped; break; case '"': if (a->escaped) { a->escaped = 0; } else if (a->quotes) { if (SUCCESS != add_element(a, el)) { return FAILURE; } a->quotes = 0; ++a->ptr; return SUCCESS; } else { php_error_docref(NULL, E_WARNING, "Failed to parse element, unexpected quote: '%.*s'", (int) (a->ptr - el), el); return FAILURE; } break; default: if (delim != *a->ptr) { a->escaped = 0; break; } /* no break */ case '}': if (!a->quotes) { return add_element(a, el); } break; } } php_error_docref(NULL, E_WARNING, "Failed to parse element, reached end of input"); return FAILURE; } static ZEND_RESULT_CODE parse_elements(ArrayParserState *a) { char delims[] = {'}', (char) PHP_PQ_DELIM_OF_ARRAY(a->typ), 0}; while (SUCCESS == parse_element(a, delims[1])) { switch (caa(a, delims, 0)) { case 0: return FAILURE; case '}': return SUCCESS; default: if (!*++a->ptr) { php_error_docref(NULL, E_WARNING, "Failed to parse elements, reached end of input"); return FAILURE; } break; } } return FAILURE; } static ZEND_RESULT_CODE parse_array(ArrayParserState *a) { HashTableList *list; if (!caa(a, "{", 1)) { return FAILURE; } list = ecalloc(1, sizeof(*list)); array_init(&list->arr); if (a->list) { add_next_index_zval(&a->list->arr, &list->arr); list->parent = a->list; } a->list = list; if (SUCCESS != parse_elements(a)) { return FAILURE; } if (!caa(a, "}", 1)) { return FAILURE; } /* step one level back up */ if (a->list->parent) { HashTableList *l = a->list->parent; efree(a->list); a->list = l; } return SUCCESS; } HashTable *php_pq_parse_array(php_pqres_t *res, const char *val_str, size_t val_len, Oid typ) { HashTable *ht = NULL; ArrayParserState a = {0}; a.typ = typ; a.ptr = val_str; a.end = val_str + val_len; a.res = res; if (SUCCESS != parse_array(&a)) { while (a.list) { HashTableList *l = a.list->parent; zval_dtor(&a.list->arr); efree(a.list); a.list = l; } return ht; } if (*a.ptr) { php_error_docref(NULL, E_NOTICE, "Trailing input: '%s'", a.ptr); } while (a.list) { HashTableList *l = a.list->parent; ht = Z_ARRVAL(a.list->arr); efree(a.list); a.list = l; } return ht; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_misc.h0000644000076500000240000001176314560227740014227 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQ_ERROR_H #define PHP_PQ_ERROR_H #include #include "php_pqres.h" #define z_is_true zend_is_true #define smart_str_s(ss) (ss)->s #define smart_str_v(ss) (smart_str_s(ss)?(ss)->s->val:NULL) #define smart_str_l(ss) (smart_str_s(ss)?(ss)->s->len:0) /* clear result object associated with a result handle */ extern void php_pqres_clear(PGresult *r); /* clear any asynchronous results */ extern void php_pqconn_clear(PGconn *conn); /* safe wrappers to clear any asynchronous wrappers before querying synchronously */ extern PGresult *php_pq_exec(PGconn *conn, const char *query); extern PGresult *php_pq_exec_params(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); extern PGresult *php_pq_prepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes); extern PGresult *php_pq_exec_prepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); /* convert version to string */ extern void php_pq_version_to_string(int version, char *buffer, int len); /* trim LF from EOL */ extern char *php_pq_rtrim(char *e); /* R, W, RW */ extern const char *php_pq_strmode(long mode); /* free zval ptr values (as hash dtor) */ extern void php_pq_hash_ptr_dtor(zval *p); #define PHP_PQerrorMessage(c) php_pq_rtrim(PQerrorMessage((c))) #define PHP_PQresultErrorMessage(r) php_pq_rtrim(PQresultErrorMessage((r))) extern zend_class_entry *php_pqdt_class_entry; extern zval *php_pqdt_from_string(zval *zv, char *input_fmt, char *dt_str, size_t dt_len, const char *output_fmt, zval *ztimezone); extern zend_string *php_pqdt_to_string(zval *zdt, const char *format); extern zend_class_entry *php_pqconv_class_entry; extern HashTable *php_pq_parse_array(php_pqres_t *res, const char *val_str, size_t val_len, Oid typ); /* ZE compat */ #if PHP_VERSION_ID >= 80000 extern int php_pq_compare_index(Bucket *lptr, Bucket *rptr); # define php_pq_call_method(objval_ptr, method_name, num_args, ...) \ zend_call_method_with_ ## num_args ## _params( \ Z_OBJ_P(objval_ptr), Z_OBJCE_P(objval_ptr), NULL, \ (method_name), __VA_ARGS__) # define php_pq_read_property(objval_ptr, prop_name, tmpval_ptr) \ zend_read_property(Z_OBJCE_P(objval_ptr), Z_OBJ_P(objval_ptr), \ (prop_name), strlen(prop_name), 0, (tmpval_ptr)) # define php_pq_update_property(objval_ptr, prop_name, newval_ptr) \ zend_update_property(Z_OBJCE_P(objval_ptr), Z_OBJ_P(objval_ptr), \ (prop_name), strlen(prop_name), (newval_ptr)) #define php_pq_cast_object(objval_ptr, cast_type, retval_ptr) \ (Z_OBJ_HT_P(objval_ptr)->cast_object && \ SUCCESS == Z_OBJ_HT_P(objval_ptr)->cast_object(Z_OBJ_P(objval_ptr), (retval_ptr), (cast_type))) #else extern int php_pq_compare_index(const void *lptr, const void *rptr); # define zend_ce_countable spl_ce_Countable # define php_pq_call_method(objval_ptr, method_name, num_args, ...) \ zend_call_method_with_ ## num_args ## _params( \ (objval_ptr), NULL, NULL, \ (method_name), __VA_ARGS__) # define php_pq_read_property(objval_ptr, prop_name, tmpval_ptr) \ zend_read_property(Z_OBJCE_P(objval_ptr), (objval_ptr), \ (prop_name), strlen(prop_name), 0, (tmpval_ptr)) # define php_pq_update_property(objval_ptr, prop_name, newval_ptr) \ zend_update_property(Z_OBJCE_P(objval_ptr), (objval_ptr), \ (prop_name), strlen(prop_name), (newval_ptr)) #define php_pq_cast_object(objval_ptr, cast_type, retval_ptr) \ (Z_OBJ_HT_P(objval_ptr)->cast_object && \ SUCCESS == Z_OBJ_HT_P(objval_ptr)->cast_object(objval_ptr, (retval_ptr), (cast_type))) #endif #if PHP_VERSION_ID < 80100 # define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args) # define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args) #endif #ifndef ZEND_ACC_READONLY #define ZEND_ACC_READONLY 0 #endif extern PHP_MINIT_FUNCTION(pq_misc); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_module.c0000644000076500000240000000657514560227740014561 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pqcancel.h" #include "php_pqconn.h" #include "php_pqcopy.h" #include "php_pqcur.h" #include "php_pqexc.h" #include "php_pqlob.h" #include "php_pqres.h" #include "php_pqstm.h" #include "php_pqtxn.h" #include "php_pqtypes.h" ZEND_DECLARE_MODULE_GLOBALS(php_pq); static void php_pq_globals_init_once(zend_php_pq_globals *G) { memset(G, 0, sizeof(*G)); } #define PHP_MINIT_CALL(i) do { \ if (SUCCESS != PHP_MINIT(i)(type, module_number)) { \ return FAILURE; \ } \ } while(0) static PHP_MINIT_FUNCTION(pq) { ZEND_INIT_MODULE_GLOBALS(php_pq, php_pq_globals_init_once, NULL); PHP_MINIT_CALL(pq_misc); PHP_MINIT_CALL(pqexc); PHP_MINIT_CALL(pqconn); PHP_MINIT_CALL(pqcancel); PHP_MINIT_CALL(pqtypes); PHP_MINIT_CALL(pqres); PHP_MINIT_CALL(pqstm); PHP_MINIT_CALL(pqtxn); PHP_MINIT_CALL(pqcur); PHP_MINIT_CALL(pqcopy); PHP_MINIT_CALL(pqlob); return SUCCESS; } #define PHP_MSHUT_CALL(i) do { \ if (SUCCESS != PHP_MSHUTDOWN(i)(type, module_number)) { \ return FAILURE; \ } \ } while(0) static PHP_MSHUTDOWN_FUNCTION(pq) { PHP_MSHUT_CALL(pqlob); PHP_MSHUT_CALL(pqcopy); PHP_MSHUT_CALL(pqcur); PHP_MSHUT_CALL(pqtxn); PHP_MSHUT_CALL(pqstm); PHP_MSHUT_CALL(pqres); PHP_MSHUT_CALL(pqtypes); PHP_MSHUT_CALL(pqcancel); PHP_MSHUT_CALL(pqconn); return SUCCESS; } static PHP_MINFO_FUNCTION(pq) { #ifdef HAVE_PQLIBVERSION int libpq_v; #endif char libpq_version[10] = "pre-9.1"; php_info_print_table_start(); php_info_print_table_header(2, "PQ Support", "enabled"); php_info_print_table_row(2, "Extension Version", PHP_PQ_VERSION); php_info_print_table_end(); php_info_print_table_start(); php_info_print_table_header(3, "Used Library", "Compiled", "Linked"); #ifdef HAVE_PQLIBVERSION libpq_v = PQlibVersion(); php_pq_version_to_string(libpq_v, libpq_version, sizeof(libpq_version)); #endif php_info_print_table_row(3, "libpq", PHP_PQ_LIBVERSION, libpq_version); php_info_print_table_end(); } static const zend_function_entry pq_functions[] = { {0} }; static zend_module_dep pq_module_deps[] = { ZEND_MOD_REQUIRED("raphf") ZEND_MOD_REQUIRED("spl") ZEND_MOD_OPTIONAL("json") ZEND_MOD_END }; zend_module_entry pq_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, pq_module_deps, "pq", pq_functions, PHP_MINIT(pq), PHP_MSHUTDOWN(pq), NULL,/*PHP_RINIT(pq),*/ NULL,/*PHP_RSHUTDOWN(pq),*/ PHP_MINFO(pq), PHP_PQ_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PQ ZEND_GET_MODULE(pq) #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_object.c0000644000076500000240000002072114560227740014527 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "php_pq_object.h" #include "php_pq_misc.h" void *php_pq_object_create(zend_class_entry *ce, void *intern, size_t obj_size, zend_object_handlers *oh, HashTable *ph) { php_pq_object_t *o = ecalloc(1, obj_size + zend_object_properties_size(ce)); zend_object_std_init(&o->zo, ce); object_properties_init(&o->zo, ce); o->zo.handlers = oh; o->intern = intern; o->prophandler = ph; zend_hash_init(&o->gc, 0, NULL, NULL, 0); return o; } void php_pq_object_dtor(zend_object *o) { php_pq_object_t *obj = PHP_PQ_OBJ(NULL, o); zend_hash_destroy(&obj->gc); zend_object_std_dtor(o); } void php_pq_object_to_zval(void *o, zval *zv) { php_pq_object_t *obj = o; ZVAL_OBJ(zv, &obj->zo); Z_ADDREF_P(zv); } void php_pq_object_to_zval_no_addref(void *o, zval *zv) { php_pq_object_t *obj = o; ZVAL_OBJ(zv, &obj->zo); } void php_pq_object_addref(void *o) { php_pq_object_t *obj = o; #ifdef GC_ADDREF GC_ADDREF(&obj->zo); #else ++GC_REFCOUNT(&obj->zo); #endif } void php_pq_object_delref(void *o) { php_pq_object_t *obj = o; zval tmp; /* this should gc immediately */ ZVAL_OBJ(&tmp, &obj->zo); zval_ptr_dtor(&tmp); } struct apply_pi_to_ht_arg { HashTable *ht; php_pq_object_t *pq_obj; unsigned gc:1; }; static int apply_pi_to_ht(zval *p, void *a) { zend_property_info *pi = Z_PTR_P(p); struct apply_pi_to_ht_arg *arg = a; if (arg->gc) { php_pq_object_prophandler_t *handler; if ((handler = zend_hash_find_ptr(arg->pq_obj->prophandler, pi->name)) && handler->gc) { zval return_value; ZVAL_ARR(&return_value, arg->ht); handler->gc(arg->pq_obj, &return_value); } } else { zval tmp_prop, *property; #if PHP_VERSION_ID < 80000 zval zobj; ZVAL_OBJ(&zobj, &arg->pq_obj->zo); # if PHP_VERSION_ID < 70100 property = zend_read_property(arg->pq_obj->zo.ce, &zobj, pi->name->val, pi->name->len, 0, &tmp_prop); # else property = zend_read_property_ex(arg->pq_obj->zo.ce, &zobj, pi->name, 0, &tmp_prop); # endif #else property = zend_read_property_ex(arg->pq_obj->zo.ce, &arg->pq_obj->zo, pi->name, 0, &tmp_prop); #endif zend_hash_update(arg->ht, pi->name, property); } return ZEND_HASH_APPLY_KEEP; } static inline HashTable *php_pq_object_debug_info_ex(zend_object *object, int *temp) { struct apply_pi_to_ht_arg arg = {NULL}; *temp = 1; ALLOC_HASHTABLE(arg.ht); ZEND_INIT_SYMTABLE(arg.ht); arg.pq_obj = PHP_PQ_OBJ(NULL, object); arg.gc = 0; zend_hash_apply_with_argument(&arg.pq_obj->zo.ce->properties_info, apply_pi_to_ht, &arg); return arg.ht; } #if PHP_VERSION_ID >= 80000 HashTable *php_pq_object_debug_info(zend_object *object, int *temp) { return php_pq_object_debug_info_ex(object, temp); } #else HashTable *php_pq_object_debug_info(zval *object, int *temp) { return php_pq_object_debug_info_ex(Z_OBJ_P(object), temp); } #endif static inline HashTable *php_pq_object_properties_ex(zend_object *object, HashTable *props) { struct apply_pi_to_ht_arg arg = {NULL}; arg.ht = props; arg.pq_obj = PHP_PQ_OBJ(NULL, object); arg.gc = 0; zend_hash_apply_with_argument(&arg.pq_obj->zo.ce->properties_info, apply_pi_to_ht, &arg); return arg.ht; } #if PHP_VERSION_ID >= 80000 HashTable *php_pq_object_properties(zend_object *object) { return php_pq_object_properties_ex(object, zend_std_get_properties(object)); } #else HashTable *php_pq_object_properties(zval *object) { return php_pq_object_properties_ex(Z_OBJ_P(object), zend_std_get_properties(object)); } #endif static inline HashTable *php_pq_object_get_gc_ex(zend_object *object, HashTable *props, zval **table, int *n) { struct apply_pi_to_ht_arg arg = {NULL}; arg.pq_obj = PHP_PQ_OBJ(NULL, object); arg.ht = &arg.pq_obj->gc; arg.gc = 1; if (GC_REFCOUNT(arg.ht) == 1) { zend_hash_clean(arg.ht); zend_hash_copy(arg.ht, props, NULL); zend_hash_apply_with_argument(&arg.pq_obj->zo.ce->properties_info, apply_pi_to_ht, &arg); } *table = NULL; *n = 0; return arg.ht; } #if PHP_VERSION_ID >= 80000 HashTable *php_pq_object_get_gc(zend_object *object, zval **table, int *n) { return php_pq_object_get_gc_ex(object, zend_std_get_properties(object), table, n); } #else HashTable *php_pq_object_get_gc(zval *object, zval **table, int *n) { return php_pq_object_get_gc_ex(Z_OBJ_P(object), zend_std_get_properties(object), table, n); } #endif zend_class_entry *ancestor(zend_class_entry *ce) { while (ce->parent) { ce = ce->parent; } return ce; } static inline int php_pq_object_read_prop_ex(zend_object *object, zend_string *member, int type, zval *return_value) { php_pq_object_t *obj = PHP_PQ_OBJ(NULL, object); php_pq_object_prophandler_t *handler; if (!obj->intern) { php_error(E_RECOVERABLE_ERROR, "%s not initialized", ancestor(obj->zo.ce)->name->val); } else if (!(handler = zend_hash_find_ptr(obj->prophandler, member)) || !handler->read) { /* default handler */ } else if (type != BP_VAR_R) { php_error(E_WARNING, "Cannot access %s properties by reference or array key/index", ancestor(obj->zo.ce)->name->val); } else { handler->read(obj, return_value); return SUCCESS; } return FAILURE; } #if PHP_VERSION_ID >= 80000 zval *php_pq_object_read_prop(zend_object *object, zend_string *member, int type, void **cache_slot, zval *tmp) { if (SUCCESS != php_pq_object_read_prop_ex(object, member, type, tmp)) { return zend_std_read_property(object, member, type, cache_slot, tmp); } zend_std_write_property(object, member, tmp, cache_slot); if (cache_slot) { *cache_slot = NULL; } return tmp; } #else zval *php_pq_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *tmp) { zend_string *member_str = zval_get_string(member); if (SUCCESS != php_pq_object_read_prop_ex(Z_OBJ_P(object), member_str, type, tmp)) { zend_string_release(member_str); return zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp); } zend_string_release(member_str); zend_std_write_property(object, member, tmp, cache_slot); if (cache_slot) { *cache_slot = NULL; } return tmp; } #endif static inline int php_pq_object_write_prop_ex(zend_object *object, zend_string *member, zval *value) { php_pq_object_t *obj = PHP_PQ_OBJ(NULL, object); php_pq_object_prophandler_t *handler; if (!obj->intern) { php_error(E_RECOVERABLE_ERROR, "%s not initialized", ancestor(obj->zo.ce)->name->val); } else if (!(handler = zend_hash_find_ptr(obj->prophandler, member))) { /* default handler */ } else { if (handler->write) { handler->write(obj, value); } return SUCCESS; } return FAILURE; } #if PHP_VERSION_ID >= 80000 zval *php_pq_object_write_prop(zend_object *object, zend_string *member, zval *value, void **cache_slot) { if (SUCCESS != php_pq_object_write_prop_ex(object, member, value)) { return zend_std_write_property(object, member, value, cache_slot); } return value; } #elif PHP_VERSION_ID >= 70400 zval *php_pq_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot) { zend_string *member_str = zval_get_string(member); if (SUCCESS != php_pq_object_write_prop_ex(Z_OBJ_P(object), member_str, value)) { value = zend_std_write_property(object, member, value, cache_slot); } zend_string_release(member_str); return value; } #else void php_pq_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot) { zend_string *member_str = zval_get_string(member); if (SUCCESS != php_pq_object_write_prop_ex(Z_OBJ_P(object), member_str, value)) { zend_std_write_property(object, member, value, cache_slot); } zend_string_release(member_str); } #endif #if PHP_VERSION_ID >= 80000 zval *php_pq_object_get_prop_ptr_null(zend_object *object, zend_string *member, int type, void **cache_slot) { return NULL; } #else zval *php_pq_object_get_prop_ptr_null(zval *object, zval *member, int type, void **cache_slot) { return NULL; } #endif void php_pq_object_prophandler_dtor(zval *zv) { pefree(Z_PTR_P(zv), 1); } pq-2.2.3/src/php_pq_object.h0000644000076500000240000000630714560227740014540 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQ_OBJECT_H #define PHP_PQ_OBJECT_H #define PHP_PQ_OBJ_DECL(_intern_type) \ _intern_type intern; \ HashTable *prophandler; \ HashTable gc; \ zend_object zo; typedef struct php_pq_object { PHP_PQ_OBJ_DECL(void *) } php_pq_object_t; static inline void *PHP_PQ_OBJ(zval *zv, zend_object *zo) { if (zv) { zo = Z_OBJ_P(zv); } return (void *) (((char *) zo) - zo->handlers->offset); } extern zend_class_entry *ancestor(zend_class_entry *ce); typedef void (*php_pq_object_prophandler_func_t)(void *o, zval *return_value); typedef struct php_pq_object_prophandler { php_pq_object_prophandler_func_t read; php_pq_object_prophandler_func_t write; php_pq_object_prophandler_func_t gc; } php_pq_object_prophandler_t; extern void php_pq_object_prophandler_dtor(zval *zv); extern void *php_pq_object_create(zend_class_entry *ce, void *intern, size_t obj_size, zend_object_handlers *oh, HashTable *ph); extern void php_pq_object_dtor(zend_object *obj); extern void php_pq_object_to_zval(void *o, zval *zv); extern void php_pq_object_to_zval_no_addref(void *o, zval *zv); extern void php_pq_object_addref(void *o); extern void php_pq_object_delref(void *o); #if PHP_VERSION_ID >= 80000 extern HashTable *php_pq_object_debug_info(zend_object *object, int *temp); extern HashTable *php_pq_object_properties(zend_object *object); extern HashTable *php_pq_object_get_gc(zend_object *object, zval **table, int *n); extern zval *php_pq_object_read_prop(zend_object *object, zend_string *member, int type, void **cache_slot, zval *tmp); extern zval *php_pq_object_write_prop(zend_object *object, zend_string *member, zval *value, void **cache_slot); extern zval *php_pq_object_get_prop_ptr_null(zend_object *object, zend_string *member, int type, void **cache_slot); #else extern HashTable *php_pq_object_debug_info(zval *object, int *temp); extern HashTable *php_pq_object_properties(zval *object); extern HashTable *php_pq_object_get_gc(zval *object, zval **table, int *n); extern zval *php_pq_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *tmp); # if PHP_VERSION_ID >= 70400 extern zval *php_pq_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot); # else extern void php_pq_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot); # endif extern zval *php_pq_object_get_prop_ptr_null(zval *object, zval *member, int type, void **cache_slot); #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_params.c0000644000076500000240000002137714560227740014554 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "php_pq.h" #include "php_pq_params.h" #include "php_pq_misc.h" #undef PHP_PQ_TYPE #include "php_pq_type.h" void php_pq_params_set_type_conv(php_pq_params_t *p, HashTable *conv) { zend_hash_clean(&p->type.conv); zend_hash_copy(&p->type.conv, conv, (copy_ctor_func_t) zval_add_ref); } static int apply_to_oid(zval *ztype, void *arg) { Oid **types = arg; **types = zval_get_long(ztype); ++*types; return ZEND_HASH_APPLY_KEEP; } unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids) { p->type.count = oids ? zend_hash_num_elements(oids) : 0; if (p->type.oids) { efree(p->type.oids); p->type.oids = NULL; } if (p->type.count) { Oid *ptr = ecalloc(p->type.count + 1, sizeof(*p->type.oids)); /* +1 for when less types than params are specified */ p->type.oids = ptr; zend_hash_apply_with_argument(oids, apply_to_oid, &ptr); } return p->type.count; } unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type) { p->type.oids = safe_erealloc(p->type.oids, ++p->type.count, sizeof(*p->type.oids), sizeof(*p->type.oids)); p->type.oids[p->type.count] = 0; p->type.oids[p->type.count-1] = type; return p->type.count; } static zend_string *object_param_to_string(php_pq_params_t *p, zval *zobj, Oid type) { #ifdef PHP_PQ_OID_JSON smart_str str = {0}; #endif switch (type) { #ifdef PHP_PQ_OID_JSON # ifdef PHP_PQ_OID_JSONB case PHP_PQ_OID_JSONB: # endif case PHP_PQ_OID_JSON: # if PHP_VERSION_ID >= 70100 JSON_G(encode_max_depth) = PHP_JSON_PARSER_DEFAULT_DEPTH; # endif php_json_encode(&str, zobj, PHP_JSON_UNESCAPED_UNICODE); smart_str_0(&str); return str.s; #endif case PHP_PQ_OID_DATE: return php_pqdt_to_string(zobj, "Y-m-d"); #ifdef PHP_PQ_OID_ABSTIME case PHP_PQ_OID_ABSTIME: return php_pqdt_to_string(zobj, "Y-m-d H:i:s"); #endif case PHP_PQ_OID_TIMESTAMP: return php_pqdt_to_string(zobj, "Y-m-d H:i:s.u"); case PHP_PQ_OID_TIMESTAMPTZ: return php_pqdt_to_string(zobj, "Y-m-d H:i:s.uO"); } return zval_get_string(zobj); } struct apply_to_param_from_array_arg { php_pq_params_t *params; unsigned index; smart_str *buffer; Oid type; char delim; zval *zconv; }; static int apply_to_param_from_array(zval *zparam, void *arg_ptr) { struct apply_to_param_from_array_arg subarg, *arg = arg_ptr; char *tmp; size_t len; zend_string *str, *tmpstr; if (arg->index++) { smart_str_appendc(arg->buffer, arg->delim); } if (arg->zconv) { zval ztype, rv; ZVAL_LONG(&ztype, arg->type); php_pq_call_method(arg->zconv, "converttostring", 2, &rv, zparam, &ztype); tmpstr = zval_get_string(&rv); zval_ptr_dtor(&rv); goto append_string; } else { again: switch (Z_TYPE_P(zparam)) { case IS_REFERENCE: ZVAL_DEREF(zparam); goto again; case IS_NULL: smart_str_appends(arg->buffer, "NULL"); break; case IS_TRUE: smart_str_appends(arg->buffer, "t"); break; case IS_FALSE: smart_str_appends(arg->buffer, "f"); break; case IS_LONG: smart_str_append_long(arg->buffer, Z_LVAL_P(zparam)); break; case IS_DOUBLE: len = spprintf(&tmp, 0, "%F", Z_DVAL_P(zparam)); smart_str_appendl(arg->buffer, tmp, len); efree(tmp); break; case IS_ARRAY: subarg = *arg; subarg.index = 0; smart_str_appendc(arg->buffer, '{'); zend_hash_apply_with_argument(Z_ARRVAL_P(zparam), apply_to_param_from_array, &subarg); smart_str_appendc(arg->buffer, '}'); break; case IS_OBJECT: if ((tmpstr = object_param_to_string(arg->params, zparam, arg->type))) { goto append_string; } /* no break */ default: tmpstr = zval_get_string(zparam); append_string: #if PHP_VERSION_ID < 70300 str = php_addslashes(tmpstr, 1); #else str = php_addslashes(tmpstr); zend_string_release(tmpstr); #endif smart_str_appendc(arg->buffer, '"'); smart_str_appendl(arg->buffer, str->val, str->len); smart_str_appendc(arg->buffer, '"'); zend_string_release(str); break; } } ++arg->index; return ZEND_HASH_APPLY_KEEP; } static zend_string *array_param_to_string(php_pq_params_t *p, zval *zarr, Oid type) { smart_str s = {0}; struct apply_to_param_from_array_arg arg = {NULL}; switch (type) { #ifdef PHP_PQ_OID_JSON # ifdef PHP_PQ_OID_JSONB case PHP_PQ_OID_JSONB: # endif case PHP_PQ_OID_JSON: php_json_encode(&s, zarr, PHP_JSON_UNESCAPED_UNICODE); break; #endif default: arg.params = p; arg.buffer = &s; arg.type = PHP_PQ_TYPE_OF_ARRAY(type); arg.delim = PHP_PQ_DELIM_OF_ARRAY(type); arg.zconv = zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type)); smart_str_appendc(arg.buffer, '{'); SEPARATE_ZVAL(zarr); zend_hash_apply_with_argument(Z_ARRVAL_P(zarr), apply_to_param_from_array, &arg); smart_str_appendc(arg.buffer, '}'); break; } smart_str_0(&s); return s.s; } static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval *zpp) { zval *zconv = NULL; Oid type = p->type.count > index ? p->type.oids[index] : 0; if (type && (zconv = zend_hash_index_find(&p->type.conv, type))) { zval ztype, rv; ZVAL_NULL(&rv); ZVAL_LONG(&ztype, type); php_pq_call_method(zconv, "converttostring", 2, &rv, zpp, &ztype); convert_to_string(&rv); p->param.strings[index] = Z_STRVAL_P(&rv); zend_hash_next_index_insert(&p->param.dtor, &rv); } else { zval tmp; zend_string *str = NULL; char tmp_str[64]; size_t tmp_len = 0; again: switch (Z_TYPE_P(zpp)) { case IS_REFERENCE: ZVAL_DEREF(zpp); goto again; case IS_NULL: p->param.strings[index] = NULL; return; case IS_TRUE: p->param.strings[index] = "t"; break; case IS_FALSE: p->param.strings[index] = "f"; return; case IS_DOUBLE: tmp_len = slprintf(tmp_str, sizeof(tmp_str), "%F", Z_DVAL_P(zpp)); str = zend_string_init(tmp_str, tmp_len, 0); break; case IS_ARRAY: str = array_param_to_string(p, zpp, type); break; case IS_OBJECT: if ((str = object_param_to_string(p, zpp, type))) { break; } /* no break */ default: str = zval_get_string(zpp); break; } if (str) { ZVAL_STR(&tmp, str); p->param.strings[index] = Z_STRVAL(tmp); zend_hash_next_index_insert(&p->param.dtor, &tmp); } } } struct apply_to_params_arg { php_pq_params_t *params; unsigned index; }; static int apply_to_params(zval *zp, void *arg_ptr) { struct apply_to_params_arg *arg = arg_ptr; ZVAL_DEREF(zp); SEPARATE_ZVAL(zp); php_pq_params_set_param(arg->params, arg->index++, zp); return ZEND_HASH_APPLY_KEEP; } unsigned php_pq_params_add_param(php_pq_params_t *p, zval *param) { p->param.strings = safe_erealloc(p->param.strings, ++p->param.count, sizeof(*p->param.strings), 0); php_pq_params_set_param(p, p->param.count-1, param); return p->type.count; } unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params) { p->param.count = params ? zend_hash_num_elements(params) : 0; if (p->param.strings) { efree(p->param.strings); p->param.strings = NULL; } zend_hash_clean(&p->param.dtor); if (p->param.count) { struct apply_to_params_arg arg = {p, 0}; p->param.strings = ecalloc(p->param.count, sizeof(*p->param.strings)); zend_hash_apply_with_argument(params, apply_to_params, &arg); } return p->param.count; } void php_pq_params_free(php_pq_params_t **p) { if (*p) { php_pq_params_set_type_oids(*p, NULL); php_pq_params_set_params(*p, NULL); zend_hash_destroy(&(*p)->param.dtor); zend_hash_destroy(&(*p)->type.conv); efree(*p); *p = NULL; } } php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params) { php_pq_params_t *p = ecalloc(1, sizeof(*p)); zend_hash_init(&p->type.conv, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&p->param.dtor, 0, NULL, ZVAL_PTR_DTOR, 0); if (conv) { php_pq_params_set_type_conv(p, conv); } if (oids) { php_pq_params_set_type_oids(p, oids); } if (params) { php_pq_params_set_params(p, params); } return p; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pq_params.h0000644000076500000240000000311014560227740014542 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQ_PARAMS_H #define PHP_PQ_PARAMS_H typedef struct php_pq_params { struct { HashTable conv; unsigned count; Oid *oids; } type; struct { HashTable dtor; unsigned count; char **strings; } param; } php_pq_params_t; extern php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params); extern void php_pq_params_free(php_pq_params_t **p); extern unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params); extern unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids); extern unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type); extern unsigned php_pq_params_add_param(php_pq_params_t *p, zval *param); extern void php_pq_params_set_type_conv(php_pq_params_t *p, HashTable *conv); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqres.c0000644000076500000240000011405614560227740013720 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqres.h" #undef PHP_PQ_TYPE #include "php_pq_type.h" zend_class_entry *php_pqres_class_entry; static zend_object_handlers php_pqres_object_handlers; static HashTable php_pqres_object_prophandlers; static zend_object_iterator_funcs php_pqres_iterator_funcs; static inline zend_object_iterator *php_pqres_iterator_init_ex(zend_class_entry *ce, zval *object, int by_ref) { php_pqres_iterator_t *iter; zval tmp, *zfetch_type; iter = ecalloc(1, sizeof(*iter)); iter->zi.funcs = &php_pqres_iterator_funcs; ZVAL_COPY_VALUE(&iter->zi.data, object); zfetch_type = php_pq_read_property(object, "fetchType", &tmp); iter->fetch_type = zval_get_long(zfetch_type); #if DBG_GC 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)); #endif return (zend_object_iterator *) iter; } static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref) { zend_object_iterator *iter = php_pqres_iterator_init_ex(ce, object, by_ref); zend_iterator_init(iter); Z_ADDREF_P(object); return iter; } static void php_pqres_internal_iterator_init(zval *zobj) { php_pqres_object_t *obj = PHP_PQ_OBJ(zobj, NULL); obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init_ex(Z_OBJCE_P(zobj), zobj, 0); obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter); } static inline void php_pqres_iterator_dtor_ex(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; #if DBG_GC fprintf(stderr, "FREE iter(#%d) rc=%d %p\n", iter->zi.std.handle, GC_REFCOUNT(&iter->zi.std), iter); #endif if (!Z_ISUNDEF(iter->current_val)) { zval_ptr_dtor(&iter->current_val); ZVAL_UNDEF(&iter->current_val); } } static void php_pqres_iterator_dtor(zend_object_iterator *i) { php_pqres_iterator_dtor_ex(i); zval_ptr_dtor(&i->data); } static void php_pqres_internal_iterator_dtor(php_pqres_object_t *obj) { if (obj->intern && obj->intern->iter) { php_pqres_iterator_dtor_ex((zend_object_iterator *) obj->intern->iter); efree(obj->intern->iter); obj->intern->iter = NULL; } } static ZEND_RESULT_CODE php_pqres_iterator_valid(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; php_pqres_object_t *obj = PHP_PQ_OBJ(&i->data, NULL); switch (PQresultStatus(obj->intern->res)) { case PGRES_TUPLES_OK: #ifdef HAVE_PGRES_SINGLE_TUPLE case PGRES_SINGLE_TUPLE: #endif if (PQntuples(obj->intern->res) <= iter->index) { return FAILURE; } break; default: return FAILURE; } return SUCCESS; } #define PHP_PQRES_JSON_OPTIONS(res) \ (php_pqres_fetch_type(res) != PHP_PQRES_FETCH_OBJECT ? PHP_JSON_OBJECT_AS_ARRAY:0) zval *php_pqres_typed_zval(php_pqres_t *res, Oid typ, zval *zv) { zval *zconv; HashTable *ht; zend_string *str; if ((zconv = zend_hash_index_find(&res->converters, typ))) { zval ztype, rv; ZVAL_NULL(&rv); ZVAL_LONG(&ztype, typ); php_pq_call_method(zconv, "convertfromstring", 2, &rv, zv, &ztype); zval_ptr_dtor(zv); ZVAL_ZVAL(zv, &rv, 0, 0); return zv; } str = zval_get_string(zv); zval_ptr_dtor(zv); switch (typ) { case PHP_PQ_OID_BOOL: if (!(res->auto_convert & PHP_PQRES_CONV_BOOL)) { goto noconversion; } ZVAL_BOOL(zv, *str->val == 't'); break; case PHP_PQ_OID_INT8: case PHP_PQ_OID_TID: case PHP_PQ_OID_INT4: case PHP_PQ_OID_INT2: case PHP_PQ_OID_XID: case PHP_PQ_OID_OID: if (!(res->auto_convert & PHP_PQRES_CONV_INT)) { goto noconversion; } { zend_long lval; double dval; switch (is_numeric_str_function(str, &lval, &dval)) { case IS_LONG: ZVAL_LONG(zv, lval); break; case IS_DOUBLE: ZVAL_DOUBLE(zv, dval); break; default: goto noconversion; } } break; case PHP_PQ_OID_FLOAT4: case PHP_PQ_OID_FLOAT8: if (!(res->auto_convert & PHP_PQRES_CONV_FLOAT)) { goto noconversion; } ZVAL_DOUBLE(zv, zend_strtod(str->val, NULL)); break; case PHP_PQ_OID_DATE: if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { goto noconversion; } php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d", NULL); break; #ifdef PHP_PQ_OID_ABSTIME case PHP_PQ_OID_ABSTIME: if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { goto noconversion; } php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s", NULL); break; #endif case PHP_PQ_OID_TIMESTAMP: if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { goto noconversion; } php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.u", NULL); break; case PHP_PQ_OID_TIMESTAMPTZ: if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { goto noconversion; } php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.uO", NULL); break; #ifdef PHP_PQ_OID_JSON # ifdef PHP_PQ_OID_JSONB case PHP_PQ_OID_JSONB: # endif case PHP_PQ_OID_JSON: if (!(res->auto_convert & PHP_PQRES_CONV_JSON)) { goto noconversion; } php_json_decode_ex(zv, str->val, str->len, PHP_PQRES_JSON_OPTIONS(res), 512 /* PHP_JSON_DEFAULT_DEPTH */); break; #endif case PHP_PQ_OID_BYTEA: if (!(res->auto_convert & PHP_PQRES_CONV_BYTEA)) { goto noconversion; } else { size_t to_len; char *to_str = (char *) PQunescapeBytea((unsigned char *) str->val, &to_len); if (!to_str) { ZVAL_NULL(zv); php_error_docref(NULL, E_WARNING, "Failed to unsescape BYTEA: '%s'", str->val); } else { ZVAL_STRINGL(zv, to_str, to_len); PQfreemem(to_str); } } break; default: if (!(res->auto_convert & PHP_PQRES_CONV_ARRAY)) { goto noconversion; } if (PHP_PQ_TYPE_IS_ARRAY(typ) && (ht = php_pq_parse_array(res, str->val, str->len, PHP_PQ_TYPE_OF_ARRAY(typ)))) { ZVAL_ARR(zv, ht); } else { goto noconversion; } break; } zend_string_release(str); return zv; noconversion: ZVAL_STR(zv, str); return zv; } static inline zval *php_pqres_get_col(php_pqres_t *r, unsigned row, unsigned col, zval *zv) { if (PQgetisnull(r->res, row, col)) { ZVAL_NULL(zv); } else { ZVAL_STRINGL(zv, PQgetvalue(r->res, row, col), PQgetlength(r->res, row, col)); zv = php_pqres_typed_zval(r, PQftype(r->res, col), zv); } return zv; } 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) { if (PQgetisnull(r->res, row, col)) { switch (fetch_type) { case PHP_PQRES_FETCH_OBJECT: add_property_null(data, PQfname(r->res, col)); break; case PHP_PQRES_FETCH_ASSOC: add_assoc_null(data, PQfname(r->res, col)); break; case PHP_PQRES_FETCH_ARRAY: add_index_null(data, col); break; } } else { zval zv; ZVAL_STRINGL(&zv, PQgetvalue(r->res, row, col), PQgetlength(r->res, row, col)); php_pqres_typed_zval(r, PQftype(r->res, col), &zv); switch (fetch_type) { case PHP_PQRES_FETCH_OBJECT: add_property_zval(data, PQfname(r->res, col), &zv); zval_ptr_dtor(&zv); break; case PHP_PQRES_FETCH_ASSOC: add_assoc_zval(data, PQfname(r->res, col), &zv); break; case PHP_PQRES_FETCH_ARRAY: add_index_zval(data, col, &zv); break; } } } zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval *data) { int c, cols = PQnfields(res); php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event); if (Z_TYPE_P(data) != IS_OBJECT && Z_TYPE_P(data) != IS_ARRAY) { if (PHP_PQRES_FETCH_OBJECT == fetch_type) { object_init(data); } else { array_init_size(data, cols); } } if (PQntuples(res) > row) { for (c = 0; c < cols; ++c) { php_pqres_add_col_to_zval(res_obj->intern, row, c, fetch_type, data); } } return data; } static zval *php_pqres_iterator_current(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; php_pqres_object_t *obj = PHP_PQ_OBJ(&i->data, NULL); if (Z_ISUNDEF(iter->current_val)) { php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, &iter->current_val); } return &iter->current_val; } static void php_pqres_iterator_key(zend_object_iterator *i, zval *key) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; ZVAL_LONG(key, iter->index); } static void php_pqres_iterator_invalidate(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; if (!Z_ISUNDEF(iter->current_val)) { zval_ptr_dtor(&iter->current_val); ZVAL_UNDEF(&iter->current_val); } } static void php_pqres_iterator_next(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; php_pqres_iterator_invalidate(i); ++iter->index; } static void php_pqres_iterator_rewind(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; php_pqres_iterator_invalidate(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) */ php_pqres_iterator_invalidate #if PHP_VERSION_ID >= 80000 , NULL #endif }; static inline ZEND_RESULT_CODE php_pqres_count_elements_ex(zend_object *object, zend_long *count) { php_pqres_object_t *obj = PHP_PQ_OBJ(NULL, object); if (!obj->intern) { return FAILURE; } else { *count = (zend_long) PQntuples(obj->intern->res); return SUCCESS; } } #if PHP_VERSION_ID >= 80000 static ZEND_RESULT_CODE php_pqres_count_elements(zend_object *object, zend_long *count) { return php_pqres_count_elements_ex(object, count); } #else static ZEND_RESULT_CODE php_pqres_count_elements(zval *object, zend_long *count) { return php_pqres_count_elements_ex(Z_OBJ_P(object), count); } #endif ZEND_RESULT_CODE php_pqres_success(PGresult *res) { zval zexc, zsqlstate; switch (PQresultStatus(res)) { case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: ZVAL_OBJ(&zexc, throw_exce(EX_SQL, "%s", PHP_PQresultErrorMessage(res))); ZVAL_STRING(&zsqlstate, PQresultErrorField(res, PG_DIAG_SQLSTATE)); php_pq_update_property(&zexc, "sqlstate", &zsqlstate); zval_ptr_dtor(&zsqlstate); return FAILURE; default: return SUCCESS; } } php_pqres_object_t *php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *conn_obj) { php_pqres_object_t *obj; php_pqres_t *r = ecalloc(1, sizeof(*r)); r->res = res; zend_hash_init(&r->bound, 0, 0, ZVAL_PTR_DTOR, 0); zend_hash_init(&r->converters, zend_hash_num_elements(&conn_obj->intern->converters), 0, ZVAL_PTR_DTOR, 0); zend_hash_copy(&r->converters, &conn_obj->intern->converters, (copy_ctor_func_t) zval_add_ref); r->auto_convert = conn_obj->intern->default_auto_convert; r->default_fetch_type = conn_obj->intern->default_fetch_type; obj = php_pqres_create_object_ex(php_pqres_class_entry, r); PQresultSetInstanceData(res, php_pqconn_event, obj); return obj; } php_pqres_fetch_t php_pqres_fetch_type(php_pqres_t *res) { return res->iter ? res->iter->fetch_type : res->default_fetch_type; } static void php_pqres_object_free(zend_object *o) { php_pqres_object_t *obj = PHP_PQ_OBJ(NULL, o); if (obj->intern) { if (obj->intern->res) { PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL); PQclear(obj->intern->res); obj->intern->res = NULL; } php_pqres_internal_iterator_dtor(obj); zend_hash_destroy(&obj->intern->bound); zend_hash_destroy(&obj->intern->converters); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqres_object_t *php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqres_object_t), &php_pqres_object_handlers, &php_pqres_object_prophandlers); } static zend_object *php_pqres_create_object(zend_class_entry *class_type) { return &php_pqres_create_object_ex(class_type, NULL)->zo; } static void php_pqres_object_read_status(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(PQresultStatus(obj->intern->res)); } static void php_pqres_object_read_status_message(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_STRING(PQresStatus(PQresultStatus(obj->intern->res))+sizeof("PGRES")); } static void php_pqres_object_read_error_message(void *o, zval *return_value) { php_pqres_object_t *obj = o; char *error = PHP_PQresultErrorMessage(obj->intern->res); if (error) { RETVAL_STRING(error); } else { RETVAL_NULL(); } } #ifndef PG_DIAG_SEVERITY # define PG_DIAG_SEVERITY 'S' #endif #ifndef PG_DIAG_SQLSTATE # define PG_DIAG_SQLSTATE 'C' #endif #ifndef PG_DIAG_MESSAGE_PRIMARY # define PG_DIAG_MESSAGE_PRIMARY 'M' #endif #ifndef PG_DIAG_MESSAGE_DETAIL # define PG_DIAG_MESSAGE_DETAIL 'D' #endif #ifndef PG_DIAG_MESSAGE_HINT # define PG_DIAG_MESSAGE_HINT 'H' #endif #ifndef PG_DIAG_STATEMENT_POSITION # define PG_DIAG_STATEMENT_POSITION 'P' #endif #ifndef PG_DIAG_INTERNAL_POSITION # define PG_DIAG_INTERNAL_POSITION 'p' #endif #ifndef PG_DIAG_INTERNAL_QUERY # define PG_DIAG_INTERNAL_QUERY 'q' #endif #ifndef PG_DIAG_CONTEXT # define PG_DIAG_CONTEXT 'W' #endif #ifndef PG_DIAG_SCHEMA_NAME # define PG_DIAG_SCHEMA_NAME 's' #endif #ifndef PG_DIAG_TABLE_NAME # define PG_DIAG_TABLE_NAME 't' #endif #ifndef PG_DIAG_COLUMN_NAME # define PG_DIAG_COLUMN_NAME 'c' #endif #ifndef PG_DIAG_DATATYPE_NAME # define PG_DIAG_DATATYPE_NAME 'd' #endif #ifndef PG_DIAG_CONSTRAINT_NAME # define PG_DIAG_CONSTRAINT_NAME 'n' #endif #ifndef PG_DIAG_SOURCE_FILE # define PG_DIAG_SOURCE_FILE 'F' #endif #ifndef PG_DIAG_SOURCE_LINE # define PG_DIAG_SOURCE_LINE 'L' #endif #ifndef PG_DIAG_SOURCE_FUNCTION # define PG_DIAG_SOURCE_FUNCTION 'R' #endif static void php_pqres_object_read_diag(void *o, zval *return_value) { php_pqres_object_t *obj = o; int i; struct { char code; const char *const name; } diag[] = { {PG_DIAG_SEVERITY, "severity"}, {PG_DIAG_SQLSTATE, "sqlstate"}, {PG_DIAG_MESSAGE_PRIMARY, "message_primary"}, {PG_DIAG_MESSAGE_DETAIL, "message_detail"}, {PG_DIAG_MESSAGE_HINT, "message_hint"}, {PG_DIAG_STATEMENT_POSITION,"statement_position"}, {PG_DIAG_INTERNAL_POSITION, "internal_position"}, {PG_DIAG_INTERNAL_QUERY, "internal_query"}, {PG_DIAG_CONTEXT, "context"}, {PG_DIAG_SCHEMA_NAME, "schema_name"}, {PG_DIAG_TABLE_NAME, "table_name"}, {PG_DIAG_COLUMN_NAME, "column_name"}, {PG_DIAG_DATATYPE_NAME, "datatype_name"}, {PG_DIAG_CONSTRAINT_NAME, "constraint_name"}, {PG_DIAG_SOURCE_FILE, "source_file"}, {PG_DIAG_SOURCE_LINE, "source_line"}, {PG_DIAG_SOURCE_FUNCTION, "source_function"}, }; array_init_size(return_value, 32); for (i = 0; i < sizeof(diag)/sizeof(diag[0]); ++i) { char *value = PQresultErrorField(obj->intern->res, diag[i].code); if (value) { add_assoc_string(return_value, diag[i].name, value); } else { add_assoc_null(return_value, diag[i].name); } } } static void php_pqres_object_read_num_rows(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(PQntuples(obj->intern->res)); } static void php_pqres_object_read_num_cols(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(PQnfields(obj->intern->res)); } static void php_pqres_object_read_affected_rows(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res))); } static void php_pqres_object_read_fetch_type(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(php_pqres_fetch_type(obj->intern)); } static void php_pqres_object_write_fetch_type(void *o, zval *value) { php_pqres_object_t *obj = o; if (!obj->intern->iter) { zval object; ZVAL_OBJ(&object, &obj->zo); php_pqres_internal_iterator_init(&object); } obj->intern->iter->fetch_type = zval_get_long(value); } static void php_pqres_object_read_auto_conv(void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(obj->intern->auto_convert); } static void php_pqres_object_write_auto_conv(void *o, zval *value) { php_pqres_object_t *obj = o; obj->intern->auto_convert = zval_get_long(value); } static ZEND_RESULT_CODE php_pqres_iteration(zval *zobj, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval *row) { ZEND_RESULT_CODE rv; php_pqres_fetch_t orig_fetch; if (!obj) { obj = PHP_PQ_OBJ(zobj, NULL); } if (obj->intern->iter) { obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter); } else { php_pqres_internal_iterator_init(zobj); } orig_fetch = obj->intern->iter->fetch_type; obj->intern->iter->fetch_type = fetch_type; if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter))) { zval *tmp = obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter); ZVAL_COPY_VALUE(row, tmp); } obj->intern->iter->fetch_type = orig_fetch; return rv; } typedef struct php_pqres_col { char *name; int num; } php_pqres_col_t; static ZEND_RESULT_CODE column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *col) { zend_long index = -1; char *name = NULL; if (!zcol) { index = 0; } else { switch (Z_TYPE_P(zcol)) { case IS_NULL: index = 0; break; case IS_LONG: index = Z_LVAL_P(zcol); break; default: convert_to_string(zcol); /* no break */ case IS_STRING: if (!is_numeric_string(Z_STRVAL_P(zcol), Z_STRLEN_P(zcol), &index, NULL, 0)) { name = Z_STRVAL_P(zcol); } break; } } if (name) { col->name = name; col->num = PQfnumber(obj->intern->res, name); } else { col->name = PQfname(obj->intern->res, index); col->num = index; } if (!col->name) { php_error_docref(NULL, E_WARNING, "Failed to find column at index " ZEND_LONG_FMT, index); return FAILURE; } if (col->num == -1) { php_error_docref(NULL, E_WARNING, "Failed to find column with name '%s'", name); return FAILURE; } return SUCCESS; } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind, 0, 0, 2) ZEND_ARG_INFO(0, col) ZEND_ARG_INFO(1, ref) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, bind) { zval *zcol, *zref; zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z/z", &zcol, &zref); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { php_pqres_col_t col; if (SUCCESS != column_nn(obj, zcol, &col)) { RETVAL_FALSE; } else { Z_TRY_ADDREF_P(zref); if (!zend_hash_index_update(&obj->intern->bound, col.num, zref)) { php_error_docref(NULL, E_WARNING, "Failed to bind column %s@%d", col.name, col.num); RETVAL_FALSE; } else { zend_hash_sort(&obj->intern->bound, php_pq_compare_index, 0); RETVAL_TRUE; } } } } } static int apply_bound(zval *zbound, int argc, va_list argv, zend_hash_key *key) { zval *zvalue; zval *zrow = va_arg(argv, zval *); ZEND_RESULT_CODE *rv = va_arg(argv, ZEND_RESULT_CODE *); if (!(zvalue = zend_hash_index_find(Z_ARRVAL_P(zrow), key->h))) { php_error_docref(NULL, E_WARNING, "Failed to find column ad index " ZEND_ULONG_FMT, key->h); *rv = FAILURE; return ZEND_HASH_APPLY_STOP; } else { ZVAL_DEREF(zbound); zval_dtor(zbound); ZVAL_COPY(zbound, zvalue); *rv = SUCCESS; return ZEND_HASH_APPLY_KEEP; } } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchBound) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { zval row; zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row)) { zend_hash_apply_with_arguments(&obj->intern->bound, apply_bound, 2, &row, &rv); if (SUCCESS == rv) { RETVAL_ZVAL(&row, 1, 0); } } zend_restore_error_handling(&zeh); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0) ZEND_ARG_INFO(0, fetch_type) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchRow) { zend_error_handling zeh; php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); zend_long fetch_type = -1; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { zval row; if (fetch_type == -1) { fetch_type = php_pqres_fetch_type(obj->intern); } zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); if (SUCCESS == php_pqres_iteration(getThis(), obj, fetch_type, &row)) { RETVAL_ZVAL(&row, 1, 0); } zend_restore_error_handling(&zeh); } } } static zval *column_at(zval *row, int col) { zval *data = NULL; HashTable *ht = HASH_OF(row); int count = zend_hash_num_elements(ht); if (col >= count) { php_error_docref(NULL, E_WARNING, "Column index %d exceeds column count %d", col, count); } else { zend_hash_internal_pointer_reset(ht); while (col-- > 0) { zend_hash_move_forward(ht); } data = zend_hash_get_current_data(ht); } return data; } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 1) ZEND_ARG_INFO(1, ref) ZEND_ARG_INFO(0, col) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchCol) { zend_error_handling zeh; zval *zcol = NULL, *zref; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z|z/!", &zref, &zcol); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { zval row; zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); if (SUCCESS == php_pqres_iteration(getThis(), obj, php_pqres_fetch_type(obj->intern), &row)) { php_pqres_col_t col; if (SUCCESS != column_nn(obj, zcol, &col)) { RETVAL_FALSE; } else { zval *zres = column_at(&row, col.num); if (!zres) { RETVAL_FALSE; } else { ZVAL_DEREF(zref); zval_dtor(zref); ZVAL_ZVAL(zref, zres, 1, 0); RETVAL_TRUE; } } } zend_restore_error_handling(&zeh); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all_cols, 0, 0, 0) ZEND_ARG_INFO(0, col) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchAllCols) { zend_error_handling zeh; zval *zcol = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zcol); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { php_pqres_col_t col; zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); if (SUCCESS == column_nn(obj, zcol, &col)) { int r, rows = PQntuples(obj->intern->res); zval tmp; array_init(return_value); for (r = 0; r < rows; ++r) { add_next_index_zval(return_value, php_pqres_get_col(obj->intern, r, col.num, &tmp)); } } zend_restore_error_handling(&zeh); } } } struct apply_to_col_arg { php_pqres_object_t *obj; php_pqres_col_t *cols; ZEND_RESULT_CODE status; }; static int apply_to_col(zval *c, void *a) { struct apply_to_col_arg *arg = a; if (SUCCESS != column_nn(arg->obj, c, arg->cols)) { arg->status = FAILURE; return ZEND_HASH_APPLY_STOP; } else { arg->status = SUCCESS; ++arg->cols; return ZEND_HASH_APPLY_KEEP; } } static php_pqres_col_t *php_pqres_convert_to_cols(php_pqres_object_t *obj, HashTable *ht) { struct apply_to_col_arg arg = {NULL}; php_pqres_col_t *tmp; arg.obj = obj; arg.cols = ecalloc(zend_hash_num_elements(ht), sizeof(*tmp)); tmp = arg.cols; zend_hash_apply_with_argument(ht, apply_to_col, &arg); if (SUCCESS == arg.status) { return tmp; } else { efree(tmp); return NULL; } } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_map, 0, 0, 0) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, vals) ZEND_ARG_INFO(0, fetch_type) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, map) { zend_error_handling zeh; zval *zkeys = 0, *zvals = 0; zend_long fetch_type = -1; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|z/!z/!l", &zkeys, &zvals, &fetch_type); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { int ks = 0, vs = 0; php_pqres_col_t def = {PQfname(obj->intern->res, 0), 0}, *keys = NULL, *vals = NULL; if (zkeys) { convert_to_array(zkeys); if ((ks = zend_hash_num_elements(Z_ARRVAL_P(zkeys)))) { keys = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zkeys)); } else { ks = 1; keys = &def; } } else { ks = 1; keys = &def; } if (zvals) { convert_to_array(zvals); if ((vs = zend_hash_num_elements(Z_ARRVAL_P(zvals)))) { vals = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zvals)); } } if (fetch_type == -1) { fetch_type = php_pqres_fetch_type(obj->intern); } if (keys) { int rows, r; zval *cur; switch (fetch_type) { case PHP_PQRES_FETCH_ARRAY: case PHP_PQRES_FETCH_ASSOC: array_init(return_value); break; case PHP_PQRES_FETCH_OBJECT: object_init(return_value); break; } for (r = 0, rows = PQntuples(obj->intern->res); r < rows; ++r) { int k, v; zval *ptr; cur = return_value; for (k = 0; k < ks; ++k) { char *key = PQgetvalue(obj->intern->res, r, keys[k].num); int len = PQgetlength(obj->intern->res, r, keys[k].num); if (!(ptr = zend_symtable_str_find(HASH_OF(cur), key, len))) { zval tmp; switch (fetch_type) { case PHP_PQRES_FETCH_ARRAY: case PHP_PQRES_FETCH_ASSOC: array_init(&tmp); break; case PHP_PQRES_FETCH_OBJECT: object_init(&tmp); break; } if (!(ptr = zend_symtable_str_update(HASH_OF(cur), key, len, &tmp))) { throw_exce(EX_RUNTIME, "Failed to create map"); goto err; } cur = ptr; } cur = ptr; } if (vals && vs) { for (v = 0; v < vs; ++v) { char *val = PQgetvalue(obj->intern->res, r, vals[v].num); int len = PQgetlength(obj->intern->res, r, vals[v].num); switch (fetch_type) { case PHP_PQRES_FETCH_ARRAY: add_index_stringl(cur, vals[v].num, val, len); break; case PHP_PQRES_FETCH_ASSOC: add_assoc_stringl(cur, vals[v].name, val, len); break; case PHP_PQRES_FETCH_OBJECT: add_property_stringl(cur, vals[v].name, val, len); break; } } } else { php_pqres_row_to_zval(obj->intern->res, r, fetch_type, cur); } } } err: if (keys && keys != &def) { efree(keys); } if (vals) { efree(vals); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all, 0, 0, 0) ZEND_ARG_INFO(0, fetch_type) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchAll) { zend_error_handling zeh; zend_long fetch_type = -1; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { int r, rows = PQntuples(obj->intern->res); zval tmp; if (fetch_type == -1) { fetch_type = php_pqres_fetch_type(obj->intern); } array_init(return_value); for (r = 0; r < rows; ++r) { ZVAL_NULL(&tmp); add_next_index_zval(return_value, php_pqres_row_to_zval(obj->intern->res, r, fetch_type, &tmp)); } } } } ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_pqres_count, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, count) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { zend_long count; if (SUCCESS != php_pqres_count_elements_ex(Z_OBJ_P(getThis()), &count)) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { RETVAL_LONG(count); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_desc, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, desc) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { int p, params; array_init(return_value); for (p = 0, params = PQnparams(obj->intern->res); p < params; ++p) { add_next_index_long(return_value, PQparamtype(obj->intern->res, p)); } } } } #if PHP_VERSION_ID >= 80000 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(ai_pqres_getIterator, 0, 0, Traversable, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, getIterator) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { zend_create_internal_iterator_zval(return_value, getThis()); } } } #endif static zend_function_entry php_pqres_methods[] = { PHP_ME(pqres, bind, ai_pqres_bind, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchBound, ai_pqres_fetch_bound, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchAll, ai_pqres_fetch_all, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchAllCols, ai_pqres_fetch_all_cols, ZEND_ACC_PUBLIC) PHP_ME(pqres, count, ai_pqres_count, ZEND_ACC_PUBLIC) PHP_ME(pqres, map, ai_pqres_map, ZEND_ACC_PUBLIC) PHP_ME(pqres, desc, ai_pqres_desc, ZEND_ACC_PUBLIC) #if PHP_VERSION_ID >= 80000 PHP_ME(pqres, getIterator, ai_pqres_getIterator, ZEND_ACC_PUBLIC) #endif {0} }; PHP_MSHUTDOWN_FUNCTION(pqres) { zend_hash_destroy(&php_pqres_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqres) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods); php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqres_class_entry->create_object = php_pqres_create_object; php_pqres_class_entry->get_iterator = php_pqres_iterator_init; #if PHP_VERSION_ID >= 80000 zend_class_implements(php_pqres_class_entry, 2, zend_ce_aggregate, zend_ce_countable); #else zend_class_implements(php_pqres_class_entry, 2, zend_ce_traversable, zend_ce_countable); #endif memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqres_object_handlers.offset = XtOffsetOf(php_pqres_object_t, zo); php_pqres_object_handlers.free_obj = php_pqres_object_free; php_pqres_object_handlers.read_property = php_pq_object_read_prop; php_pqres_object_handlers.write_property = php_pq_object_write_prop; php_pqres_object_handlers.clone_obj = NULL; php_pqres_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqres_object_handlers.get_gc = php_pq_object_get_gc; php_pqres_object_handlers.get_debug_info = php_pq_object_debug_info; php_pqres_object_handlers.get_properties = php_pq_object_properties; php_pqres_object_handlers.count_elements = php_pqres_count_elements; zend_hash_init(&php_pqres_object_prophandlers, 9, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_status; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "status", sizeof("status")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_status_message; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "statusMessage", sizeof("statusMessage")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_error_message; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("diag"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_diag; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "diag", sizeof("diag")-1, (void *) &ph, sizeof(ph)); zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_num_rows; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "numRows", sizeof("numRows")-1, (void *) &ph, sizeof(ph)); zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_num_cols; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "numCols", sizeof("numCols")-1, (void *) &ph, sizeof(ph)); zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_affected_rows; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows")-1, (void *) &ph, sizeof(ph)); zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_fetch_type; ph.write = php_pqres_object_write_fetch_type; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("autoConvert"), PHP_PQRES_CONV_ALL, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_auto_conv; ph.write = php_pqres_object_write_auto_conv; zend_hash_str_add_mem(&php_pqres_object_prophandlers, "autoConvert", sizeof("autoConvert")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR); #ifdef HAVE_PGRES_COPY_BOTH zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH); #endif #ifdef HAVE_PGRES_SINGLE_TUPLE zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE); #endif zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_BOOL"), PHP_PQRES_CONV_BOOL); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_INT"), PHP_PQRES_CONV_INT); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_FLOAT"), PHP_PQRES_CONV_FLOAT); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_JSON"), PHP_PQRES_CONV_JSON); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_BYTEA"), PHP_PQRES_CONV_BYTEA); zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqres.h0000644000076500000240000000463214560227740013723 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQRES_H #define PHP_PQRES_H #include "php_pqconn.h" typedef enum php_pqres_fetch { PHP_PQRES_FETCH_ARRAY, PHP_PQRES_FETCH_ASSOC, PHP_PQRES_FETCH_OBJECT } php_pqres_fetch_t; #define PHP_PQRES_CONV_BOOL 0x0001 #define PHP_PQRES_CONV_INT 0x0002 #define PHP_PQRES_CONV_FLOAT 0x0004 #define PHP_PQRES_CONV_BYTEA 0x0008 #define PHP_PQRES_CONV_SCALAR 0x000f #define PHP_PQRES_CONV_ARRAY 0x0010 #define PHP_PQRES_CONV_DATETIME 0x0020 #define PHP_PQRES_CONV_JSON 0x0100 #define PHP_PQRES_CONV_ALL 0xffff 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 { PGresult *res; php_pqres_iterator_t *iter; HashTable bound; HashTable converters; unsigned auto_convert; php_pqres_fetch_t default_fetch_type; } php_pqres_t; typedef struct php_pqres_object { PHP_PQ_OBJ_DECL(php_pqres_t *) } php_pqres_object_t; extern ZEND_RESULT_CODE php_pqres_success(PGresult *res); extern php_pqres_object_t *php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *obj); extern zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval *data); extern zval *php_pqres_typed_zval(php_pqres_t *res, Oid typ, zval *zv); extern php_pqres_fetch_t php_pqres_fetch_type(php_pqres_t *res); #include "php_pq_object.h" #include "php_pqconn_event.h" extern zend_class_entry *php_pqres_class_entry; extern php_pqres_object_t *php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern); extern PHP_MINIT_FUNCTION(pqres); extern PHP_MSHUTDOWN_FUNCTION(pqres); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqstm.c0000644000076500000240000004276514560227740013741 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqconn.h" #include "php_pqres.h" #include "php_pqstm.h" zend_class_entry *php_pqstm_class_entry; static zend_object_handlers php_pqstm_object_handlers; static HashTable php_pqstm_object_prophandlers; static void php_pqstm_deallocate(php_pqstm_object_t *obj, zend_bool async, zend_bool silent) { if (obj->intern->allocated) { char *quoted_name = PQescapeIdentifier(obj->intern->conn->intern->conn, obj->intern->name, strlen(obj->intern->name)); if (quoted_name) { smart_str cmd = {0}; smart_str_appends(&cmd, "DEALLOCATE "); smart_str_appends(&cmd, quoted_name); smart_str_0(&cmd); if (async) { if (PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd))) { obj->intern->conn->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj->intern->conn); } else if (!silent) { throw_exce(EX_IO, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } } else { PGresult *res; if ((res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)))) { php_pqres_clear(res); } else if (!silent) { throw_exce(EX_RUNTIME, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } } PQfreemem(quoted_name); smart_str_free(&cmd); } obj->intern->allocated = 0; zend_hash_str_del(&obj->intern->conn->intern->statements, obj->intern->name, strlen(obj->intern->name)); } } static void php_pqstm_object_free(zend_object *o) { php_pqstm_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE stm(#%d) %p (conn(#%d): %p)\n", obj->zo.handle, obj, obj->intern->conn->zo.handle, obj->intern->conn); #endif if (obj->intern) { if (obj->intern->conn->intern) { php_pq_callback_dtor(&obj->intern->conn->intern->onevent); php_pqstm_deallocate(obj, 0, 1); php_pq_object_delref(obj->intern->conn); } efree(obj->intern->name); efree(obj->intern->query); zend_hash_destroy(&obj->intern->bound); if (obj->intern->params) { php_pq_params_free(&obj->intern->params); } efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqstm_object_t *php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqstm_object_t), &php_pqstm_object_handlers, &php_pqstm_object_prophandlers); } static zend_object *php_pqstm_create_object(zend_class_entry *class_type) { return &php_pqstm_create_object_ex(class_type, NULL)->zo; } static void php_pqstm_object_read_name(void *o, zval *return_value) { php_pqstm_object_t *obj = o; RETVAL_STRING(obj->intern->name); } static void php_pqstm_object_read_connection(void *o, zval *return_value) { php_pqstm_object_t *obj = o; php_pq_object_to_zval(obj->intern->conn, return_value); } static void php_pqstm_object_gc_connection(void *o, zval *return_value) { php_pqstm_object_t *obj = o; zval zconn; php_pq_object_to_zval_no_addref(obj->intern->conn, &zconn); add_next_index_zval(return_value, &zconn); } static void php_pqstm_object_read_query(void *o, zval *return_value) { php_pqstm_object_t *obj = o; RETVAL_STRING(obj->intern->query); } static void php_pqstm_object_read_types(void *o, zval *return_value) { int i; php_pqstm_object_t *obj = o; array_init_size(return_value, obj->intern->params->type.count); for (i = 0; i < obj->intern->params->type.count; i++) { add_next_index_long(return_value, (long)obj->intern->params->type.oids[i]); } } php_pqstm_t *php_pqstm_init(php_pqconn_object_t *conn, const char *name, const char *query, php_pq_params_t *params) { php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); php_pq_object_addref(conn); stm->conn = conn; stm->name = estrdup(name); stm->params = params; stm->query = estrdup(query); stm->allocated = 1; ZEND_INIT_SYMTABLE(&stm->bound); zend_hash_str_add_ptr(&conn->intern->statements, name, strlen(name), stm); return stm; } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3) ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, query) ZEND_ARG_ARRAY_INFO(0, types, 1) ZEND_ARG_INFO(0, async) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, __construct) { zend_error_handling zeh; zval *zconn, *ztypes = NULL; char *name_str, *query_str; size_t name_len, *query_len; zend_bool async = 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "Oss|a/!b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes, &async); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); php_pqconn_object_t *conn_obj = PHP_PQ_OBJ(zconn, NULL); if (obj->intern) { throw_exce(EX_BAD_METHODCALL, "pq\\Statement already initialized"); } else if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { php_pq_params_t *params = php_pq_params_init(&conn_obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL); if (async) { rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, params); } else { rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, params); } if (SUCCESS == rv) { obj->intern = php_pqstm_init(conn_obj, name_str, query_str, params); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_bind, 0, 0, 2) ZEND_ARG_INFO(0, param_no) ZEND_ARG_INFO(1, param_ref) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, bind) { zend_long param_no; zval *param_ref; zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "lz", ¶m_no, ¶m_ref); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else if (!obj->intern->allocated) { throw_exce(EX_UNINITIALIZED, "pq\\Statement has been deallocated"); } else { Z_ADDREF_P(param_ref); zend_hash_index_update(&obj->intern->bound, param_no, param_ref); zend_hash_sort(&obj->intern->bound, php_pq_compare_index, 0); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, params, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, exec) { zend_error_handling zeh; zval *zparams = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|a/!", &zparams); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else if (!obj->intern->allocated) { throw_exce(EX_UNINITIALIZED, "pq\\Statement has been deallocated"); } else { PGresult *res; php_pq_params_set_params(obj->intern->params, zparams ? Z_ARRVAL_P(zparams) : &obj->intern->bound); res = php_pq_exec_prepared(obj->intern->conn->intern->conn, obj->intern->name, obj->intern->params->param.count, (const char *const*) obj->intern->params->param.strings, NULL, NULL, 0); php_pq_params_set_params(obj->intern->params, NULL); if (!res) { throw_exce(EX_RUNTIME, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else if (SUCCESS == php_pqres_success(res)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); php_pqconn_notify_listeners(obj->intern->conn); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, params, 1) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, execAsync) { zend_error_handling zeh; zval *zparams = NULL; php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|a/!f", &zparams, &resolver.fci, &resolver.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else if (!obj->intern->allocated) { throw_exce(EX_UNINITIALIZED, "pq\\Statement has been deallocated"); } else { int rc; php_pq_params_set_params(obj->intern->params, zparams ? Z_ARRVAL_P(zparams) : &obj->intern->bound); rc = PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, obj->intern->params->param.count, (const char *const*) obj->intern->params->param.strings, NULL, NULL, 0); php_pq_params_set_params(obj->intern->params, NULL); if (!rc) { throw_exce(EX_IO, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); #if HAVE_PQSETSINGLEROWMODE } else if (obj->intern->conn->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn->intern->conn)) { throw_exce(EX_RUNTIME, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); #endif } else { php_pq_callback_recurse(&obj->intern->conn->intern->onevent, &resolver); obj->intern->conn->intern->poller = PQconsumeInput; } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, desc) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else if (!obj->intern->allocated) { throw_exce(EX_UNINITIALIZED, "pq\\Statement has been deallocated"); } else { PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name); if (!res) { throw_exce(EX_RUNTIME, "Failed to describe statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { int p, params; array_init(return_value); for (p = 0, params = PQnparams(res); p < params; ++p) { add_next_index_long(return_value, PQparamtype(res, p)); } } php_pqres_clear(res); php_pqconn_notify_listeners(obj->intern->conn); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc_async, 0, 0, 1) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, descAsync) { zend_error_handling zeh; php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "f", &resolver.fci, &resolver.fcc); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else if (!obj->intern->allocated) { throw_exce(EX_UNINITIALIZED, "pq\\Statement has been deallocated"); } else if (!PQsendDescribePrepared(obj->intern->conn->intern->conn, obj->intern->name)) { throw_exce(EX_IO, "Failed to describe statement: %s", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pq_callback_recurse(&obj->intern->conn->intern->onevent, &resolver); obj->intern->conn->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj->intern->conn); } } } static zend_always_inline void php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAMETERS, zend_bool async) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (rv == SUCCESS) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else { php_pqstm_deallocate(obj, async, 0); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_deallocate, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, deallocate) { php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_deallocate_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, deallocateAsync) { php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } static inline void php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAMETERS, zend_bool async) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (rv == SUCCESS) { php_pqstm_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Statement not initialized"); } else if (!obj->intern->allocated) { if (async) { rv = php_pqconn_prepare_async(NULL, obj->intern->conn, obj->intern->name, obj->intern->query, obj->intern->params); } else { rv = php_pqconn_prepare(NULL, obj->intern->conn, obj->intern->name, obj->intern->query, obj->intern->params); } if (SUCCESS == rv) { obj->intern->allocated = 1; zend_hash_str_add_ptr(&obj->intern->conn->intern->statements, obj->intern->name, strlen(obj->intern->name), obj->intern); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_prepare, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, prepare) { php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_prepare_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, prepareAsync) { php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } static zend_function_entry php_pqstm_methods[] = { PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC) PHP_ME(pqstm, bind, ai_pqstm_bind, ZEND_ACC_PUBLIC) PHP_ME(pqstm, deallocate, ai_pqstm_deallocate, ZEND_ACC_PUBLIC) PHP_ME(pqstm, deallocateAsync, ai_pqstm_deallocate_async, ZEND_ACC_PUBLIC) PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC) PHP_ME(pqstm, descAsync, ai_pqstm_desc_async, ZEND_ACC_PUBLIC) PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC) PHP_ME(pqstm, execAsync, ai_pqstm_exec_async, ZEND_ACC_PUBLIC) PHP_ME(pqstm, prepare, ai_pqstm_prepare, ZEND_ACC_PUBLIC) PHP_ME(pqstm, prepareAsync, ai_pqstm_prepare_async, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqstm) { zend_hash_destroy(&php_pqstm_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqstm) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods); php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqstm_class_entry->create_object = php_pqstm_create_object; memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqstm_object_handlers.offset = XtOffsetOf(php_pqstm_object_t, zo); php_pqstm_object_handlers.free_obj = php_pqstm_object_free; php_pqstm_object_handlers.read_property = php_pq_object_read_prop; php_pqstm_object_handlers.write_property = php_pq_object_write_prop; php_pqstm_object_handlers.clone_obj = NULL; php_pqstm_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqstm_object_handlers.get_gc = php_pq_object_get_gc; php_pqstm_object_handlers.get_properties = php_pq_object_properties; php_pqstm_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqstm_object_prophandlers, 4, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC); ph.read = php_pqstm_object_read_name; zend_hash_str_add_mem(&php_pqstm_object_prophandlers, "name", sizeof("name")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC); ph.read = php_pqstm_object_read_connection; ph.gc = php_pqstm_object_gc_connection; zend_hash_str_add_mem(&php_pqstm_object_prophandlers, "connection", sizeof("connection")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC); ph.read = php_pqstm_object_read_query; zend_hash_str_add_mem(&php_pqstm_object_prophandlers, "query", sizeof("query")-1, (void *) &ph, sizeof(ph)); zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("types"), ZEND_ACC_PUBLIC); ph.read = php_pqstm_object_read_types; zend_hash_str_add_mem(&php_pqstm_object_prophandlers, "types", sizeof("types")-1, (void *) &ph, sizeof(ph)); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqstm.h0000644000076500000240000000272414560227740013735 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQSTM_H #define PHP_PQSTM_H #include "php_pqconn.h" typedef struct php_pqstm { php_pqconn_object_t *conn; char *name; HashTable bound; php_pq_params_t *params; char *query; unsigned allocated:1; } php_pqstm_t; typedef struct php_pqstm_object { PHP_PQ_OBJ_DECL(php_pqstm_t *) } php_pqstm_object_t; extern zend_class_entry *php_pqstm_class_entry; extern php_pqstm_object_t *php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern); extern php_pqstm_t *php_pqstm_init(php_pqconn_object_t *conn, const char *name, const char *query, php_pq_params_t *params); extern PHP_MINIT_FUNCTION(pqstm); extern PHP_MSHUTDOWN_FUNCTION(pqstm); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqtxn.c0000644000076500000240000007062514560227740013743 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqres.h" #include "php_pqlob.h" #include "php_pqtxn.h" zend_class_entry *php_pqtxn_class_entry; static zend_object_handlers php_pqtxn_object_handlers; static HashTable php_pqtxn_object_prophandlers; const char *php_pq_isolation_level(long *isolation) { switch (*isolation) { case PHP_PQTXN_SERIALIZABLE: return "SERIALIZABLE"; case PHP_PQTXN_REPEATABLE_READ: return "REPEATABLE READ"; default: *isolation = PHP_PQTXN_READ_COMMITTED; /* no break */ case PHP_PQTXN_READ_COMMITTED: return "READ COMMITTED"; } } static void php_pqtxn_object_free(zend_object *o) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE txn(#%d) %p (conn(#%d): %p)\n", obj->zo.handle, obj, obj->intern->conn->zo.handle, obj->intern->conn); #endif if (obj->intern) { if (obj->intern->open && obj->intern->conn->intern) { PGresult *res = php_pq_exec(obj->intern->conn->intern->conn, "ROLLBACK"); if (res) { php_pqres_clear(res); } } php_pq_object_delref(obj->intern->conn); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqtxn_object_t *php_pqtxn_create_object_ex(zend_class_entry *ce, php_pqtxn_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqtxn_object_t), &php_pqtxn_object_handlers, &php_pqtxn_object_prophandlers); } static zend_object *php_pqtxn_create_object(zend_class_entry *class_type) { return &php_pqtxn_create_object_ex(class_type, NULL)->zo; } static void php_pqtxn_object_read_connection(void *o, zval *return_value) { php_pqtxn_object_t *obj = o; php_pq_object_to_zval(obj->intern->conn, return_value); } static void php_pqtxn_object_gc_connection(void *o, zval *return_value) { php_pqtxn_object_t *obj = o; zval zconn; php_pq_object_to_zval_no_addref(obj->intern->conn, &zconn); add_next_index_zval(return_value, &zconn); } static void php_pqtxn_object_read_isolation(void *o, zval *return_value) { php_pqtxn_object_t *obj = o; RETVAL_LONG(obj->intern->isolation); } static void php_pqtxn_object_read_readonly(void *o, zval *return_value) { php_pqtxn_object_t *obj = o; RETVAL_BOOL(obj->intern->readonly); } static void php_pqtxn_object_read_deferrable(void *o, zval *return_value) { php_pqtxn_object_t *obj = o; RETVAL_BOOL(obj->intern->deferrable); } static void php_pqtxn_object_write_isolation(void *o, zval *value) { php_pqtxn_object_t *obj = o; php_pqtxn_isolation_t orig = obj->intern->isolation; PGresult *res; switch ((obj->intern->isolation = zval_get_long(value))) { case PHP_PQTXN_READ_COMMITTED: res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL READ COMMITED"); break; case PHP_PQTXN_REPEATABLE_READ: res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); break; case PHP_PQTXN_SERIALIZABLE: res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); break; default: obj->intern->isolation = orig; res = NULL; break; } if (res) { php_pqres_success(res); php_pqres_clear(res); } } static void php_pqtxn_object_write_readonly(void *o, zval *value) { php_pqtxn_object_t *obj = o; PGresult *res; if ((obj->intern->readonly = z_is_true(value))) { res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY"); } else { res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE"); } if (res) { php_pqres_success(res); php_pqres_clear(res); } } static void php_pqtxn_object_write_deferrable(void *o, zval *value) { php_pqtxn_object_t *obj = o; PGresult *res; if ((obj->intern->deferrable = z_is_true(value))) { res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE"); } else { res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE"); } if (res) { php_pqres_success(res); php_pqres_clear(res); } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_construct, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) ZEND_ARG_INFO(0, async) ZEND_ARG_INFO(0, isolation) ZEND_ARG_INFO(0, readonly) ZEND_ARG_INFO(0, deferrable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, __construct) { zend_error_handling zeh; zval *zconn; zend_long isolation = PHP_PQTXN_READ_COMMITTED; zend_bool async = 0, readonly = 0, deferrable = 0; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O|blbb", &zconn, php_pqconn_class_entry, &async, &isolation, &readonly, &deferrable); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = PHP_PQ_OBJ(zconn, NULL); if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { switch (ZEND_NUM_ARGS()) { case 1: case 2: isolation = conn_obj->intern->default_txn_isolation; /* no break */ case 3: readonly = conn_obj->intern->default_txn_readonly; /* no break */ case 4: deferrable = conn_obj->intern->default_txn_deferrable; break; } if (async) { rv = php_pqconn_start_transaction_async(zconn, conn_obj, isolation, readonly, deferrable); } else { rv = php_pqconn_start_transaction(zconn, conn_obj, isolation, readonly, deferrable); } if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); obj->intern = ecalloc(1, sizeof(*obj->intern)); php_pq_object_addref(conn_obj); obj->intern->conn = conn_obj; obj->intern->open = 1; obj->intern->isolation = isolation; obj->intern->readonly = readonly; obj->intern->deferrable = deferrable; } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, savepoint) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transaction already closed"); } else { PGresult *res; smart_str cmd = {0}; smart_str_appends(&cmd, "SAVEPOINT \""); smart_str_append_unsigned(&cmd, ++obj->intern->savepoint); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)); if (!res) { throw_exce(EX_RUNTIME, "Failed to create %s (%s)", smart_str_v(&cmd), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res); php_pqres_clear(res); } smart_str_free(&cmd); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, savepointAsync) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transaction already closed"); } else { smart_str cmd = {0}; smart_str_appends(&cmd, "SAVEPOINT \""); smart_str_append_unsigned(&cmd, ++obj->intern->savepoint); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); if (!PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd))) { throw_exce(EX_IO, "Failed to create %s (%s)", smart_str_v(&cmd), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } smart_str_free(&cmd); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, commit) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transacation not initialized"); } else if (!obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transaction already closed"); } else { PGresult *res; smart_str cmd = {0}; zend_bool just_release_sp = !!obj->intern->savepoint; if (!just_release_sp) { res = php_pq_exec(obj->intern->conn->intern->conn, "COMMIT"); } else { smart_str_appends(&cmd, "RELEASE SAVEPOINT \""); smart_str_append_unsigned(&cmd, obj->intern->savepoint--); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)); } if (!res) { throw_exce(EX_RUNTIME, "Failed to %s (%s)", smart_str_l(&cmd) ? smart_str_v(&cmd) : "commit transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { if (!just_release_sp) { obj->intern->open = 0; } } php_pqres_clear(res); } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, commitAsync) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transaction already closed"); } else { int rc; smart_str cmd = {0}; zend_bool just_release_sp = !!obj->intern->savepoint; if (!just_release_sp) { rc = PQsendQuery(obj->intern->conn->intern->conn, "COMMIT"); } else { smart_str_appends(&cmd, "RELEASE SAVEPOINT \""); smart_str_append_unsigned(&cmd, obj->intern->savepoint--); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); rc = PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd)); } if (!rc) { throw_exce(EX_IO, "Failed to %s (%s)", smart_str_l(&cmd) ? smart_str_v(&cmd) : "commmit transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (!just_release_sp) { obj->intern->open = 0; } obj->intern->conn->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj->intern->conn); } smart_str_free(&cmd); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, rollback) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transaction already closed"); } else { PGresult *res; smart_str cmd = {0}; zend_bool just_release_sp = !!obj->intern->savepoint; if (!just_release_sp) { res = php_pq_exec(obj->intern->conn->intern->conn, "ROLLBACK"); } else { smart_str_appends(&cmd, "ROLLBACK TO SAVEPOINT \""); smart_str_append_unsigned(&cmd, obj->intern->savepoint--); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)); } if (!res) { throw_exce(EX_RUNTIME, "Failed to %s (%s)", smart_str_l(&cmd) ? smart_str_v(&cmd) : "rollback transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { if (!just_release_sp) { obj->intern->open = 0; } } php_pqres_clear(res); } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, rollbackAsync) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!obj->intern->open) { throw_exce(EX_RUNTIME, "pq\\Transaction already closed"); } else { int rc; smart_str cmd = {0}; zend_bool just_release_sp = !!obj->intern->savepoint; if (!just_release_sp) { rc = PQsendQuery(obj->intern->conn->intern->conn, "ROLLBACK"); } else { smart_str_appends(&cmd, "ROLLBACK TO SAVEPOINT \""); smart_str_append_unsigned(&cmd, obj->intern->savepoint--); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); rc = PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd)); } if (!rc) { throw_exce(EX_IO, "Failed to %s (%s)", smart_str_l(&cmd) ? smart_str_v(&cmd) : "rollback transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (!just_release_sp) { obj->intern->open = 0; } obj->intern->conn->intern->poller = PQconsumeInput; } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, exportSnapshot) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else { PGresult *res = php_pq_exec(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()"); if (!res) { throw_exce(EX_RUNTIME, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { RETVAL_STRING(PQgetvalue(res, 0, 0)); } php_pqres_clear(res); } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, exportSnapshotAsync) { zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (!PQsendQuery(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()")) { throw_exce(EX_IO, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { obj->intern->conn->intern->poller = PQconsumeInput; php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot, 0, 0, 1) ZEND_ARG_INFO(0, snapshot_id) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, importSnapshot) { zend_error_handling zeh; char *snapshot_str; size_t snapshot_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &snapshot_str, &snapshot_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (obj->intern->isolation < PHP_PQTXN_REPEATABLE_READ) { throw_exce(EX_RUNTIME, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot"); } else { char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len); if (!sid) { throw_exce(EX_ESCAPE, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { PGresult *res; smart_str cmd = {0}; smart_str_appends(&cmd, "SET TRANSACTION SNAPSHOT "); smart_str_appends(&cmd, sid); smart_str_0(&cmd); res = php_pq_exec(obj->intern->conn->intern->conn, smart_str_v(&cmd)); if (!res) { throw_exce(EX_RUNTIME, "Failed to import transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res); php_pqres_clear(res); } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot_async, 0, 0, 1) ZEND_ARG_INFO(0, snapshot_id) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, importSnapshotAsync) { zend_error_handling zeh; char *snapshot_str; size_t snapshot_len; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &snapshot_str, &snapshot_len); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else if (obj->intern->isolation < PHP_PQTXN_REPEATABLE_READ) { throw_exce(EX_RUNTIME, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot"); } else { char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len); if (!sid) { throw_exce(EX_ESCAPE, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { smart_str cmd = {0}; smart_str_appends(&cmd, "SET TRANSACTION SNAPSHOT "); smart_str_appends(&cmd, sid); smart_str_0(&cmd); if (!PQsendQuery(obj->intern->conn->intern->conn, smart_str_v(&cmd))) { throw_exce(EX_IO, "Failed to %s (%s)", smart_str_v(&cmd), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { obj->intern->conn->intern->poller = PQconsumeInput; } smart_str_free(&cmd); php_pqconn_notify_listeners(obj->intern->conn); } } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_open_lob, 0, 0, 1) ZEND_ARG_INFO(0, oid) ZEND_ARG_INFO(0, mode) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, openLOB) { zend_error_handling zeh; zend_long mode = INV_WRITE|INV_READ, loid; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &loid, &mode); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else { int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode); if (lofd < 0) { throw_exce(EX_RUNTIME, "Failed to open large object with oid=%lu with mode '%s' (%s)", loid, php_pq_strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqlob_t *lob = ecalloc(1, sizeof(*lob)); lob->lofd = lofd; lob->loid = loid; php_pq_object_addref(obj); lob->txn = obj; RETVAL_OBJ(&php_pqlob_create_object_ex(php_pqlob_class_entry, lob)->zo); } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_create_lob, 0, 0, 0) ZEND_ARG_INFO(0, mode) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, createLOB) { zend_error_handling zeh; zend_long mode = INV_WRITE|INV_READ; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &mode); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else { Oid loid = lo_creat(obj->intern->conn->intern->conn, mode); if (loid == InvalidOid) { throw_exce(EX_RUNTIME, "Failed to create large object with mode '%s' (%s)", php_pq_strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode); if (lofd < 0) { throw_exce(EX_RUNTIME, "Failed to open large object with oid=%lu with mode '%s': %s", loid, php_pq_strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqlob_t *lob = ecalloc(1, sizeof(*lob)); lob->lofd = lofd; lob->loid = loid; php_pq_object_addref(obj); lob->txn = obj; RETVAL_OBJ(&php_pqlob_create_object_ex(php_pqlob_class_entry, lob)->zo); } } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_unlink_lob, 0, 0, 1) ZEND_ARG_INFO(0, oid) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, unlinkLOB) { zend_error_handling zeh; zend_long loid; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "l", &loid); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else { int rc = lo_unlink(obj->intern->conn->intern->conn, loid); if (rc != 1) { throw_exce(EX_RUNTIME, "Failed to unlink LOB (oid=%lu): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_lob, 0, 0, 1) ZEND_ARG_INFO(0, local_path) ZEND_ARG_INFO(0, oid) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, importLOB) { zend_error_handling zeh; char *path_str; size_t path_len; zend_long oid = InvalidOid; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &path_str, &path_len, &oid); zend_restore_error_handling(&zeh); if (rv == SUCCESS) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else { if (oid == InvalidOid) { oid = lo_import(obj->intern->conn->intern->conn, path_str); } else { oid = lo_import_with_oid(obj->intern->conn->intern->conn, path_str, oid); } if (oid == InvalidOid) { throw_exce(EX_RUNTIME, "Failed to import LOB from '%s' (%s)", path_str, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { RETVAL_LONG(oid); } php_pqconn_notify_listeners(obj->intern->conn); } } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_lob, 0, 0, 2) ZEND_ARG_INFO(0, oid) ZEND_ARG_INFO(0, local_path) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, exportLOB) { zend_error_handling zeh; char *path_str; size_t path_len; zend_long oid; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "lp", &oid, &path_str, &path_len); zend_restore_error_handling(&zeh); if (rv == SUCCESS) { php_pqtxn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Transaction not initialized"); } else { int rc = lo_export(obj->intern->conn->intern->conn, oid, path_str); if (rc == -1) { throw_exce(EX_RUNTIME, "Failed to export LOB (oid=%lu) to '%s' (%s)", oid, path_str, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } php_pqconn_notify_listeners(obj->intern->conn); } } } static zend_function_entry php_pqtxn_methods[] = { PHP_ME(pqtxn, __construct, ai_pqtxn_construct, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, commit, ai_pqtxn_commit, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, rollback, ai_pqtxn_rollback, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, commitAsync, ai_pqtxn_commit_async, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, rollbackAsync, ai_pqtxn_rollback_async, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, savepoint, ai_pqtxn_savepoint, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, savepointAsync, ai_pqtxn_savepoint_async, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, exportSnapshot, ai_pqtxn_export_snapshot, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, exportSnapshotAsync, ai_pqtxn_export_snapshot_async, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, importSnapshot, ai_pqtxn_import_snapshot, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, importSnapshotAsync, ai_pqtxn_import_snapshot_async, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, openLOB, ai_pqtxn_open_lob, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, createLOB, ai_pqtxn_create_lob, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, unlinkLOB, ai_pqtxn_unlink_lob, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, importLOB, ai_pqtxn_import_lob, ZEND_ACC_PUBLIC) PHP_ME(pqtxn, exportLOB, ai_pqtxn_export_lob, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqtxn) { zend_hash_destroy(&php_pqtxn_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqtxn) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Transaction", php_pqtxn_methods); php_pqtxn_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqtxn_class_entry->create_object = php_pqtxn_create_object; memcpy(&php_pqtxn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqtxn_object_handlers.offset = XtOffsetOf(php_pqtxn_object_t, zo); php_pqtxn_object_handlers.free_obj = php_pqtxn_object_free; php_pqtxn_object_handlers.read_property = php_pq_object_read_prop; php_pqtxn_object_handlers.write_property = php_pq_object_write_prop; php_pqtxn_object_handlers.clone_obj = NULL; php_pqtxn_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqtxn_object_handlers.get_gc = php_pq_object_get_gc; php_pqtxn_object_handlers.get_properties = php_pq_object_properties; php_pqtxn_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqtxn_object_prophandlers, 4, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC); ph.read = php_pqtxn_object_read_connection; ph.gc = php_pqtxn_object_gc_connection; zend_hash_str_add_mem(&php_pqtxn_object_prophandlers, "connection", sizeof("connection")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("isolation"), ZEND_ACC_PUBLIC); ph.read = php_pqtxn_object_read_isolation; ph.write = php_pqtxn_object_write_isolation; zend_hash_str_add_mem(&php_pqtxn_object_prophandlers, "isolation", sizeof("isolation")-1, (void *) &ph, sizeof(ph)); zend_declare_property_bool(php_pqtxn_class_entry, ZEND_STRL("readonly"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqtxn_object_read_readonly; ph.write = php_pqtxn_object_write_readonly; zend_hash_str_add_mem(&php_pqtxn_object_prophandlers, "readonly", sizeof("readonly")-1, (void *) &ph, sizeof(ph)); zend_declare_property_bool(php_pqtxn_class_entry, ZEND_STRL("deferrable"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqtxn_object_read_deferrable; ph.write = php_pqtxn_object_write_deferrable; zend_hash_str_add_mem(&php_pqtxn_object_prophandlers, "deferrable", sizeof("deferrable")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED); zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("REPEATABLE_READ"), PHP_PQTXN_REPEATABLE_READ); zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE); return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqtxn.h0000644000076500000240000000307114560227740013737 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQTXN_H #define PHP_PQTXN_H #include "php_pqconn.h" typedef enum php_pqtxn_isolation { PHP_PQTXN_READ_COMMITTED, PHP_PQTXN_REPEATABLE_READ, PHP_PQTXN_SERIALIZABLE, } php_pqtxn_isolation_t; typedef struct php_pqtxn { php_pqconn_object_t *conn; php_pqtxn_isolation_t isolation; unsigned savepoint; unsigned open:1; unsigned readonly:1; unsigned deferrable:1; } php_pqtxn_t; typedef struct php_pqtxn_object { PHP_PQ_OBJ_DECL(php_pqtxn_t *) } php_pqtxn_object_t; extern const char *php_pq_isolation_level(long *isolation); extern zend_class_entry *php_pqtxn_class_entry; extern php_pqtxn_object_t *php_pqtxn_create_object_ex(zend_class_entry *ce, php_pqtxn_t *intern); extern PHP_MINIT_FUNCTION(pqtxn); extern PHP_MSHUTDOWN_FUNCTION(pqtxn); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqtypes.c0000644000076500000240000002715614560227740014277 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "php_pq.h" #include "php_pq_misc.h" #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqres.h" #include "php_pqtypes.h" zend_class_entry *php_pqtypes_class_entry; static zend_object_handlers php_pqtypes_object_handlers; static HashTable php_pqtypes_object_prophandlers; static void php_pqtypes_object_free(zend_object *o) { php_pqtypes_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC fprintf(stderr, "FREE types(#%d) %p (conn(#%d): %p)\n", obj->zo.handle, obj, obj->intern->conn->zo.handle, obj->intern->conn); #endif if (obj->intern) { zend_hash_destroy(&obj->intern->types); php_pq_object_delref(obj->intern->conn); efree(obj->intern); obj->intern = NULL; } php_pq_object_dtor(o); } php_pqtypes_object_t *php_pqtypes_create_object_ex(zend_class_entry *ce, php_pqtypes_t *intern) { return php_pq_object_create(ce, intern, sizeof(php_pqtypes_object_t), &php_pqtypes_object_handlers, &php_pqtypes_object_prophandlers); } static zend_object *php_pqtypes_create_object(zend_class_entry *class_type) { return &php_pqtypes_create_object_ex(class_type, NULL)->zo; } static void php_pqtypes_object_read_connection(void *o, zval *return_value) { php_pqtypes_object_t *obj = o; php_pq_object_to_zval(obj->intern->conn, return_value); } static void php_pqtypes_object_gc_connection(void *o, zval *return_value) { php_pqtypes_object_t *obj = o; zval zconn; php_pq_object_to_zval_no_addref(obj->intern->conn, &zconn); add_next_index_zval(return_value, &zconn); } static inline int has_dimension(HashTable *ht, zval *member, zend_string **key, zend_long *index) { if (Z_TYPE_P(member) == IS_LONG) { *index = Z_LVAL_P(member); check_index: return zend_hash_index_exists(ht, *index); } else { zend_string *str = zval_get_string(member); if (is_numeric_str_function(str, index, NULL)) { zend_string_release(str); goto check_index; } if (zend_hash_exists(ht, str)) { *key = str; return 1; } zend_string_release(str); return 0; } } static inline int php_pqtypes_object_has_dimension_ex(zend_object *object, zval *member, int check_empty) { php_pqtypes_object_t *obj = PHP_PQ_OBJ(NULL, object); zend_string *key = NULL; zend_long index = 0; if (has_dimension(&obj->intern->types, member, &key, &index)) { if (check_empty) { zval *data; if (key) { if ((data = zend_hash_find(&obj->intern->types, key))) { zend_string_release(key); return Z_TYPE_P(data) != IS_NULL; } zend_string_release(key); } else if ((data = zend_hash_index_find(&obj->intern->types, index))) { return Z_TYPE_P(data) != IS_NULL; } } else { if (key) { zend_string_release(key); } return 1; } } return 0; } #if PHP_VERSION_ID >= 80000 static int php_pqtypes_object_has_dimension(zend_object *object, zval *member, int check_empty) { return php_pqtypes_object_has_dimension_ex(object, member, check_empty); } #else static int php_pqtypes_object_has_dimension(zval *object, zval *member, int check_empty) { return php_pqtypes_object_has_dimension_ex(Z_OBJ_P(object), member, check_empty); } #endif static inline zval *php_pqtypes_object_read_dimension_ex(zend_object *object, zval *member, int type, zval *rv) { php_pqtypes_object_t *obj = PHP_PQ_OBJ(NULL, object); zend_string *key = NULL; zend_long index = 0; zval *data = NULL; if (has_dimension(&obj->intern->types, member, &key, &index)) { if (key) { data = zend_hash_find(&obj->intern->types, key); zend_string_release(key); } else { data = zend_hash_index_find(&obj->intern->types, index); } } return data; } #if PHP_VERSION_ID >= 80000 static zval *php_pqtypes_object_read_dimension(zend_object *object, zval *member, int type, zval *rv) { return php_pqtypes_object_read_dimension_ex(object, member, type, rv); } #else static zval *php_pqtypes_object_read_dimension(zval *object, zval *member, int type, zval *rv) { return php_pqtypes_object_read_dimension_ex(Z_OBJ_P(object), member, type, rv); } #endif #if PHP_VERSION_ID >= 80000 static void php_pqtypes_object_write_dimension(zend_object *object, zval *offset, zval *value) { throw_exce(EX_RUNTIME, "pq\\Types object must not be modified"); } #else static void php_pqtypes_object_write_dimension(zval *object, zval *offset, zval *value) { throw_exce(EX_RUNTIME, "pq\\Types object must not be modified"); } #endif #if PHP_VERSION_ID >= 80000 static void php_pqtypes_object_unset_dimension(zend_object *object, zval *offset) { throw_exce(EX_RUNTIME, "pq\\Types object must not be modified"); } #else static void php_pqtypes_object_unset_dimension(zval *object, zval *offset) { throw_exce(EX_RUNTIME, "pq\\Types object must not be modified"); } #endif ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) ZEND_ARG_ARRAY_INFO(0, namespaces, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtypes, __construct) { zend_error_handling zeh; zval *zconn, *znsp = NULL; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O|a!", &zconn, php_pqconn_class_entry, &znsp); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = PHP_PQ_OBJ(zconn, NULL); if (!conn_obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { php_pqtypes_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->conn = conn_obj; php_pq_object_addref(conn_obj); zend_hash_init(&obj->intern->types, 512, NULL, ZVAL_PTR_DTOR, 0); if (znsp) { php_pq_call_method(getThis(), "refresh", 1, NULL, znsp); } else { php_pq_call_method(getThis(), "refresh", 0, NULL); } } } } #define PHP_PQ_TYPES_QUERY \ "select t.oid, t.typname, t.* " \ "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \ "where typisdefined" #ifndef PHP_PQ_OID_TEXT # define PHP_PQ_OID_TEXT 25 #endif static int apply_nsp(zval *zp, int argc, va_list argv, zend_hash_key *key) { unsigned pcount, tcount; php_pq_params_t *params = va_arg(argv, php_pq_params_t *); smart_str *str = va_arg(argv, smart_str *); tcount = php_pq_params_add_type_oid(params, PHP_PQ_OID_TEXT); pcount = php_pq_params_add_param(params, zp); if (tcount != pcount) { php_error_docref(NULL, E_WARNING, "Param/Type count mismatch"); return ZEND_HASH_APPLY_STOP; } if (pcount > 1) { smart_str_appendc(str, ','); } smart_str_appendc(str, '$'); smart_str_append_unsigned(str, pcount); return ZEND_HASH_APPLY_KEEP; } ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, namespaces, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtypes, refresh) { HashTable *nsp = NULL; zend_error_handling zeh; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|H/!", &nsp); zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqtypes_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Types not initialized"); } else { PGresult *res; if (!nsp || !zend_hash_num_elements(nsp)) { res = php_pq_exec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')"); } else { smart_str str = {0}; php_pq_params_t *params = php_pq_params_init(&obj->intern->conn->intern->converters, NULL, NULL); smart_str_appends(&str, PHP_PQ_TYPES_QUERY " and nspname in("); zend_hash_apply_with_arguments(nsp, apply_nsp, 2, params, &str); smart_str_appendc(&str, ')'); smart_str_0(&str); res = php_pq_exec_params(obj->intern->conn->intern->conn, smart_str_v(&str), params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); smart_str_free(&str); php_pq_params_free(¶ms); } if (!res) { throw_exce(EX_RUNTIME, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { if (SUCCESS == php_pqres_success(res)) { int r, rows; for (r = 0, rows = PQntuples(res); r < rows; ++r) { zval tmp, *row; ZVAL_NULL(&tmp); row = php_pqres_row_to_zval(res, r, PHP_PQRES_FETCH_OBJECT, &tmp); Z_ADDREF_P(row); zend_hash_index_update(&obj->intern->types, atol(PQgetvalue(res, r, 0 )), row); zend_hash_str_update(&obj->intern->types, PQgetvalue(res, r, 1), PQgetlength(res, r, 1), row); } } php_pqres_clear(res); php_pqconn_notify_listeners(obj->intern->conn); } } } } static zend_function_entry php_pqtypes_methods[] = { PHP_ME(pqtypes, __construct, ai_pqtypes_construct, ZEND_ACC_PUBLIC) PHP_ME(pqtypes, refresh, ai_pqtypes_refresh, ZEND_ACC_PUBLIC) {0} }; PHP_MSHUTDOWN_FUNCTION(pqtypes) { zend_hash_destroy(&php_pqtypes_object_prophandlers); return SUCCESS; } PHP_MINIT_FUNCTION(pqtypes) { zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Types", php_pqtypes_methods); php_pqtypes_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqtypes_class_entry->create_object = php_pqtypes_create_object; /* zend_class_implements(php_pqtypes_class_entry, 1, zend_ce_arrayaccess); */ memcpy(&php_pqtypes_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_pqtypes_object_handlers.offset = XtOffsetOf(php_pqtypes_object_t, zo); php_pqtypes_object_handlers.free_obj = php_pqtypes_object_free; php_pqtypes_object_handlers.read_property = php_pq_object_read_prop; php_pqtypes_object_handlers.write_property = php_pq_object_write_prop; php_pqtypes_object_handlers.clone_obj = NULL; php_pqtypes_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; php_pqtypes_object_handlers.get_gc = php_pq_object_get_gc; php_pqtypes_object_handlers.get_properties = php_pq_object_properties; php_pqtypes_object_handlers.get_debug_info = php_pq_object_debug_info; php_pqtypes_object_handlers.has_dimension = php_pqtypes_object_has_dimension; php_pqtypes_object_handlers.read_dimension = php_pqtypes_object_read_dimension; php_pqtypes_object_handlers.unset_dimension = php_pqtypes_object_unset_dimension; php_pqtypes_object_handlers.write_dimension = php_pqtypes_object_write_dimension; zend_hash_init(&php_pqtypes_object_prophandlers, 1, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_null(php_pqtypes_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC); ph.read = php_pqtypes_object_read_connection; ph.gc = php_pqtypes_object_gc_connection; zend_hash_str_add_mem(&php_pqtypes_object_prophandlers, "connection", sizeof("connection")-1, (void *) &ph, sizeof(ph)); ph.gc = NULL; # undef PHP_PQ_TYPE # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid); # include "php_pq_type.h" return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/src/php_pqtypes.h0000644000076500000240000000244414560227740014275 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQTYPES_H #define PHP_PQTYPES_H #include "php_pqconn.h" typedef struct php_pqtypes { HashTable types; php_pqconn_object_t *conn; } php_pqtypes_t; typedef struct php_pqtypes_object { PHP_PQ_OBJ_DECL(php_pqtypes_t *) } php_pqtypes_object_t; extern zend_class_entry *php_pqtypes_class_entry; extern php_pqtypes_object_t *php_pqtypes_create_object_ex(zend_class_entry *ce, php_pqtypes_t *intern); extern PHP_MINIT_FUNCTION(pqtypes); extern PHP_MSHUTDOWN_FUNCTION(pqtypes); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/tests/async001.phpt0000644000076500000240000000154014560227740014352 0ustar mikestaff--TEST-- async connect --SKIPIF-- --FILE-- status); echo "W"; $w = array($c->socket); $r = $e = null; stream_select($r, $w, $e, null); while (true) { $s[] = $c->status; echo "P"; switch ($c->poll()) { case pq\Connection::POLLING_READING: echo "R"; $w = $e = null; $r = array($c->socket); stream_select($r, $w, $e, NULL); break; case pq\Connection::POLLING_WRITING: echo "W"; $w = array($c->socket); $r = $e = null; stream_select($r, $w, $e, null); break; case pq\Connection::POLLING_FAILED: echo "F"; break 2; case pq\Connection::POLLING_OK: echo "S"; break 2; } } $s[] = $c->status; printf("\n%s\n", implode(",", $s)); ?> DONE --EXPECTREGEX-- Test (WP(RP)*)+S [23](,\d*)*,0 DONE pq-2.2.3/tests/async002.phpt0000644000076500000240000000201514560227740014351 0ustar mikestaff--TEST-- async reset --SKIPIF-- --FILE-- status); echo "W"; $w = array($c->socket); $r = $e = null; stream_select($r, $w, $e, null); while (true) { $s[] = $c->status; echo "P"; switch ($c->poll()) { case pq\Connection::POLLING_READING: echo "R"; $w = $e = null; $r = array($c->socket); stream_select($r, $w, $e, NULL); break; case pq\Connection::POLLING_WRITING: echo "W"; $w = array($c->socket); $r = $e = null; stream_select($r, $w, $e, null); break; case pq\Connection::POLLING_FAILED: echo "F"; break 2; case pq\Connection::POLLING_OK: echo "S"; break 2; } } $s[] = $c->status; printf("\n%s\n", implode(",", $s)); } complete($c); if ($c->status == pq\Connection::OK) { $c->resetAsync(); complete($c); } ?> DONE --EXPECTREGEX-- Test (WP(RP)*)+S [23](,\d*)*,0 (WP(RP)*)+S [23](,\d*)*,0 DONE pq-2.2.3/tests/async003.phpt0000644000076500000240000000413314560227740014355 0ustar mikestaff--TEST-- async exec --SKIPIF-- --FILE-- execAsync("SELECT 1+2+3; SELECT 2,3,4", function ($res) { var_dump($res); }); do { while ($c->busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, 1, 1000)) { $c->poll(); } } } while ($c->getResult()); ?> DONE --EXPECTF-- Test object(pq\Result)#%d (9) { ["status"]=> int(2) ["statusMessage"]=> string(9) "TUPLES_OK" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(1) ["affectedRows"]=> int(%d) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } object(pq\Result)#%d (9) { ["status"]=> int(2) ["statusMessage"]=> string(9) "TUPLES_OK" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(3) ["affectedRows"]=> int(%d) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } DONE pq-2.2.3/tests/async004.phpt0000644000076500000240000000250114560227740014353 0ustar mikestaff--TEST-- async exec params --SKIPIF-- --FILE-- execParamsAsync("SELECT \$1,\$2::int4", array(1,2), array($t["int4"]->oid), function ($res) { var_dump($res); }); do { while ($c->busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); ?> DONE --EXPECTF-- Test object(pq\Result)#%d (9) { ["status"]=> int(2) ["statusMessage"]=> string(9) "TUPLES_OK" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(2) ["affectedRows"]=> int(%d) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } DONE pq-2.2.3/tests/async005.phpt0000644000076500000240000000272414560227740014363 0ustar mikestaff--TEST-- async prepared statement --SKIPIF-- --FILE-- connection->busy) { $r = array($s->connection->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $s->connection->poll(); } } } while ($s->connection->getResult()); } $c = new pq\Connection(PQ_DSN); $t = new pq\Types($c); $s = $c->prepareAsync("test", "SELECT \$1,\$2::int4", array($t["int4"]->oid)); complete($s); $s->execAsync(array(1,2), function ($res) { var_dump($res); }); complete($s); ?> DONE --EXPECTF-- Test object(pq\Result)#%d (9) { ["status"]=> int(2) ["statusMessage"]=> string(9) "TUPLES_OK" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(2) ["affectedRows"]=> int(%d) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } DONE pq-2.2.3/tests/async006.phpt0000644000076500000240000000762014560227740014364 0ustar mikestaff--TEST-- async unbuffered exec --SKIPIF-- --FILE-- unbuffered = true; $c->execAsync("SELECT a FROM generate_series(1,3) a", function ($res) { var_dump($res); }); do { while ($c->busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); ?> DONE --EXPECTF-- Test object(pq\Result)#%d (9) { ["status"]=> int(9) ["statusMessage"]=> string(12) "SINGLE_TUPLE" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(1) ["affectedRows"]=> int(0) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } object(pq\Result)#%d (9) { ["status"]=> int(9) ["statusMessage"]=> string(12) "SINGLE_TUPLE" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(1) ["affectedRows"]=> int(0) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } object(pq\Result)#%d (9) { ["status"]=> int(9) ["statusMessage"]=> string(12) "SINGLE_TUPLE" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(1) ["numCols"]=> int(1) ["affectedRows"]=> int(0) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } object(pq\Result)#%d (9) { ["status"]=> int(2) ["statusMessage"]=> string(9) "TUPLES_OK" ["errorMessage"]=> string(0) "" ["diag"]=> array(17) { ["severity"]=> NULL ["sqlstate"]=> NULL ["message_primary"]=> NULL ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> NULL ["source_line"]=> NULL ["source_function"]=> NULL } ["numRows"]=> int(0) ["numCols"]=> int(1) ["affectedRows"]=> int(3) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } DONE pq-2.2.3/tests/async007.phpt0000644000076500000240000000132014560227740014354 0ustar mikestaff--TEST-- async statement --SKIPIF-- --FILE-- busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); } $c = new pq\Connection(PQ_DSN); $t = new pq\Types($c); $s = new pq\Statement($c, "test1", "SELECT NOW() - \$1", null, true); complete($s->connection); $s->execAsync(array("2012-12-12 12:12:12")); complete($s->connection); $s->descAsync(function($r) use ($t) { list($typeOid) = $r->desc(); printf("%s\n", $t[$typeOid]->typname); }); complete($s->connection); ?> DONE --EXPECT-- Test timestamptz DONE pq-2.2.3/tests/async008.phpt0000644000076500000240000000153214560227740014362 0ustar mikestaff--TEST-- async cursor --SKIPIF-- --FILE-- busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); } $c = new pq\Connection(PQ_DSN); $p = $c->declareAsync("mycursor", pq\Cursor::WITH_HOLD, "SELECT * FROM generate_series(0,29) s WHERE (s%2)=0"); complete($c); do { $p->fetchAsync(2, function ($r) { foreach ($r as $row) { foreach ($row as $col) { echo " $col"; } echo "\n"; } }); complete($p->connection); $p->moveAsync(1, function ($r) use(&$keep_going) { $keep_going = $r->affectedRows; }); complete($p->connection); } while ($keep_going); ?> ===DONE=== --EXPECT-- Test 0 2 6 8 12 14 18 20 24 26 ===DONE=== pq-2.2.3/tests/async009.phpt0000644000076500000240000000151014560227740014357 0ustar mikestaff--TEST-- Deallocate and prepare statement async --SKIPIF-- --FILE-- busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); } $c = new pq\Connection(PQ_DSN); $s = $c->prepareAsync("test1", "SELECT 'test' || \$1"); complete($c); $r = $s->exec(array("ing")); $r->fetchCol($d); var_dump($d); $s->deallocateAsync(); complete($c); try { $s->exec(array("ing")); } catch (pq\Exception\BadMethodCallException $e) { echo "Caught exception\n"; } $s->prepareAsync(); complete($c); $r = $s->exec(array("ing")); $r->fetchCol($d); var_dump($d); ?> DONE --EXPECT-- Test string(7) "testing" Caught exception string(7) "testing" DONE pq-2.2.3/tests/async010.phpt0000644000076500000240000000207114560227740014352 0ustar mikestaff--TEST-- asnyc query not cleaned before sync exec --SKIPIF-- --FILE-- $c->execAsync("select clock_timestamp(), pg_sleep(0.1), clock_timestamp()", function($r) { var_dump([ "cb" => $r->fetchRow() ]); }) ]); var_dump([ "execParams" => $c->execParams("select \$1::int4", [123])->fetchRow() ]); ?> DONE --EXPECTF-- Test array(1) { ["async"]=> NULL } array(1) { ["cb"]=> array(3) { [0]=> object(pq\DateTime)#%d (4) { ["format"]=> string(14) "Y-m-d H:i:s.uO" ["date"]=> string(26) "%s" ["timezone_type"]=> int(1) ["timezone"]=> string(6) "%s" } [1]=> string(0) "" [2]=> object(pq\DateTime)#%d (4) { ["format"]=> string(14) "Y-m-d H:i:s.uO" ["date"]=> string(26) "%s" ["timezone_type"]=> int(1) ["timezone"]=> string(6) "%s" } } } array(1) { ["execParams"]=> array(1) { [0]=> int(123) } } DONE pq-2.2.3/tests/basic001.phpt0000644000076500000240000000210514560227740014314 0ustar mikestaff--TEST-- basic functionality --SKIPIF-- --FILE-- exec("SELECT 1 as one, 2 as two from generate_series(1,2)"); var_dump($res->status == pq\Result::TUPLES_OK); var_dump($res->numRows); var_dump($res->numCols); var_dump(count($res) == $res->count(), $res->numRows == count($res)); foreach ($res as $rowNum => $rowData) { printf("%d.0 => %d\n", $rowNum, $rowData[0]); printf("%d.1 => %d\n", $rowNum, $rowData[1]); } $res->fetchType = pq\Result::FETCH_ASSOC; foreach ($res as $rowNum => $rowData) { printf("%d.0 => %d\n", $rowNum, $rowData["one"]); printf("%d.1 => %d\n", $rowNum, $rowData["two"]); } $res->fetchType = pq\Result::FETCH_OBJECT; foreach ($res as $rowNum => $rowData) { printf("%d.0 => %d\n", $rowNum, $rowData->one); printf("%d.1 => %d\n", $rowNum, $rowData->two); } ?> DONE --EXPECT-- Test bool(true) int(2) int(2) bool(true) bool(true) 0.0 => 1 0.1 => 2 1.0 => 1 1.1 => 2 0.0 => 1 0.1 => 2 1.0 => 1 1.1 => 2 0.0 => 1 0.1 => 2 1.0 => 1 1.1 => 2 DONE pq-2.2.3/tests/basic002.phpt0000644000076500000240000000063514560227740014323 0ustar mikestaff--TEST-- basic functionality --SKIPIF-- --FILE-- prepare("test1", "SELECT \$1",array($t["text"]->oid)); $r = $s->exec(array("fooo")); printf("%s\n", $r->errorMessage); var_dump($r->fetchCol($val)); var_dump($val); ?> DONE --EXPECT-- Test bool(true) string(4) "fooo" DONE pq-2.2.3/tests/basic003.phpt0000644000076500000240000000047614560227740014327 0ustar mikestaff--TEST-- basic functionality --SKIPIF-- --FILE-- libraryVersion); var_dump($c->protocolVersion); var_dump($c->serverVersion); ?> DONE --EXPECTF-- Test string(%d) "%s" int(%d) string(%d) "%s" DONE pq-2.2.3/tests/bound002.phpt0000644000076500000240000000101414560227740014341 0ustar mikestaff--TEST-- fetch bound --SKIPIF-- --FILE-- exec("select 1*a,2*a,3*a from generate_series(2,3) a"); $r->bind(0, $a); $r->bind(1, $b); $r->bind(2, $c); while ($s = $r->fetchBound()) { var_dump($s,$a,$b,$c); } ?> DONE --EXPECT-- Test array(3) { [0]=> int(2) [1]=> int(4) [2]=> int(6) } int(2) int(4) int(6) array(3) { [0]=> int(3) [1]=> int(6) [2]=> int(9) } int(3) int(6) int(9) DONE pq-2.2.3/tests/callback001.phpt0000644000076500000240000000066614560227740015001 0ustar mikestaff--TEST-- callback sanity --SKIPIF-- --FILE-- execAsync("select 1; select 2", function($r) { print_r($r->fetchAll()); }); $c->exec("select 3"); ?> ===DONE=== --EXPECT-- Test Array ( [0] => Array ( [0] => 1 ) ) Array ( [0] => Array ( [0] => 2 ) ) ===DONE=== pq-2.2.3/tests/callback002.phpt0000644000076500000240000000115614560227740014775 0ustar mikestaff--TEST-- callback sanity --SKIPIF-- --FILE-- execAsync("select 1; select 2", function($r) { print_r($r->fetchAll()); }); try { $c->execAsync("select 3; select 4", function($r) { }); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } $c->exec(""); ?> ===DONE=== --EXPECT-- Test Failed to execute query (another command is already in progress) Array ( [0] => Array ( [0] => 1 ) ) Array ( [0] => Array ( [0] => 2 ) ) ===DONE=== pq-2.2.3/tests/callback003.phpt0000644000076500000240000000177614560227740015006 0ustar mikestaff--TEST-- callback sanity --SKIPIF-- --FILE-- execAsync("select 1; select 2", function($r) use($c) { echo "CALLBACK 1\n"; print_r($r->fetchAll()); $c->exec("select 'bug'"); try { $c->execAsync("select 3; select 4", function($r) { echo "CALLBACK 2\n"; print_r($r->fetchAll()); }); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } }); $c->exec("select 'end'"); ?> ===DONE=== --EXPECT-- Test CALLBACK 1 Array ( [0] => Array ( [0] => 1 ) ) CALLBACK 1 Array ( [0] => Array ( [0] => 2 ) ) CALLBACK 2 Array ( [0] => Array ( [0] => 3 ) ) CALLBACK 2 Array ( [0] => Array ( [0] => 4 ) ) CALLBACK 2 Array ( [0] => Array ( [0] => 3 ) ) CALLBACK 2 Array ( [0] => Array ( [0] => 4 ) ) ===DONE===pq-2.2.3/tests/cancel001.phpt0000644000076500000240000000302514560227740014462 0ustar mikestaff--TEST-- cancel --SKIPIF-- --FILE-- exec("SET lc_messages TO 'C'"); } catch (pq\Exception $e) { // no not fail if we are not superuser } $x = new pq\Cancel($c); $c->execAsync("SELECT pg_sleep(10)"); $x->cancel(); var_dump($c === $x->connection); var_dump($c->getResult()); printf("%s\n", $c->errorMessage); ?> DONE --EXPECTF-- Test bool(true) object(pq\Result)#%d (9) { ["status"]=> int(7) ["statusMessage"]=> string(11) "FATAL_ERROR" ["errorMessage"]=> string(47) "ERROR: canceling statement due to user request" ["diag"]=> array(17) { ["severity"]=> string(5) "ERROR" ["sqlstate"]=> string(5) "57014" ["message_primary"]=> string(39) "canceling statement due to user request" ["message_detail"]=> NULL ["message_hint"]=> NULL ["statement_position"]=> NULL ["internal_position"]=> NULL ["internal_query"]=> NULL ["context"]=> NULL ["schema_name"]=> NULL ["table_name"]=> NULL ["column_name"]=> NULL ["datatype_name"]=> NULL ["constraint_name"]=> NULL ["source_file"]=> string(10) "postgres.c" ["source_line"]=> string(4) "%d" ["source_function"]=> string(17) "ProcessInterrupts" } ["numRows"]=> int(0) ["numCols"]=> int(0) ["affectedRows"]=> int(0) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } ERROR: canceling statement due to user request DONE pq-2.2.3/tests/conv001.phpt0000644000076500000240000001671514560227740014214 0ustar mikestaff--TEST-- converter --SKIPIF-- --INI-- date.timezone=UTC --FILE-- types = $types; } } class HStoreConverter extends Converter { function convertTypes() { return [ $this->types["hstore"]->oid ]; } function convertFromString($string, $type) { return eval("return [$string];"); } function convertToString($data, $type) { $string = ""; foreach ($data as $k => $v) { if (isset($v)) { $string .= sprintf("\"%s\"=>\"%s\",", addslashes($k), addslashes($v)); } else { $string .= sprintf("\"%s\"=>NULL,", addslashes($k)); } } return $string; } } class IntVectorConverter extends Converter { function convertTypes() { return [ $this->types["int2vector"]->oid, $this->types["oidvector"]->oid ]; } function convertFromString($string, $type) { return array_map("intval", explode(" ", $string)); } function convertToString($data, $type) { return implode(" ", $data); } } class JSONConverter extends Converter { function convertTypes() { return [ $this->types["json"]->oid ]; } function convertFromString($string, $type) { return json_decode($string, true); } function convertToString($data, $type) { return json_encode($data); } } class Point { public $x; public $y; function __construct($x, $y) { $this->x = $x; $this->y = $y; } } class Box { public $p1; public $p2; function __construct(Point $p1, Point $p2) { $this->p1 = $p1; $this->p2 = $p2; } } class BoxConverter extends Converter { function convertTypes() { return [ $this->types["box"]->oid ]; } function convertToString($box, $type) { return sprintf("(%F,%F),(%F,%F)", $box->p1->x, $box->p1->y, $box->p2->x, $box->p2->y ); } function convertFromString($data, $type) { list($p1x, $p1y, $p2x, $p2y) = sscanf($data, "(%f,%f),(%f,%f)"); return new Box(new Point($p1x, $p1y), new Point($p2x, $p2y)); } } class Text { private $data; function __construct($data) { $this->data = $data; } function __toString() { return (string) $this->data; } } $c = new pq\Connection(PQ_DSN); $c->exec("CREATE EXTENSION IF NOT EXISTS hstore"); $t = new pq\Types($c); $c->setConverter(new HStoreConverter($t)); $c->setConverter(new IntVectorConverter($t)); if (!(defined("pq\\Types::JSON") && defined("pq\\Result::CONV_JSON"))) { $c->setConverter(new JSONConverter($t)); } $c->setConverter(new BoxConverter($t)); $r = $c->execParams("SELECT \$1 as hs, \$2 as iv, \$3 as oids, \$4 as js, \$5 as ia, \$6 as ta, \$7 as ba, \$8 as da, \$9 as dbl, \$10 as bln, ". "\$11 as dt1, \$12 as dt3, \$13 as dt4, \$14 as dt5, \$15 as dt7, \$16 as dt8, \$17 as txta, \$18 as boxa", array( // hstore array( "k1" => "v1", "k2" => "v2", "k3" => null ), // vectors array( 1, 3, 5, 7, 9, 11 ), array( 2345124, 1431341, 1343423 ), // JSON (object) array( "int" => 123, "obj" => (object) array( "a" => 1, "b" => 2, "c" => 3, ), "str" => "äüö" ), // arrays array(array(array(1,2,3))), array(array("a\"","b}",null)), array(true,false), array(1.1,2.2), // double 123.456, // bool true, // datetimes new pq\Datetime, new pq\Datetime, new pq\Datetime, new pq\Datetime, new pq\Datetime, new pq\Datetime, // text array [new Text(0), new Text(" or "), new Text(true)], // box array [new Box(new Point(1,2), new Point(2,3)), new Box(new Point(3,4), new Point(4,5))], ), array( $t["hstore"]->oid, $t["int2vector"]->oid, $t["oidvector"]->oid, $t["json"]->oid, $t["_int4"]->oid, $t["_text"]->oid, $t["_bool"]->oid, $t["_float8"]->oid, $t["float4"]->oid, $t["bool"]->oid, $t["date"]->oid, $t["timestamp"]->oid, $t["timestamptz"]->oid, $t["date"]->oid, $t["timestamp"]->oid, $t["timestamptz"]->oid, $t["_text"]->oid, $t["_box"]->oid ) ); var_dump($r->fetchAll()); ?> Done --EXPECTF-- Test array(1) { [0]=> array(%d) { [0]=> array(3) { ["k1"]=> string(2) "v1" ["k2"]=> string(2) "v2" ["k3"]=> NULL } [1]=> array(6) { [0]=> int(1) [1]=> int(3) [2]=> int(5) [3]=> int(7) [4]=> int(9) [5]=> int(11) } [2]=> array(3) { [0]=> int(2345124) [1]=> int(1431341) [2]=> int(1343423) } [3]=> array(3) { ["int"]=> int(123) ["obj"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) } ["str"]=> string(6) "äüö" } [4]=> array(1) { [0]=> array(1) { [0]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } } [5]=> array(1) { [0]=> array(3) { [0]=> string(2) "a"" [1]=> string(2) "b}" [2]=> NULL } } [6]=> array(2) { [0]=> bool(true) [1]=> bool(false) } [7]=> array(2) { [0]=> float(1.1) [1]=> float(2.2) } [8]=> float(123.456) [9]=> bool(true) [10]=> object(pq\DateTime)#%d (4) { ["format"]=> string(5) "Y-m-d" ["date"]=> string(26) "%d-%d-%d 00:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } [11]=> object(pq\DateTime)#%d (4) { ["format"]=> string(13) "Y-m-d H:i:s.u" ["date"]=> string(26) "%d-%d-%d %d:%d:%d.%d" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } [12]=> object(pq\DateTime)#%d (4) { ["format"]=> string(14) "Y-m-d H:i:s.uO" ["date"]=> string(26) "%d-%d-%d %d:%d:%d.%d" ["timezone_type"]=> int(1) ["timezone"]=> string(%d) "%s" } [13]=> object(pq\DateTime)#%d (4) { ["format"]=> string(5) "Y-m-d" ["date"]=> string(26) "%d-%d-%d 00:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } [14]=> object(pq\DateTime)#%d (4) { ["format"]=> string(13) "Y-m-d H:i:s.u" ["date"]=> string(26) "%d-%d-%d %d:%d:%d.%d" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } [15]=> object(pq\DateTime)#%d (4) { ["format"]=> string(14) "Y-m-d H:i:s.uO" ["date"]=> string(26) "%d-%d-%d %d:%d:%d.%d" ["timezone_type"]=> int(1) ["timezone"]=> string(%d) "%s" } [16]=> array(3) { [0]=> string(1) "0" [1]=> string(4) " or " [2]=> string(1) "1" } [17]=> array(2) { [0]=> object(Box)#%d (2) { ["p1"]=> object(Point)#%d (2) { ["x"]=> float(2) ["y"]=> float(3) } ["p2"]=> object(Point)#%d (2) { ["x"]=> float(1) ["y"]=> float(2) } } [1]=> object(Box)#%d (2) { ["p1"]=> object(Point)#%d (2) { ["x"]=> float(4) ["y"]=> float(5) } ["p2"]=> object(Point)#%d (2) { ["x"]=> float(3) ["y"]=> float(4) } } } } } Done pq-2.2.3/tests/copy001.phpt0000644000076500000240000000232414560227740014210 0ustar mikestaff--TEST-- copy --SKIPIF-- --FILE-- exec("DROP TABLE IF EXISTS copy_test; CREATE TABLE copy_test (id serial, line text);"); $file = file(__FILE__); $in = new pq\COPY($c, "copy_test (line)", pq\COPY::FROM_STDIN, "DELIMITER '\t'"); var_dump( $c === $in->connection, "copy_test (line)" === $in->expression, pq\COPY::FROM_STDIN === $in->direction, "DELIMITER '\t'" === $in->options ); foreach ($file as $i => $line) { $in->put(addcslashes($line, "\\\t")); } $in->end(); $out = new pq\COPY($c, "copy_test (line)", pq\COPY::TO_STDOUT, "DELIMITER '\t'"); var_dump( $c === $out->connection, "copy_test (line)" === $out->expression, pq\COPY::TO_STDOUT === $out->direction, "DELIMITER '\t'" === $out->options ); while ($out->get($line)) { $lines[] = stripcslashes($line); } var_dump($file == $lines); if ($file != $lines) { foreach (array_keys(array_diff($file, $lines)) as $idx) { var_dump($idx, $file[$idx], $lines[$idx], "##############"); } } $c->exec("DROP TABLE copy_test"); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pq-2.2.3/tests/crash_cur_reverse_dep.phpt0000644000076500000240000000056114560227740017352 0ustar mikestaff--TEST-- crash txn reverse dependency from connection --SKIPIF-- =")) echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n"; ?> --FILE-- t = $c->startTransaction(); ?> ===DONE=== --EXPECT-- Test ===DONE=== pq-2.2.3/tests/crash_result_iterator.phpt0000644000076500000240000000066014560227740017425 0ustar mikestaff--TEST-- crash result iterator --SKIPIF-- --FILE-- exec($sql) as $row) { var_dump($row); } ?> ===DONE=== --EXPECT-- Test array(1) { [0]=> int(1) } array(1) { [0]=> int(2) } array(1) { [0]=> int(3) } ===DONE=== pq-2.2.3/tests/crash_stm_reverse_dep.phpt0000644000076500000240000000057214560227740017366 0ustar mikestaff--TEST-- crash stm reverse dependency from connection --SKIPIF-- =")) echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n"; ?> --FILE-- s = $c->prepare("test", "SELECT 1"); ?> ===DONE=== --EXPECT-- Test ===DONE=== pq-2.2.3/tests/crash_txn_reverse_dep.phpt0000644000076500000240000000062014560227740017366 0ustar mikestaff--TEST-- crash txn reverse dependency from connection --SKIPIF-- =")) echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n"; ?> --FILE-- c = $c->declare("test", pq\Cursor::WITH_HOLD, "SELECT 1"); ?> ===DONE=== --EXPECT-- Test ===DONE=== pq-2.2.3/tests/crash_unbuffered_async_prepare.phpt0000644000076500000240000000114514560227740021235 0ustar mikestaff--TEST-- crash unbuffered async prepare --SKIPIF-- --FILE-- busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); } try { $c = new pq\Connection(PQ_DSN); $c->unbuffered = true; $s = $c->prepareAsync("test", "SELECT * from generate_series(1,2)"); complete($c); $r = $s->execAsync(); complete($c); } catch (Exception $e) { echo $e; } unset($c); ?> ===DONE=== --EXPECT-- Test ===DONE===pq-2.2.3/tests/cursor001.phpt0000644000076500000240000000170614560227740014556 0ustar mikestaff--TEST-- cursor --SKIPIF-- --FILE-- declare("mycursor", pq\Cursor::WITH_HOLD, "SELECT * FROM generate_series(0,29) s WHERE (s%2)=0"); for ($r = $p->fetch(2); $r->numRows; $p->move(1), $r = $p->fetch(2)) { foreach ($r as $row) { foreach ($row as $col) { echo " $col"; } echo "\n"; } } try { $p = new pq\Cursor($c, "mycursor", pq\Cursor::WITH_HOLD, "SELECT * FROM generate_series(0,29) s WHERE (s%2)=0"); } catch (Exception $ex) { $p->close(); } $p = new pq\Cursor($c, "mycursor", pq\Cursor::WITH_HOLD, "SELECT * FROM generate_series(0,29) s WHERE (s%2)=0"); for ($r = $p->fetch(2); $r->numRows; $p->move(1), $r = $p->fetch(2)) { foreach ($r as $row) { foreach ($row as $col) { echo " $col"; } echo "\n"; } } ?> ===DONE=== --EXPECT-- Test 0 2 6 8 12 14 18 20 24 26 0 2 6 8 12 14 18 20 24 26 ===DONE=== pq-2.2.3/tests/encoding001.phpt0000644000076500000240000000076514560227740015033 0ustar mikestaff--TEST-- encoding --SKIPIF-- --FILE-- encoding); $c->encoding = "utf8"; var_dump($c->encoding); $c->exec("SELECT 'ßüpä…'")->fetchCol($val); var_dump($val); $tmp = 12345; $c->encoding = $tmp; var_dump($c->encoding); ?> DONE --EXPECTF-- Test string(%d) "%s" string(4) "UTF8" string(10) "ßüpä…" Notice: Unrecognized encoding '12345' in %s on line %d string(4) "UTF8" DONE pq-2.2.3/tests/exceptions001.phpt0000644000076500000240000000163314560227740015421 0ustar mikestaff--TEST-- exceptions --SKIPIF-- --FILE-- getCode() == pq\Exception::INVALID_ARGUMENT, $e->getCode()."!=".pq\Exception::INVALID_ARGUMENT); } class c extends pq\Connection { function __construct() { } function open($dsn) { parent::__construct($dsn); } } $c = new c; try { $c->reset(); foo(); } catch (pq\Exception\BadMethodCallException $e) { assert($e->getCode() == pq\Exception::UNINITIALIZED, $e->getCode()."!=".pq\Exception::UNINITIALIZED); } $c->open(PQ_DSN); try { $c->open(PQ_DSN); foo(); } catch (pq\Exception\BadMethodCallException $e) { assert($e->getCode() == pq\Exception::BAD_METHODCALL, $e->getCode()."!=".pq\Exception::BAD_METHODCALL); } ?> DONE --EXPECT-- Test DONE pq-2.2.3/tests/exceptions002.phpt0000644000076500000240000000067514560227740015427 0ustar mikestaff--TEST-- sql exception --SKIPIF-- --FILE-- exec("SELECT 1 FROM probably_non_existent_table"); } catch (pq\Exception $e) { var_dump($e instanceof pq\Exception\DomainException); var_dump($e->getCode() == pq\Exception::SQL); var_dump($e->sqlstate); } ?> DONE --EXPECT-- Test bool(true) bool(true) string(5) "42P01" DONE pq-2.2.3/tests/fetch001.phpt0000644000076500000240000000167114560227740014333 0ustar mikestaff--TEST-- fetch type --SKIPIF-- --FILE-- exec("SELECT a,b, NULL as c from generate_series(1,2) a, generate_series(2,4) b"); $r->fetchType = pq\Result::FETCH_ARRAY; foreach ($r as $k => $v) { printf("%s => %s,%s,%s\n", $k, $v[0], $v[1], $v[2]); $r->fetchType = (string) $r->fetchType; } $r->fetchType = pq\Result::FETCH_ASSOC; foreach ($r as $k => $v) { printf("%s => %s,%s,%s\n", $k, $v["a"], $v["b"], $v["c"]); $r->fetchType = (string) $r->fetchType; } $r->fetchType = pq\Result::FETCH_OBJECT; foreach ($r as $k => $v) { printf("%s => %s,%s,%s\n", $k, $v->a, $v->b, $v->c); $r->fetchType = (string) $r->fetchType; } ?> DONE --EXPECT-- Test 0 => 1,2, 1 => 1,3, 2 => 1,4, 3 => 2,2, 4 => 2,3, 5 => 2,4, 0 => 1,2, 1 => 1,3, 2 => 1,4, 3 => 2,2, 4 => 2,3, 5 => 2,4, 0 => 1,2, 1 => 1,3, 2 => 1,4, 3 => 2,2, 4 => 2,3, 5 => 2,4, DONE pq-2.2.3/tests/flush001.phpt0000644000076500000240000000136314560227740014361 0ustar mikestaff--TEST-- flush --SKIPIF-- --FILE-- nonblocking = true; var_dump($c->nonblocking); $c->execAsync("SELECT '".str_repeat("a", 6e7)."'", function($r) { $r->fetchCol($s); var_dump(strlen($s)); }); var_dump($flushed = $c->flush()); do { while (!$flushed || $c->busy) { $r = $c->busy ? [$c->socket] : null; $w = !$flushed ?[$c->socket] : null; if (stream_select($r, $w, $e, null)) { if ($r) { printf("P%d", $c->poll()); } if ($w) { printf("F%d", $flushed = $c->flush()); } } } echo "\n"; } while ($c->getResult()); ?> ===DONE=== --EXPECTF-- Test bool(true) bool(%s) %r(F0)*(F1)*(P3)+%r int(60000000) ===DONE=== pq-2.2.3/tests/gh-issue015_listeners.phpt0000644000076500000240000000255414560227740017064 0ustar mikestaff--TEST-- restore listeners on reset --SKIPIF-- --INI-- date.timezone=UTC --FILE-- listen("notify", function($channel, $message) { printf("%s: %s\n", $channel, $message); }); $c->on(pq\Connection::EVENT_RESET, function($conn) { printf("Connection was reset\n"); }); $c->notify("notify", "Gotcha!"); $c->resetAsync(); // wait until the stream becomes writable $w = array($c->socket); $r = $e = null; if (stream_select($r, $w, $e, null)) { // loop until the connection is established while (true) { switch ($c->poll()) { case pq\Connection::POLLING_READING: // we should wait for the stream to be read-ready $r = array($c->socket); stream_select($r, $w, $e, NULL); break; case pq\Connection::POLLING_WRITING: // we should wait for the stream to be write-ready $w = array($c->socket); $r = $e = null; stream_select($r, $w, $e, null); break; case pq\Connection::POLLING_FAILED: printf("Connection failed: %s\n", $c->errorMessage); break 2; case pq\Connection::POLLING_OK: printf("Connection completed\n"); break 2; } } } $c->notify("notify", "Do you miss me?"); $c->exec(""); ?> ===DONE=== --EXPECT-- Test notify: Gotcha! Connection was reset Connection completed notify: Do you miss me? ===DONE===pq-2.2.3/tests/gh-issue015_statements.phpt0000644000076500000240000000122314560227740017233 0ustar mikestaff--TEST-- restore statements on reset --SKIPIF-- --INI-- date.timezone=UTC --FILE-- prepare("test", "SELECT 1"); $c->on(pq\Connection::EVENT_RESET, function($conn) { printf("Connection was reset\n"); }); var_dump($s->exec()->fetchRow()); $c->reset(); // Fatal error: Uncaught exception 'pq\Exception\DomainException' with message 'ERROR: prepared statement "test" does not exist' var_dump($s->exec()->fetchRow()); ?> ===DONE=== --EXPECT-- Test array(1) { [0]=> int(1) } Connection was reset array(1) { [0]=> int(1) } ===DONE===pq-2.2.3/tests/gh-issue047_jsonb.phpt0000644000076500000240000000105214560227740016164 0ustar mikestaff--TEST-- json conv broken since 2.2.1 --SKIPIF-- --INI-- date.timezone=UTC --FILE-- defaultFetchType = \pq\Result::FETCH_ASSOC; $q = <<exec($q); var_dump($r->fetchAll()); ?> ===DONE=== --EXPECT-- Test array(2) { [0]=> array(1) { ["jsonb"]=> string(4) "text" } [1]=> array(1) { ["jsonb"]=> int(0) } } ===DONE=== pq-2.2.3/tests/info001.phpt0000644000076500000240000000043014560227740014165 0ustar mikestaff--TEST-- connection info --SKIPIF-- --FILE-- db, $c->user, $c->pass, $c->host, $c->port, $c->options ); ?> DONE --EXPECTF-- Test %s DONE pq-2.2.3/tests/info002.phpt0000644000076500000240000000042214560227740014167 0ustar mikestaff--TEST-- ext info --SKIPIF-- --FILE-- info(); ?> Done --EXPECTF-- Test pq PQ Support => enabled Extension Version => %s Used Library => Compiled => Linked libpq => %s => %s Done pq-2.2.3/tests/lob001.phpt0000644000076500000240000000115614560227740014014 0ustar mikestaff--TEST-- large objects --SKIPIF-- --FILE-- startTransaction(); $lob = $t->createLOB(); var_dump($lob->transaction === $t); $lob->write(file_get_contents(__FILE__)); var_dump($lob->tell()); $lob->seek(0, SEEK_SET); $dat = $lob->read(filesize(__FILE__)); var_dump(md5($dat)===md5_file(__FILE__)); $lob->truncate(5); $lob = new pq\Lob($t, $lob->oid); var_dump($lob->read(123)); $t->commit(); $t->unlinkLOB($lob->oid); ?> DONE --EXPECTF-- Test bool(true) int(474) bool(true) string(5) "%c?php" DONE pq-2.2.3/tests/lob002.phpt0000644000076500000240000000146314560227740014016 0ustar mikestaff--TEST-- large object stream --SKIPIF-- --FILE-- startTransaction(); $lob = $t->createLOB(); fwrite($lob->stream, file_get_contents(__FILE__)); var_dump(ftell($lob->stream)); fseek($lob->stream, 0, SEEK_SET); $dat = fread($lob->stream, filesize(__FILE__)); var_dump(md5($dat)===md5_file(__FILE__)); ftruncate($lob->stream, 5); $lob = new pq\Lob($t, $lob->oid); var_dump(fread($lob->stream, 123)); $t->commit(); $t->unlinkLOB($lob->oid); ?> DONE --EXPECTF-- Test int(488) bool(true) Warning: ftruncate(): Can't truncate this stream! in %s on line %d string(123) "%c?php echo "Test\n"; include "_setup.inc"; $c = new pq\Connection(PQ_DSN); $t = $c->startTransaction(); $lob = $t->creat" DONE pq-2.2.3/tests/lob003.phpt0000644000076500000240000000110314560227740014006 0ustar mikestaff--TEST-- large object closing stream --SKIPIF-- --FILE-- startTransaction(); $lob = $t->createLOB(); var_dump($lob->stream); var_dump($lob->stream); fclose($lob->stream); // bad boy! var_dump($lob->stream); var_dump(fread($lob->stream, 5)); $lob = null; ?> DONE --EXPECTF-- Test resource(%d) of type (stream) resource(%d) of type (stream) Warning: fclose(): %d is not a valid stream resource in %s on line %d resource(%d) of type (stream) string(0) "" DONE pq-2.2.3/tests/lob004.phpt0000644000076500000240000000065314560227740014020 0ustar mikestaff--TEST-- large object import/export --SKIPIF-- --CLEAN-- --FILE-- importLOB(__FILE__); var_dump($oid); $t->exportLOB($oid, "lob004.tmp"); var_dump(md5_file(__FILE__)===md5_file("lob004.tmp")); ?> DONE --EXPECTF-- Test int(%d) bool(true) DONE pq-2.2.3/tests/map001.phpt0000644000076500000240000000606114560227740014015 0ustar mikestaff--TEST-- map result --SKIPIF-- --FILE-- exec("select (ARRAY['one','two','three','four','five','six','seven','eight','nine','ten'])[a] num, ". "round(log(a)::numeric,3) log, round(exp(a)::numeric,3) exp from generate_series(1,10) a"); $r->fetchType = pq\Result::FETCH_OBJECT; var_dump($r->map()); var_dump($r->map() == $r->map(0)); var_dump($r->map() == $r->map(0, array(0,1,2))); $r = $c->exec("select * from generate_series(0,1) a, generate_series(0,1) b, generate_series(0,1) c, generate_series(0,1) d ". "order by a,b,c,d"); $r->fetchType = pq\Result::FETCH_ARRAY; var_dump($r->map(array(0,"b",2), "d")); ?> DONE --EXPECTF-- Test object(stdClass)#%d (10) { ["one"]=> object(stdClass)#%d (3) { ["num"]=> string(3) "one" ["log"]=> string(5) "0.000" ["exp"]=> string(5) "2.718" } ["two"]=> object(stdClass)#%d (3) { ["num"]=> string(3) "two" ["log"]=> string(5) "0.301" ["exp"]=> string(5) "7.389" } ["three"]=> object(stdClass)#%d (3) { ["num"]=> string(5) "three" ["log"]=> string(5) "0.477" ["exp"]=> string(6) "20.086" } ["four"]=> object(stdClass)#%d (3) { ["num"]=> string(4) "four" ["log"]=> string(5) "0.602" ["exp"]=> string(6) "54.598" } ["five"]=> object(stdClass)#%d (3) { ["num"]=> string(4) "five" ["log"]=> string(5) "0.699" ["exp"]=> string(7) "148.413" } ["six"]=> object(stdClass)#%d (3) { ["num"]=> string(3) "six" ["log"]=> string(5) "0.778" ["exp"]=> string(7) "403.429" } ["seven"]=> object(stdClass)#%d (3) { ["num"]=> string(5) "seven" ["log"]=> string(5) "0.845" ["exp"]=> string(8) "1096.633" } ["eight"]=> object(stdClass)#%d (3) { ["num"]=> string(5) "eight" ["log"]=> string(5) "0.903" ["exp"]=> string(8) "2980.958" } ["nine"]=> object(stdClass)#%d (3) { ["num"]=> string(4) "nine" ["log"]=> string(5) "0.954" ["exp"]=> string(8) "8103.084" } ["ten"]=> object(stdClass)#%d (3) { ["num"]=> string(3) "ten" ["log"]=> string(5) "1.000" ["exp"]=> string(9) "22026.466" } } bool(true) bool(true) array(2) { [0]=> array(2) { [0]=> array(2) { [0]=> array(1) { [3]=> string(1) "1" } [1]=> array(1) { [3]=> string(1) "1" } } [1]=> array(2) { [0]=> array(1) { [3]=> string(1) "1" } [1]=> array(1) { [3]=> string(1) "1" } } } [1]=> array(2) { [0]=> array(2) { [0]=> array(1) { [3]=> string(1) "1" } [1]=> array(1) { [3]=> string(1) "1" } } [1]=> array(2) { [0]=> array(1) { [3]=> string(1) "1" } [1]=> array(1) { [3]=> string(1) "1" } } } } DONE pq-2.2.3/tests/notify001.phpt0000644000076500000240000000214314560227740014545 0ustar mikestaff--TEST-- notify --SKIPIF-- --FILE-- listen("test", function($channel, $message, $pid) { printf("%s(%d): %s\n", $channel, $pid, $message); }); $producer = new pq\Connection(PQ_DSN); $producer->notify("test", "this is a test"); $consumer->exec("select 1"); $producer->notify("test", "this is an async test"); $r = array($consumer->socket); $w = null; $e = null; stream_select($r, $w, $e, NULL); $consumer->poll(); $producer->notify("other", "this should not show up"); stream_select($r, $w, $e, 0,1000); $consumer->poll(); $producer->notify("test", "just to be sure"); $r = array($consumer->socket); $w = null; $e = null; stream_select($r, $w, $e, 0,1000); $consumer->poll(); $consumer->unlisten("test"); $producer->notify("test", "this shouldn't show up either"); $r = array($consumer->socket); $w = null; $e = null; stream_select($r, $w, $e, 0,1000); $consumer->poll(); ?> DONE --EXPECTF-- Test test(%d): this is a test test(%d): this is an async test test(%d): just to be sure DONE pq-2.2.3/tests/persistent001.phpt0000644000076500000240000000117014560227740015434 0ustar mikestaff--TEST-- persistent handles --SKIPIF-- --FILE-- listen("chan", function($chan, $msg) { // dummy }); $c->on(pq\Connection::EVENT_RESULT, function($c, $res) { }); } if (!($i%10)) gc_collect_cycles(); $c->exec(""); } var_dump(raphf\stat_persistent_handles()->{"pq\\Connection"}); ?> DONE --EXPECTF-- Test array(1) { ["%S"]=> array(2) { ["used"]=> int(1) ["free"]=> int(2) } } DONE pq-2.2.3/tests/res001.phpt0000644000076500000240000000374114560227740014033 0ustar mikestaff--TEST-- empty result --SKIPIF-- --FILE-- Done --EXPECTF-- Test Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d object(pq\Result)#%d (9) { ["status"]=> NULL ["statusMessage"]=> NULL ["errorMessage"]=> NULL ["diag"]=> NULL ["numRows"]=> int(0) ["numCols"]=> int(0) ["affectedRows"]=> int(0) ["fetchType"]=> int(0) ["autoConvert"]=> int(65535) } Test Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d Warning: pq\Result not initialized in %s on line %d array(10) { ["affectedRows"]=> int(0) ["autoConvert"]=> int(65535) ["diag"]=> NULL ["dummy"]=> int(2) ["errorMessage"]=> NULL ["fetchType"]=> int(0) ["numCols"]=> int(0) ["numRows"]=> int(0) ["status"]=> NULL ["statusMessage"]=> NULL } Done pq-2.2.3/tests/reset001.phpt0000644000076500000240000000053514560227740014362 0ustar mikestaff--TEST-- connection reset --SKIPIF-- --FILE-- reset(); var_dump($c->status); $c->on(pq\Connection::EVENT_RESET, function ($c) { print "RESET!\n"; }); $c->reset(); var_dump($c->status); ?> DONE --EXPECT-- Test int(0) RESET! int(0) DONE pq-2.2.3/tests/savepoint001.phpt0000644000076500000240000000044714560227740015252 0ustar mikestaff--TEST-- savepoints --SKIPIF-- --FILE-- startTransaction(); $t->savepoint(); $t->savepoint(); $t->rollback(); $t->commit(); $t->rollback(); ?> DONE --EXPECT-- Test DONE pq-2.2.3/tests/stm_bound001.phpt0000644000076500000240000000123414560227740015227 0ustar mikestaff--TEST-- statement w/ bound vars --SKIPIF-- --FILE-- bind(0, $_1); $s->bind(1, $_2); $s->bind(2, $_3); $r = $s->exec(); var_dump($r->fetchAll()); $_1 = "\$1"; $_2 = "\$2"; $_3 = "\$3"; $r = $s->exec(); var_dump($r->fetchAll()); ?> Done --EXPECT-- Test array(1) { [0]=> array(3) { [0]=> NULL [1]=> NULL [2]=> NULL } } array(1) { [0]=> array(3) { [0]=> string(2) "$1" [1]=> string(2) "$2" [2]=> string(2) "$3" } } Done pq-2.2.3/tests/stm_deallocate_prepare001.phpt0000644000076500000240000000110714560227740017732 0ustar mikestaff--TEST-- Deallocated and prepare statement --SKIPIF-- --FILE-- prepare("test1", "SELECT 'test' || \$1"); $r = $s->exec(array("ing")); $r->fetchCol($d); var_dump($d); $s->deallocate(); try { $s->exec(array("ing")); } catch (pq\Exception\BadMethodCallException $e) { echo "Caught exception\n"; } $s->prepare(); $r = $s->exec(array("ing")); $r->fetchCol($d); var_dump($d); ?> DONE --EXPECT-- Test string(7) "testing" Caught exception string(7) "testing" DONE pq-2.2.3/tests/stm_desc001.phpt0000644000076500000240000000054614560227740015043 0ustar mikestaff--TEST-- desc statement --SKIPIF-- --FILE-- prepare("test1", "SELECT NOW() - \$1"); $r = $s->exec(array("2012-12-12 12:12:12")); $d = $s->desc(); printf("%s\n", (new pq\Types($c))[$d[0]]->typname); ?> DONE --EXPECT-- Test timestamptz DONE pq-2.2.3/tests/stm_desc002.phpt0000644000076500000240000000055714560227740015046 0ustar mikestaff--TEST-- desc statement --SKIPIF-- --FILE-- exec(array("2012-12-12 12:12:12")); $d = $s->desc(); printf("%s\n", (new pq\Types($c))[$d[0]]->typname); ?> DONE --EXPECT-- Test timestamptz DONE pq-2.2.3/tests/stm_props001.phpt0000644000076500000240000000127214560227740015265 0ustar mikestaff--TEST-- Statement properties --SKIPIF-- --FILE-- connection); var_dump($n === $s->name); var_dump($q === $s->query); var_dump($t === $s->types); $n = 'props2'; $s = $c->prepare($n, $q, $t); var_dump($c === $s->connection); var_dump($n === $s->name); var_dump($q === $s->query); var_dump($t === $s->types); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pq-2.2.3/tests/trans001.phpt0000644000076500000240000000241014560227740014361 0ustar mikestaff--TEST-- transaction --SKIPIF-- --FILE-- exec("DROP TABLE IF EXISTS test CASCADE"); $c->exec("SET client_min_messages TO NOTICE"); try { $c->exec("SET lc_messages TO 'C'"); } catch (pq\Exception $e) { // do not die if we are not superuser } $c->on(pq\Connection::EVENT_NOTICE, function($c, $notice) { echo "Got notice: $notice\n"; }); var_dump($c->transactionStatus == pq\Connection::TRANS_IDLE); $t = new pq\Transaction($c); var_dump($t->connection->transactionStatus == pq\Connection::TRANS_INTRANS); $c->exec("DROP TABLE IF EXISTS test"); $c->off(pq\Connection::EVENT_NOTICE); $c->exec("CREATE TABLE test (id serial, data text)"); $s = $c->prepare("test_insert", "INSERT INTO test (data) VALUES (\$1)", array((new pq\Types($c))["text"]->oid)); $s->exec(array("a")); $s->exec(array("b")); $s->exec(array("c")); $r = $c->exec("SELECT * FROM test"); while ($row = $r->fetchRow(pq\Result::FETCH_OBJECT)) { printf("%d => %s\n", $row->id, $row->data); } $t->rollback(); var_dump($c->transactionStatus == pq\Connection::TRANS_IDLE); ?> DONE --EXPECT-- Test bool(true) bool(true) Got notice: NOTICE: table "test" does not exist, skipping 1 => a 2 => b 3 => c bool(true) DONE pq-2.2.3/tests/trans002.phpt0000644000076500000240000000073214560227740014367 0ustar mikestaff--TEST-- txn properties --SKIPIF-- --FILE-- isolation, $t->readonly, $t->deferrable ); $t->isolation = pq\Transaction::SERIALIZABLE; $t->readonly = true; $t->deferrable = true; var_dump( $t->isolation, $t->readonly, $t->deferrable ); ?> DONE --EXPECTF-- Test int(0) bool(false) bool(false) int(2) bool(true) bool(true) DONE pq-2.2.3/tests/types001.phpt0000644000076500000240000000106514560227740014403 0ustar mikestaff--TEST-- types functionality --SKIPIF-- --FILE-- connection === $c); var_dump(isset($t["int4"]), empty($t["int4"])); var_dump(isset($t["whatthahell"]), empty($t["whatthahell"])); var_dump(isset($t[25]), empty($t[25])); var_dump(isset($t[0]), empty($t[0])); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(false) bool(false) bool(true) bool(true) bool(false) bool(false) bool(true) DONE pq-2.2.3/tests/types002.phpt0000644000076500000240000000435614560227740014412 0ustar mikestaff--TEST-- extended type support --SKIPIF-- --INI-- date.timezone=UTC --FILE-- exec("SET timezone TO UTC; SELECT NULL as null, true as bool, 1::int2 as int2, 2::int4 as int4, 3::int8 as int8, 1.1::float4 as float4, 2.2::float8 as float8, '2013-01-01'::date as date, '2013-01-01 01:01:01'::timestamp as timestamp, '2013-01-01 01:01:01 UTC'::timestamptz as timestamptz, array[array[1,2,3],array[4,5,6],array[NULL::int,NULL::int,NULL::int]] as intarray, array[box(point(1,2),point(2,3)),box(point(4,5),point(5,6))] as boxarray, array[]::text[] as emptyarray, 'foo\n'::bytea as bytea, 'foo\n'::bytea::text as bytea_text "); var_dump($r->fetchRow(pq\Result::FETCH_ASSOC)); ?> DONE --EXPECTF-- Test array(15) { ["null"]=> NULL ["bool"]=> bool(true) ["int2"]=> int(1) ["int4"]=> int(2) ["int8"]=> int(3) ["float4"]=> float(1.1) ["float8"]=> float(2.2) ["date"]=> object(pq\DateTime)#%d (4) { ["format"]=> string(5) "Y-m-d" ["date"]=> string(%d) "2013-01-01 00:00:00%r(\.000000)?%r" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } ["timestamp"]=> object(pq\DateTime)#%d (4) { ["format"]=> string(13) "Y-m-d H:i:s.u" ["date"]=> string(%d) "2013-01-01 01:01:01%r(\.000000)?%r" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } ["timestamptz"]=> object(pq\DateTime)#%d (4) { ["format"]=> string(14) "Y-m-d H:i:s.uO" ["date"]=> string(%d) "2013-01-01 01:01:01%r(\.000000)?%r" ["timezone_type"]=> int(1) ["timezone"]=> string(6) "+00:00" } ["intarray"]=> array(3) { [0]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } [1]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } [2]=> array(3) { [0]=> NULL [1]=> NULL [2]=> NULL } } ["boxarray"]=> array(2) { [0]=> string(11) "(2,3),(1,2)" [1]=> string(11) "(5,6),(4,5)" } ["emptyarray"]=> array(0) { } ["bytea"]=> string(4) "foo " ["bytea_text"]=> string(10) "\x666f6f0a" } DONE pq-2.2.3/tests/unbuffered001.phpt0000644000076500000240000000161214560227740015362 0ustar mikestaff--TEST-- unbuffered result --SKIPIF-- --FILE-- unbuffered ? true : false); $c->unbuffered = 1; var_dump($c->unbuffered); $c->execAsync("SELECT a from generate_series(1,10) a", function($res) { switch ($res->status) { case pq\Result::SINGLE_TUPLE: $res->fetchCol($val, "a"); printf("%s\n", $val); break; case pq\Result::TUPLES_OK: printf("-> fetching done\n"); break; default: printf("!! %s\n", $res->errorMessage); break; } }); do { while ($c->busy) { $r = array($c->socket); $w = $e = null; if (stream_select($r, $w, $e, null)) { $c->poll(); } } } while ($c->getResult()); ?> DONE --EXPECTF-- Test bool(false) bool(true) 1 2 3 4 5 6 7 8 9 10 -> fetching done DONE pq-2.2.3/tests/_setup.inc0000644000076500000240000000007614560227740014114 0ustar mikestaffserverVersion) > 0) { die("skip server {$c->serverVersion} is too old, needed " . SERVER_MIN); } } catch (pq\Exception $e) { die("skip could not connect to PQ_DSN ".$e->getMessage()); } pq-2.2.3/AUTHORS0000644000076500000240000000003714560227740012025 0ustar mikestaffMichael Wallner pq-2.2.3/BUGS0000644000076500000240000000005114560227740011434 0ustar mikestaffYay, no known and unresolved issues yet! pq-2.2.3/CONTRIBUTING.md0000644000076500000240000000361614560227740013214 0ustar mikestaff# Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at http://contributor-covenant.org/version/1/2/0/. pq-2.2.3/CREDITS0000644000076500000240000000002314560227740011770 0ustar mikestaffpq Michael Wallner pq-2.2.3/LICENSE0000644000076500000240000000250114560227740011760 0ustar mikestaffCopyright (c) 2013, Michael Wallner . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pq-2.2.3/THANKS0000644000076500000240000000014314560227740011666 0ustar mikestaffThanks go to the following people, who have contributed to this project: Remi Collet Chris Wright pq-2.2.3/TODO0000644000076500000240000000020614560227740011443 0ustar mikestaff* COPY: getAsync & putAsync * fetchInto/fetchCtor? * binary protocol? * parse explicit array dimension information in front of arrays pq-2.2.3/README.md0000644000076500000240000000416014560227740012235 0ustar mikestaff# pecl/pq [![Build Status](https://github.com/m6w6/ext-pq/workflows/ci/badge.svg?branch=master)](https://github.com/m6w6/ext-pq/actions?query=branch%3Amaster+workflow%3Aci) [![codecov](https://codecov.io/gh/m6w6/ext-pq/branch/master/graph/badge.svg?token=Nku9tz8EMj)](https://codecov.io/gh/m6w6/ext-pq) ## About: This is a modern binding to the mature [libpq](http://www.postgresql.org/docs/current/static/libpq.html), the official PostgreSQL C-client library. ### Highlights: * Nearly 100% support for [asynchronous usage](https://mdref.m6w6.name/pq/Connection/:%20Asynchronous%20Usage). * Extended [type support by pg_type](https://mdref.m6w6.name/pq/Types/:%20Overview). * Fetching simple [multi-dimensional array maps](https://mdref.m6w6.name/pq/Result/map). * Working [Gateway implementation](https://github.com/m6w6/pq-gateway). ## Documentation See the [online markdown reference](https://mdref.m6w6.name/pq). Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO). ## Install ### PECL pecl install pq ### PHARext Watch out for [PECL replicates](https://replicator.pharext.org?pq) and pharext packages attached to [releases](https://github.com/m6w6/ext-pq/releases). ### Checkout git clone github.com:m6w6/ext-pq cd ext-pq /path/to/phpize ./configure --with-php-config=/path/to/php-config make sudo make install ## Dependencies: This extension unconditionally depends on the pre-loaded presence of the following PHP extensions: - [raphf](http://pecl.php.net/package/raphf) - [spl](http://php.net/spl) It optionally depends on the following extensions: * [json](http://php.net/json) ## ChangeLog A comprehensive list of changes can be obtained from the [PECL website](https://pecl.php.net/package-changelog.php?package=pq). ## License ext-pq is licensed under the 2-Clause-BSD license, which can be found in the accompanying [LICENSE](./LICENSE) file. ## Contributing All forms of contribution are welcome! Please see the bundled [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed. The list of past and current contributors is maintained in [THANKS](./THANKS). pq-2.2.3/config.m40000644000076500000240000000007714560227740012470 0ustar mikestaffdnl phpize stub of config9.m4 for pecl/pq sinclude(config9.m4) pq-2.2.3/config9.m40000644000076500000240000001055114560227740012557 0ustar mikestaffPHP_ARG_WITH(pq, [whether to enable libpq (PostgreSQL) support], [ --with-pq[=DIR] Include libpq support]) if test "$PHP_PQ" != "no"; then SEARCH_PATH="/usr/local /usr /opt" if test "$PHP_PQ" != "yes"; then SEARCH_PATH="$PHP_PQ $SEARCH_PATH" fi AC_MSG_CHECKING(for pg_config) for i in $SEARCH_PATH; do if test -x "$i/bin/pg_config"; then PG_CONFIG="$i/bin/pg_config" break fi done if test -z "$PG_CONFIG"; then AC_PATH_PROG(PG_CONFIG, pg_config, no) fi AC_MSG_RESULT($PG_CONFIG) if test "$PG_CONFIG" = "no"; then AC_MSG_ERROR(could not find a usable pg_config in $SEARCH_PATH) else if test "$PHP_PQ" != "yes" -a "$PHP_PQ/bin/pg_config" != "$PG_CONFIG"; then AC_MSG_WARN(Found pg_config is not in $PHP_PQ) fi AC_MSG_CHECKING(for PostgreSQL version) PQ_VERSION=$($PG_CONFIG --version | $SED 's/PostgreSQL //') if test -z "$PQ_VERSION"; then AC_MSG_RESULT(not found) AC_MSG_ERROR(\`$PG_CONFIG --version\` did not provide any meaningful output, please reinstall postgresql/libpq) else AC_MSG_RESULT($PQ_VERSION) AC_DEFINE_UNQUOTED(PHP_PQ_LIBVERSION, "$PQ_VERSION", [ ]) fi PQ_INCDIR=$($PG_CONFIG --includedir) PQ_LIBDIR=$($PG_CONFIG --libdir) fi PHP_ADD_INCLUDE($PQ_INCDIR) ifdef([AC_PROG_EGREP], [ AC_PROG_EGREP ], [ AC_CHECK_PROG(EGREP, egrep, egrep) ]) dnl dnl PQ_CHECK_CONST(name) dnl AC_DEFUN([PQ_CHECK_CONST], [ AC_MSG_CHECKING(for $1) if $EGREP -q $1 $PQ_INCDIR/libpq-fe.h; then AC_DEFINE(HAVE_$1, 1, [Have $1]) AC_MSG_RESULT(yep) else AC_MSG_RESULT(nope) fi ]) PQ_CHECK_CONST(PGRES_SINGLE_TUPLE) PQ_CHECK_CONST(PGRES_COPY_BOTH) PQ_CHECK_CONST(CONNECTION_CHECK_WRITABLE) PQ_CHECK_CONST(CONNECTION_CONSUME) PQ_CHECK_CONST(CONNECTION_GSS_STARTUP) dnl dnl PQ_CHECK_FUNC(sym, fail-hard) dnl AC_DEFUN([PQ_CHECK_FUNC], [ PQ_SYM=$1 FAIL_HARD=$2 save_LIBS="$LIBS" LIBS= PHP_CHECK_LIBRARY(pq, $1, [ AC_DEFINE([HAVE_]translit($1,a-z,A-Z), 1, Have $1) ], [ if test -n "$FAIL_HARD"; then if $FAIL_HARD; then AC_MSG_ERROR(could not find $PQ_SYM in -lpq -L$PQ_LIBDIR) fi fi ], [ -L$PQ_LIBDIR ]) LIBS="$save_LIBS" ]) PQ_CHECK_FUNC(PQregisterEventProc, true) PHP_ADD_LIBRARY_WITH_PATH(pq, $PQ_LIBDIR, PQ_SHARED_LIBADD) PHP_SUBST(PQ_SHARED_LIBADD) PQ_CHECK_FUNC(PQlibVersion) PQ_CHECK_FUNC(PQprotocolVersion) PQ_CHECK_FUNC(PQserverVersion) PQ_CHECK_FUNC(PQconninfo) PQ_CHECK_FUNC(PQsetSingleRowMode) dnl dnl PQ_HAVE_PHP_EXT(name[, code-if-yes[, code-if-not]]) dnl AC_DEFUN([PQ_HAVE_PHP_EXT], [ extname=$1 haveext=$[PHP_]translit($1,a-z_-,A-Z__) AC_MSG_CHECKING([for ext/$extname support]) if test "$haveext" != "no" && test "x$haveext" != "x"; then [PHP_PQ_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1 AC_MSG_RESULT([yes]) $2 elif test -x "$PHP_EXECUTABLE"; then grepext=`$PHP_EXECUTABLE -m | $EGREP ^$extname\$` if test "$grepext" = "$extname"; then [PHP_PQ_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1 AC_MSG_RESULT([yes]) $2 else [PHP_PQ_HAVE_EXT_]translit($1,a-z_-,A-Z__)= AC_MSG_RESULT([no]) $3 fi else [PHP_PQ_HAVE_EXT_]translit($1,a-z_-,A-Z__)= AC_MSG_RESULT([no]) $3 fi ]) PQ_SRC="\ src/php_pq_module.c\ src/php_pq_misc.c\ src/php_pq_callback.c\ src/php_pq_object.c\ src/php_pq_params.c\ src/php_pqcancel.c\ src/php_pqconn.c\ src/php_pqconn_event.c\ src/php_pqcopy.c\ src/php_pqexc.c\ src/php_pqlob.c\ src/php_pqres.c\ src/php_pqstm.c\ src/php_pqtxn.c\ src/php_pqtypes.c\ src/php_pqcur.c\ " PHP_NEW_EXTENSION(pq, $PQ_SRC, $ext_shared) PHP_ADD_BUILD_DIR($ext_builddir/src) PHP_ADD_INCLUDE($ext_srcdir/src) PQ_HAVE_PHP_EXT([raphf], [ AC_MSG_CHECKING([for php_raphf.h]) PQ_EXT_RAPHF_INCDIR= for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../raphf; do if test -d $i; then if test -f $i/php_raphf.h; then PQ_EXT_RAPHF_INCDIR=$i break elif test -f $i/ext/raphf/php_raphf.h; then PQ_EXT_RAPHF_INCDIR=$i/ext/raphf break fi fi done if test "x$PQ_EXT_RAPHF_INCDIR" = "x"; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([$PQ_EXT_RAPHF_INCDIR]) AC_DEFINE([PHP_PQ_HAVE_PHP_RAPHF_H], [1], [Have ext/raphf support]) PHP_ADD_INCLUDE([$PQ_EXT_RAPHF_INCDIR]) fi ], [ AC_MSG_ERROR([Please install pecl/raphf and activate extension=raphf.$SHLIB_DL_SUFFIX_NAME in your php.ini]) ]) PHP_ADD_EXTENSION_DEP(pq, raphf, true) fi pq-2.2.3/php_pq.h0000644000076500000240000000311014560227740012410 0ustar mikestaff/* +--------------------------------------------------------------------+ | PECL :: pq | +--------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ | Copyright (c) 2013, Michael Wallner | +--------------------------------------------------------------------+ */ #ifndef PHP_PQ_H #define PHP_PQ_H #define PHP_PQ_VERSION "2.2.3" #ifdef PHP_WIN32 # define PHP_PQ_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_PQ_API extern __attribute__ ((visibility("default"))) #else # define PHP_PQ_API extern #endif extern int pq_module_number; extern zend_module_entry pq_module_entry; #define phpext_pq_ptr &pq_module_entry ZEND_BEGIN_MODULE_GLOBALS(php_pq) struct { /* for ext-raphf */ zend_string *name; } connection; ZEND_END_MODULE_GLOBALS(php_pq) ZEND_EXTERN_MODULE_GLOBALS(php_pq); #ifdef ZTS # include "TSRM/TSRM.h" # define PHP_PQ_G ((zend_php_pq_globals *) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(php_pq_globals_id)]) #else # define PHP_PQ_G (&php_pq_globals) #endif #endif /* PHP_PQ_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ pq-2.2.3/php_pq_type.h0000644000076500000240000004664614560227740013476 0ustar mikestaff /* Generated file. See scripts/gen_pq_type-pq11.php */ #ifndef PHP_PQ_TYPE # define PHP_PQ_TYPE(t,o) #endif #ifndef PHP_PQ_OID_BOOL # define PHP_PQ_OID_BOOL 16 #endif PHP_PQ_TYPE("BOOL", 16) #ifndef PHP_PQ_OID_BYTEA # define PHP_PQ_OID_BYTEA 17 #endif PHP_PQ_TYPE("BYTEA", 17) #ifndef PHP_PQ_OID_CHAR # define PHP_PQ_OID_CHAR 18 #endif PHP_PQ_TYPE("CHAR", 18) #ifndef PHP_PQ_OID_NAME # define PHP_PQ_OID_NAME 19 #endif PHP_PQ_TYPE("NAME", 19) #ifndef PHP_PQ_OID_INT8 # define PHP_PQ_OID_INT8 20 #endif PHP_PQ_TYPE("INT8", 20) #ifndef PHP_PQ_OID_INT2 # define PHP_PQ_OID_INT2 21 #endif PHP_PQ_TYPE("INT2", 21) #ifndef PHP_PQ_OID_INT2VECTOR # define PHP_PQ_OID_INT2VECTOR 22 #endif PHP_PQ_TYPE("INT2VECTOR", 22) #ifndef PHP_PQ_OID_INT4 # define PHP_PQ_OID_INT4 23 #endif PHP_PQ_TYPE("INT4", 23) #ifndef PHP_PQ_OID_REGPROC # define PHP_PQ_OID_REGPROC 24 #endif PHP_PQ_TYPE("REGPROC", 24) #ifndef PHP_PQ_OID_TEXT # define PHP_PQ_OID_TEXT 25 #endif PHP_PQ_TYPE("TEXT", 25) #ifndef PHP_PQ_OID_OID # define PHP_PQ_OID_OID 26 #endif PHP_PQ_TYPE("OID", 26) #ifndef PHP_PQ_OID_TID # define PHP_PQ_OID_TID 27 #endif PHP_PQ_TYPE("TID", 27) #ifndef PHP_PQ_OID_XID # define PHP_PQ_OID_XID 28 #endif PHP_PQ_TYPE("XID", 28) #ifndef PHP_PQ_OID_CID # define PHP_PQ_OID_CID 29 #endif PHP_PQ_TYPE("CID", 29) #ifndef PHP_PQ_OID_OIDVECTOR # define PHP_PQ_OID_OIDVECTOR 30 #endif PHP_PQ_TYPE("OIDVECTOR", 30) #ifndef PHP_PQ_OID_PG_DDL_COMMAND # define PHP_PQ_OID_PG_DDL_COMMAND 32 #endif PHP_PQ_TYPE("PG_DDL_COMMAND", 32) #ifndef PHP_PQ_OID_PG_TYPE # define PHP_PQ_OID_PG_TYPE 71 #endif PHP_PQ_TYPE("PG_TYPE", 71) #ifndef PHP_PQ_OID_PG_ATTRIBUTE # define PHP_PQ_OID_PG_ATTRIBUTE 75 #endif PHP_PQ_TYPE("PG_ATTRIBUTE", 75) #ifndef PHP_PQ_OID_PG_PROC # define PHP_PQ_OID_PG_PROC 81 #endif PHP_PQ_TYPE("PG_PROC", 81) #ifndef PHP_PQ_OID_PG_CLASS # define PHP_PQ_OID_PG_CLASS 83 #endif PHP_PQ_TYPE("PG_CLASS", 83) #ifndef PHP_PQ_OID_JSON # define PHP_PQ_OID_JSON 114 #endif PHP_PQ_TYPE("JSON", 114) #ifndef PHP_PQ_OID_XML # define PHP_PQ_OID_XML 142 #endif PHP_PQ_TYPE("XML", 142) #ifndef PHP_PQ_OID_XMLARRAY # define PHP_PQ_OID_XMLARRAY 143 #endif PHP_PQ_TYPE("XMLARRAY", 143) #ifndef PHP_PQ_OID_PG_NODE_TREE # define PHP_PQ_OID_PG_NODE_TREE 194 #endif PHP_PQ_TYPE("PG_NODE_TREE", 194) #ifndef PHP_PQ_OID_JSONARRAY # define PHP_PQ_OID_JSONARRAY 199 #endif PHP_PQ_TYPE("JSONARRAY", 199) #ifndef PHP_PQ_OID_SMGR # define PHP_PQ_OID_SMGR 210 #endif PHP_PQ_TYPE("SMGR", 210) #ifndef PHP_PQ_OID_INDEX_AM_HANDLER # define PHP_PQ_OID_INDEX_AM_HANDLER 325 #endif PHP_PQ_TYPE("INDEX_AM_HANDLER", 325) #ifndef PHP_PQ_OID_POINT # define PHP_PQ_OID_POINT 600 #endif PHP_PQ_TYPE("POINT", 600) #ifndef PHP_PQ_OID_LSEG # define PHP_PQ_OID_LSEG 601 #endif PHP_PQ_TYPE("LSEG", 601) #ifndef PHP_PQ_OID_PATH # define PHP_PQ_OID_PATH 602 #endif PHP_PQ_TYPE("PATH", 602) #ifndef PHP_PQ_OID_BOX # define PHP_PQ_OID_BOX 603 #endif PHP_PQ_TYPE("BOX", 603) #ifndef PHP_PQ_OID_POLYGON # define PHP_PQ_OID_POLYGON 604 #endif PHP_PQ_TYPE("POLYGON", 604) #ifndef PHP_PQ_OID_LINE # define PHP_PQ_OID_LINE 628 #endif PHP_PQ_TYPE("LINE", 628) #ifndef PHP_PQ_OID_LINEARRAY # define PHP_PQ_OID_LINEARRAY 629 #endif PHP_PQ_TYPE("LINEARRAY", 629) #ifndef PHP_PQ_OID_CIDR # define PHP_PQ_OID_CIDR 650 #endif PHP_PQ_TYPE("CIDR", 650) #ifndef PHP_PQ_OID_CIDRARRAY # define PHP_PQ_OID_CIDRARRAY 651 #endif PHP_PQ_TYPE("CIDRARRAY", 651) #ifndef PHP_PQ_OID_FLOAT4 # define PHP_PQ_OID_FLOAT4 700 #endif PHP_PQ_TYPE("FLOAT4", 700) #ifndef PHP_PQ_OID_FLOAT8 # define PHP_PQ_OID_FLOAT8 701 #endif PHP_PQ_TYPE("FLOAT8", 701) #ifndef PHP_PQ_OID_UNKNOWN # define PHP_PQ_OID_UNKNOWN 705 #endif PHP_PQ_TYPE("UNKNOWN", 705) #ifndef PHP_PQ_OID_CIRCLE # define PHP_PQ_OID_CIRCLE 718 #endif PHP_PQ_TYPE("CIRCLE", 718) #ifndef PHP_PQ_OID_CIRCLEARRAY # define PHP_PQ_OID_CIRCLEARRAY 719 #endif PHP_PQ_TYPE("CIRCLEARRAY", 719) #ifndef PHP_PQ_OID_MACADDR8 # define PHP_PQ_OID_MACADDR8 774 #endif PHP_PQ_TYPE("MACADDR8", 774) #ifndef PHP_PQ_OID_MACADDR8ARRAY # define PHP_PQ_OID_MACADDR8ARRAY 775 #endif PHP_PQ_TYPE("MACADDR8ARRAY", 775) #ifndef PHP_PQ_OID_MONEY # define PHP_PQ_OID_MONEY 790 #endif PHP_PQ_TYPE("MONEY", 790) #ifndef PHP_PQ_OID_MONEYARRAY # define PHP_PQ_OID_MONEYARRAY 791 #endif PHP_PQ_TYPE("MONEYARRAY", 791) #ifndef PHP_PQ_OID_MACADDR # define PHP_PQ_OID_MACADDR 829 #endif PHP_PQ_TYPE("MACADDR", 829) #ifndef PHP_PQ_OID_INET # define PHP_PQ_OID_INET 869 #endif PHP_PQ_TYPE("INET", 869) #ifndef PHP_PQ_OID_BOOLARRAY # define PHP_PQ_OID_BOOLARRAY 1000 #endif PHP_PQ_TYPE("BOOLARRAY", 1000) #ifndef PHP_PQ_OID_BYTEAARRAY # define PHP_PQ_OID_BYTEAARRAY 1001 #endif PHP_PQ_TYPE("BYTEAARRAY", 1001) #ifndef PHP_PQ_OID_CHARARRAY # define PHP_PQ_OID_CHARARRAY 1002 #endif PHP_PQ_TYPE("CHARARRAY", 1002) #ifndef PHP_PQ_OID_NAMEARRAY # define PHP_PQ_OID_NAMEARRAY 1003 #endif PHP_PQ_TYPE("NAMEARRAY", 1003) #ifndef PHP_PQ_OID_INT2ARRAY # define PHP_PQ_OID_INT2ARRAY 1005 #endif PHP_PQ_TYPE("INT2ARRAY", 1005) #ifndef PHP_PQ_OID_INT2VECTORARRAY # define PHP_PQ_OID_INT2VECTORARRAY 1006 #endif PHP_PQ_TYPE("INT2VECTORARRAY", 1006) #ifndef PHP_PQ_OID_INT4ARRAY # define PHP_PQ_OID_INT4ARRAY 1007 #endif PHP_PQ_TYPE("INT4ARRAY", 1007) #ifndef PHP_PQ_OID_REGPROCARRAY # define PHP_PQ_OID_REGPROCARRAY 1008 #endif PHP_PQ_TYPE("REGPROCARRAY", 1008) #ifndef PHP_PQ_OID_TEXTARRAY # define PHP_PQ_OID_TEXTARRAY 1009 #endif PHP_PQ_TYPE("TEXTARRAY", 1009) #ifndef PHP_PQ_OID_TIDARRAY # define PHP_PQ_OID_TIDARRAY 1010 #endif PHP_PQ_TYPE("TIDARRAY", 1010) #ifndef PHP_PQ_OID_XIDARRAY # define PHP_PQ_OID_XIDARRAY 1011 #endif PHP_PQ_TYPE("XIDARRAY", 1011) #ifndef PHP_PQ_OID_CIDARRAY # define PHP_PQ_OID_CIDARRAY 1012 #endif PHP_PQ_TYPE("CIDARRAY", 1012) #ifndef PHP_PQ_OID_OIDVECTORARRAY # define PHP_PQ_OID_OIDVECTORARRAY 1013 #endif PHP_PQ_TYPE("OIDVECTORARRAY", 1013) #ifndef PHP_PQ_OID_BPCHARARRAY # define PHP_PQ_OID_BPCHARARRAY 1014 #endif PHP_PQ_TYPE("BPCHARARRAY", 1014) #ifndef PHP_PQ_OID_VARCHARARRAY # define PHP_PQ_OID_VARCHARARRAY 1015 #endif PHP_PQ_TYPE("VARCHARARRAY", 1015) #ifndef PHP_PQ_OID_INT8ARRAY # define PHP_PQ_OID_INT8ARRAY 1016 #endif PHP_PQ_TYPE("INT8ARRAY", 1016) #ifndef PHP_PQ_OID_POINTARRAY # define PHP_PQ_OID_POINTARRAY 1017 #endif PHP_PQ_TYPE("POINTARRAY", 1017) #ifndef PHP_PQ_OID_LSEGARRAY # define PHP_PQ_OID_LSEGARRAY 1018 #endif PHP_PQ_TYPE("LSEGARRAY", 1018) #ifndef PHP_PQ_OID_PATHARRAY # define PHP_PQ_OID_PATHARRAY 1019 #endif PHP_PQ_TYPE("PATHARRAY", 1019) #ifndef PHP_PQ_OID_BOXARRAY # define PHP_PQ_OID_BOXARRAY 1020 #endif PHP_PQ_TYPE("BOXARRAY", 1020) #ifndef PHP_PQ_OID_FLOAT4ARRAY # define PHP_PQ_OID_FLOAT4ARRAY 1021 #endif PHP_PQ_TYPE("FLOAT4ARRAY", 1021) #ifndef PHP_PQ_OID_FLOAT8ARRAY # define PHP_PQ_OID_FLOAT8ARRAY 1022 #endif PHP_PQ_TYPE("FLOAT8ARRAY", 1022) #ifndef PHP_PQ_OID_POLYGONARRAY # define PHP_PQ_OID_POLYGONARRAY 1027 #endif PHP_PQ_TYPE("POLYGONARRAY", 1027) #ifndef PHP_PQ_OID_OIDARRAY # define PHP_PQ_OID_OIDARRAY 1028 #endif PHP_PQ_TYPE("OIDARRAY", 1028) #ifndef PHP_PQ_OID_ACLITEM # define PHP_PQ_OID_ACLITEM 1033 #endif PHP_PQ_TYPE("ACLITEM", 1033) #ifndef PHP_PQ_OID_ACLITEMARRAY # define PHP_PQ_OID_ACLITEMARRAY 1034 #endif PHP_PQ_TYPE("ACLITEMARRAY", 1034) #ifndef PHP_PQ_OID_MACADDRARRAY # define PHP_PQ_OID_MACADDRARRAY 1040 #endif PHP_PQ_TYPE("MACADDRARRAY", 1040) #ifndef PHP_PQ_OID_INETARRAY # define PHP_PQ_OID_INETARRAY 1041 #endif PHP_PQ_TYPE("INETARRAY", 1041) #ifndef PHP_PQ_OID_BPCHAR # define PHP_PQ_OID_BPCHAR 1042 #endif PHP_PQ_TYPE("BPCHAR", 1042) #ifndef PHP_PQ_OID_VARCHAR # define PHP_PQ_OID_VARCHAR 1043 #endif PHP_PQ_TYPE("VARCHAR", 1043) #ifndef PHP_PQ_OID_DATE # define PHP_PQ_OID_DATE 1082 #endif PHP_PQ_TYPE("DATE", 1082) #ifndef PHP_PQ_OID_TIME # define PHP_PQ_OID_TIME 1083 #endif PHP_PQ_TYPE("TIME", 1083) #ifndef PHP_PQ_OID_TIMESTAMP # define PHP_PQ_OID_TIMESTAMP 1114 #endif PHP_PQ_TYPE("TIMESTAMP", 1114) #ifndef PHP_PQ_OID_TIMESTAMPARRAY # define PHP_PQ_OID_TIMESTAMPARRAY 1115 #endif PHP_PQ_TYPE("TIMESTAMPARRAY", 1115) #ifndef PHP_PQ_OID_DATEARRAY # define PHP_PQ_OID_DATEARRAY 1182 #endif PHP_PQ_TYPE("DATEARRAY", 1182) #ifndef PHP_PQ_OID_TIMEARRAY # define PHP_PQ_OID_TIMEARRAY 1183 #endif PHP_PQ_TYPE("TIMEARRAY", 1183) #ifndef PHP_PQ_OID_TIMESTAMPTZ # define PHP_PQ_OID_TIMESTAMPTZ 1184 #endif PHP_PQ_TYPE("TIMESTAMPTZ", 1184) #ifndef PHP_PQ_OID_TIMESTAMPTZARRAY # define PHP_PQ_OID_TIMESTAMPTZARRAY 1185 #endif PHP_PQ_TYPE("TIMESTAMPTZARRAY", 1185) #ifndef PHP_PQ_OID_INTERVAL # define PHP_PQ_OID_INTERVAL 1186 #endif PHP_PQ_TYPE("INTERVAL", 1186) #ifndef PHP_PQ_OID_INTERVALARRAY # define PHP_PQ_OID_INTERVALARRAY 1187 #endif PHP_PQ_TYPE("INTERVALARRAY", 1187) #ifndef PHP_PQ_OID_NUMERICARRAY # define PHP_PQ_OID_NUMERICARRAY 1231 #endif PHP_PQ_TYPE("NUMERICARRAY", 1231) #ifndef PHP_PQ_OID_CSTRINGARRAY # define PHP_PQ_OID_CSTRINGARRAY 1263 #endif PHP_PQ_TYPE("CSTRINGARRAY", 1263) #ifndef PHP_PQ_OID_TIMETZ # define PHP_PQ_OID_TIMETZ 1266 #endif PHP_PQ_TYPE("TIMETZ", 1266) #ifndef PHP_PQ_OID_TIMETZARRAY # define PHP_PQ_OID_TIMETZARRAY 1270 #endif PHP_PQ_TYPE("TIMETZARRAY", 1270) #ifndef PHP_PQ_OID_BIT # define PHP_PQ_OID_BIT 1560 #endif PHP_PQ_TYPE("BIT", 1560) #ifndef PHP_PQ_OID_BITARRAY # define PHP_PQ_OID_BITARRAY 1561 #endif PHP_PQ_TYPE("BITARRAY", 1561) #ifndef PHP_PQ_OID_VARBIT # define PHP_PQ_OID_VARBIT 1562 #endif PHP_PQ_TYPE("VARBIT", 1562) #ifndef PHP_PQ_OID_VARBITARRAY # define PHP_PQ_OID_VARBITARRAY 1563 #endif PHP_PQ_TYPE("VARBITARRAY", 1563) #ifndef PHP_PQ_OID_NUMERIC # define PHP_PQ_OID_NUMERIC 1700 #endif PHP_PQ_TYPE("NUMERIC", 1700) #ifndef PHP_PQ_OID_REFCURSOR # define PHP_PQ_OID_REFCURSOR 1790 #endif PHP_PQ_TYPE("REFCURSOR", 1790) #ifndef PHP_PQ_OID_REFCURSORARRAY # define PHP_PQ_OID_REFCURSORARRAY 2201 #endif PHP_PQ_TYPE("REFCURSORARRAY", 2201) #ifndef PHP_PQ_OID_REGPROCEDURE # define PHP_PQ_OID_REGPROCEDURE 2202 #endif PHP_PQ_TYPE("REGPROCEDURE", 2202) #ifndef PHP_PQ_OID_REGOPER # define PHP_PQ_OID_REGOPER 2203 #endif PHP_PQ_TYPE("REGOPER", 2203) #ifndef PHP_PQ_OID_REGOPERATOR # define PHP_PQ_OID_REGOPERATOR 2204 #endif PHP_PQ_TYPE("REGOPERATOR", 2204) #ifndef PHP_PQ_OID_REGCLASS # define PHP_PQ_OID_REGCLASS 2205 #endif PHP_PQ_TYPE("REGCLASS", 2205) #ifndef PHP_PQ_OID_REGTYPE # define PHP_PQ_OID_REGTYPE 2206 #endif PHP_PQ_TYPE("REGTYPE", 2206) #ifndef PHP_PQ_OID_REGPROCEDUREARRAY # define PHP_PQ_OID_REGPROCEDUREARRAY 2207 #endif PHP_PQ_TYPE("REGPROCEDUREARRAY", 2207) #ifndef PHP_PQ_OID_REGOPERARRAY # define PHP_PQ_OID_REGOPERARRAY 2208 #endif PHP_PQ_TYPE("REGOPERARRAY", 2208) #ifndef PHP_PQ_OID_REGOPERATORARRAY # define PHP_PQ_OID_REGOPERATORARRAY 2209 #endif PHP_PQ_TYPE("REGOPERATORARRAY", 2209) #ifndef PHP_PQ_OID_REGCLASSARRAY # define PHP_PQ_OID_REGCLASSARRAY 2210 #endif PHP_PQ_TYPE("REGCLASSARRAY", 2210) #ifndef PHP_PQ_OID_REGTYPEARRAY # define PHP_PQ_OID_REGTYPEARRAY 2211 #endif PHP_PQ_TYPE("REGTYPEARRAY", 2211) #ifndef PHP_PQ_OID_RECORD # define PHP_PQ_OID_RECORD 2249 #endif PHP_PQ_TYPE("RECORD", 2249) #ifndef PHP_PQ_OID_CSTRING # define PHP_PQ_OID_CSTRING 2275 #endif PHP_PQ_TYPE("CSTRING", 2275) #ifndef PHP_PQ_OID_ANY # define PHP_PQ_OID_ANY 2276 #endif PHP_PQ_TYPE("ANY", 2276) #ifndef PHP_PQ_OID_ANYARRAY # define PHP_PQ_OID_ANYARRAY 2277 #endif PHP_PQ_TYPE("ANYARRAY", 2277) #ifndef PHP_PQ_OID_VOID # define PHP_PQ_OID_VOID 2278 #endif PHP_PQ_TYPE("VOID", 2278) #ifndef PHP_PQ_OID_TRIGGER # define PHP_PQ_OID_TRIGGER 2279 #endif PHP_PQ_TYPE("TRIGGER", 2279) #ifndef PHP_PQ_OID_LANGUAGE_HANDLER # define PHP_PQ_OID_LANGUAGE_HANDLER 2280 #endif PHP_PQ_TYPE("LANGUAGE_HANDLER", 2280) #ifndef PHP_PQ_OID_INTERNAL # define PHP_PQ_OID_INTERNAL 2281 #endif PHP_PQ_TYPE("INTERNAL", 2281) #ifndef PHP_PQ_OID_OPAQUE # define PHP_PQ_OID_OPAQUE 2282 #endif PHP_PQ_TYPE("OPAQUE", 2282) #ifndef PHP_PQ_OID_ANYELEMENT # define PHP_PQ_OID_ANYELEMENT 2283 #endif PHP_PQ_TYPE("ANYELEMENT", 2283) #ifndef PHP_PQ_OID__RECORD # define PHP_PQ_OID__RECORD 2287 #endif PHP_PQ_TYPE("_RECORD", 2287) #ifndef PHP_PQ_OID_ANYNONARRAY # define PHP_PQ_OID_ANYNONARRAY 2776 #endif PHP_PQ_TYPE("ANYNONARRAY", 2776) #ifndef PHP_PQ_OID_TXID_SNAPSHOTARRAY # define PHP_PQ_OID_TXID_SNAPSHOTARRAY 2949 #endif PHP_PQ_TYPE("TXID_SNAPSHOTARRAY", 2949) #ifndef PHP_PQ_OID_UUID # define PHP_PQ_OID_UUID 2950 #endif PHP_PQ_TYPE("UUID", 2950) #ifndef PHP_PQ_OID_UUIDARRAY # define PHP_PQ_OID_UUIDARRAY 2951 #endif PHP_PQ_TYPE("UUIDARRAY", 2951) #ifndef PHP_PQ_OID_TXID_SNAPSHOT # define PHP_PQ_OID_TXID_SNAPSHOT 2970 #endif PHP_PQ_TYPE("TXID_SNAPSHOT", 2970) #ifndef PHP_PQ_OID_FDW_HANDLER # define PHP_PQ_OID_FDW_HANDLER 3115 #endif PHP_PQ_TYPE("FDW_HANDLER", 3115) #ifndef PHP_PQ_OID_PG_LSN # define PHP_PQ_OID_PG_LSN 3220 #endif PHP_PQ_TYPE("PG_LSN", 3220) #ifndef PHP_PQ_OID_PG_LSNARRAY # define PHP_PQ_OID_PG_LSNARRAY 3221 #endif PHP_PQ_TYPE("PG_LSNARRAY", 3221) #ifndef PHP_PQ_OID_TSM_HANDLER # define PHP_PQ_OID_TSM_HANDLER 3310 #endif PHP_PQ_TYPE("TSM_HANDLER", 3310) #ifndef PHP_PQ_OID_PG_NDISTINCT # define PHP_PQ_OID_PG_NDISTINCT 3361 #endif PHP_PQ_TYPE("PG_NDISTINCT", 3361) #ifndef PHP_PQ_OID_PG_DEPENDENCIES # define PHP_PQ_OID_PG_DEPENDENCIES 3402 #endif PHP_PQ_TYPE("PG_DEPENDENCIES", 3402) #ifndef PHP_PQ_OID_ANYENUM # define PHP_PQ_OID_ANYENUM 3500 #endif PHP_PQ_TYPE("ANYENUM", 3500) #ifndef PHP_PQ_OID_TSVECTOR # define PHP_PQ_OID_TSVECTOR 3614 #endif PHP_PQ_TYPE("TSVECTOR", 3614) #ifndef PHP_PQ_OID_TSQUERY # define PHP_PQ_OID_TSQUERY 3615 #endif PHP_PQ_TYPE("TSQUERY", 3615) #ifndef PHP_PQ_OID_GTSVECTOR # define PHP_PQ_OID_GTSVECTOR 3642 #endif PHP_PQ_TYPE("GTSVECTOR", 3642) #ifndef PHP_PQ_OID_TSVECTORARRAY # define PHP_PQ_OID_TSVECTORARRAY 3643 #endif PHP_PQ_TYPE("TSVECTORARRAY", 3643) #ifndef PHP_PQ_OID_GTSVECTORARRAY # define PHP_PQ_OID_GTSVECTORARRAY 3644 #endif PHP_PQ_TYPE("GTSVECTORARRAY", 3644) #ifndef PHP_PQ_OID_TSQUERYARRAY # define PHP_PQ_OID_TSQUERYARRAY 3645 #endif PHP_PQ_TYPE("TSQUERYARRAY", 3645) #ifndef PHP_PQ_OID_REGCONFIG # define PHP_PQ_OID_REGCONFIG 3734 #endif PHP_PQ_TYPE("REGCONFIG", 3734) #ifndef PHP_PQ_OID_REGCONFIGARRAY # define PHP_PQ_OID_REGCONFIGARRAY 3735 #endif PHP_PQ_TYPE("REGCONFIGARRAY", 3735) #ifndef PHP_PQ_OID_REGDICTIONARY # define PHP_PQ_OID_REGDICTIONARY 3769 #endif PHP_PQ_TYPE("REGDICTIONARY", 3769) #ifndef PHP_PQ_OID_REGDICTIONARYARRAY # define PHP_PQ_OID_REGDICTIONARYARRAY 3770 #endif PHP_PQ_TYPE("REGDICTIONARYARRAY", 3770) #ifndef PHP_PQ_OID_JSONB # define PHP_PQ_OID_JSONB 3802 #endif PHP_PQ_TYPE("JSONB", 3802) #ifndef PHP_PQ_OID_JSONBARRAY # define PHP_PQ_OID_JSONBARRAY 3807 #endif PHP_PQ_TYPE("JSONBARRAY", 3807) #ifndef PHP_PQ_OID_ANYRANGE # define PHP_PQ_OID_ANYRANGE 3831 #endif PHP_PQ_TYPE("ANYRANGE", 3831) #ifndef PHP_PQ_OID_EVENT_TRIGGER # define PHP_PQ_OID_EVENT_TRIGGER 3838 #endif PHP_PQ_TYPE("EVENT_TRIGGER", 3838) #ifndef PHP_PQ_OID_INT4RANGE # define PHP_PQ_OID_INT4RANGE 3904 #endif PHP_PQ_TYPE("INT4RANGE", 3904) #ifndef PHP_PQ_OID_INT4RANGEARRAY # define PHP_PQ_OID_INT4RANGEARRAY 3905 #endif PHP_PQ_TYPE("INT4RANGEARRAY", 3905) #ifndef PHP_PQ_OID_NUMRANGE # define PHP_PQ_OID_NUMRANGE 3906 #endif PHP_PQ_TYPE("NUMRANGE", 3906) #ifndef PHP_PQ_OID_NUMRANGEARRAY # define PHP_PQ_OID_NUMRANGEARRAY 3907 #endif PHP_PQ_TYPE("NUMRANGEARRAY", 3907) #ifndef PHP_PQ_OID_TSRANGE # define PHP_PQ_OID_TSRANGE 3908 #endif PHP_PQ_TYPE("TSRANGE", 3908) #ifndef PHP_PQ_OID_TSRANGEARRAY # define PHP_PQ_OID_TSRANGEARRAY 3909 #endif PHP_PQ_TYPE("TSRANGEARRAY", 3909) #ifndef PHP_PQ_OID_TSTZRANGE # define PHP_PQ_OID_TSTZRANGE 3910 #endif PHP_PQ_TYPE("TSTZRANGE", 3910) #ifndef PHP_PQ_OID_TSTZRANGEARRAY # define PHP_PQ_OID_TSTZRANGEARRAY 3911 #endif PHP_PQ_TYPE("TSTZRANGEARRAY", 3911) #ifndef PHP_PQ_OID_DATERANGE # define PHP_PQ_OID_DATERANGE 3912 #endif PHP_PQ_TYPE("DATERANGE", 3912) #ifndef PHP_PQ_OID_DATERANGEARRAY # define PHP_PQ_OID_DATERANGEARRAY 3913 #endif PHP_PQ_TYPE("DATERANGEARRAY", 3913) #ifndef PHP_PQ_OID_INT8RANGE # define PHP_PQ_OID_INT8RANGE 3926 #endif PHP_PQ_TYPE("INT8RANGE", 3926) #ifndef PHP_PQ_OID_INT8RANGEARRAY # define PHP_PQ_OID_INT8RANGEARRAY 3927 #endif PHP_PQ_TYPE("INT8RANGEARRAY", 3927) #ifndef PHP_PQ_OID_REGNAMESPACE # define PHP_PQ_OID_REGNAMESPACE 4089 #endif PHP_PQ_TYPE("REGNAMESPACE", 4089) #ifndef PHP_PQ_OID_REGNAMESPACEARRAY # define PHP_PQ_OID_REGNAMESPACEARRAY 4090 #endif PHP_PQ_TYPE("REGNAMESPACEARRAY", 4090) #ifndef PHP_PQ_OID_REGROLE # define PHP_PQ_OID_REGROLE 4096 #endif PHP_PQ_TYPE("REGROLE", 4096) #ifndef PHP_PQ_OID_REGROLEARRAY # define PHP_PQ_OID_REGROLEARRAY 4097 #endif PHP_PQ_TYPE("REGROLEARRAY", 4097) #ifndef PHP_PQ_TYPE_IS_ARRAY # define PHP_PQ_TYPE_IS_ARRAY(oid) ( \ 0 \ || ((oid) == 143) \ || ((oid) == 199) \ || ((oid) == 629) \ || ((oid) == 651) \ || ((oid) == 719) \ || ((oid) == 775) \ || ((oid) == 791) \ || ((oid) == 1000) \ || ((oid) == 1001) \ || ((oid) == 1002) \ || ((oid) == 1003) \ || ((oid) == 1005) \ || ((oid) == 1006) \ || ((oid) == 1007) \ || ((oid) == 1008) \ || ((oid) == 1009) \ || ((oid) == 1010) \ || ((oid) == 1011) \ || ((oid) == 1012) \ || ((oid) == 1013) \ || ((oid) == 1014) \ || ((oid) == 1015) \ || ((oid) == 1016) \ || ((oid) == 1017) \ || ((oid) == 1018) \ || ((oid) == 1019) \ || ((oid) == 1020) \ || ((oid) == 1021) \ || ((oid) == 1022) \ || ((oid) == 1027) \ || ((oid) == 1028) \ || ((oid) == 1034) \ || ((oid) == 1040) \ || ((oid) == 1041) \ || ((oid) == 1115) \ || ((oid) == 1182) \ || ((oid) == 1183) \ || ((oid) == 1185) \ || ((oid) == 1187) \ || ((oid) == 1231) \ || ((oid) == 1263) \ || ((oid) == 1270) \ || ((oid) == 1561) \ || ((oid) == 1563) \ || ((oid) == 2201) \ || ((oid) == 2207) \ || ((oid) == 2208) \ || ((oid) == 2209) \ || ((oid) == 2210) \ || ((oid) == 2211) \ || ((oid) == 2949) \ || ((oid) == 2951) \ || ((oid) == 3221) \ || ((oid) == 3643) \ || ((oid) == 3644) \ || ((oid) == 3645) \ || ((oid) == 3735) \ || ((oid) == 3770) \ || ((oid) == 3807) \ || ((oid) == 3905) \ || ((oid) == 3907) \ || ((oid) == 3909) \ || ((oid) == 3911) \ || ((oid) == 3913) \ || ((oid) == 3927) \ || ((oid) == 4090) \ || ((oid) == 4097) \ ) #endif #ifndef PHP_PQ_TYPE_OF_ARRAY # define PHP_PQ_TYPE_OF_ARRAY(oid) ( \ (oid) == 143 ? 142 : \ (oid) == 199 ? 114 : \ (oid) == 629 ? 628 : \ (oid) == 651 ? 650 : \ (oid) == 719 ? 718 : \ (oid) == 775 ? 774 : \ (oid) == 791 ? 790 : \ (oid) == 1000 ? 16 : \ (oid) == 1001 ? 17 : \ (oid) == 1002 ? 18 : \ (oid) == 1003 ? 19 : \ (oid) == 1005 ? 21 : \ (oid) == 1006 ? 22 : \ (oid) == 1007 ? 23 : \ (oid) == 1008 ? 24 : \ (oid) == 1009 ? 25 : \ (oid) == 1010 ? 27 : \ (oid) == 1011 ? 28 : \ (oid) == 1012 ? 29 : \ (oid) == 1013 ? 30 : \ (oid) == 1014 ? 1042 : \ (oid) == 1015 ? 1043 : \ (oid) == 1016 ? 20 : \ (oid) == 1017 ? 600 : \ (oid) == 1018 ? 601 : \ (oid) == 1019 ? 602 : \ (oid) == 1020 ? 603 : \ (oid) == 1021 ? 700 : \ (oid) == 1022 ? 701 : \ (oid) == 1027 ? 604 : \ (oid) == 1028 ? 26 : \ (oid) == 1034 ? 1033 : \ (oid) == 1040 ? 829 : \ (oid) == 1041 ? 869 : \ (oid) == 1115 ? 1114 : \ (oid) == 1182 ? 1082 : \ (oid) == 1183 ? 1083 : \ (oid) == 1185 ? 1184 : \ (oid) == 1187 ? 1186 : \ (oid) == 1231 ? 1700 : \ (oid) == 1263 ? 2275 : \ (oid) == 1270 ? 1266 : \ (oid) == 1561 ? 1560 : \ (oid) == 1563 ? 1562 : \ (oid) == 2201 ? 1790 : \ (oid) == 2207 ? 2202 : \ (oid) == 2208 ? 2203 : \ (oid) == 2209 ? 2204 : \ (oid) == 2210 ? 2205 : \ (oid) == 2211 ? 2206 : \ (oid) == 2949 ? 2970 : \ (oid) == 2951 ? 2950 : \ (oid) == 3221 ? 3220 : \ (oid) == 3643 ? 3614 : \ (oid) == 3644 ? 3642 : \ (oid) == 3645 ? 3615 : \ (oid) == 3735 ? 3734 : \ (oid) == 3770 ? 3769 : \ (oid) == 3807 ? 3802 : \ (oid) == 3905 ? 3904 : \ (oid) == 3907 ? 3906 : \ (oid) == 3909 ? 3908 : \ (oid) == 3911 ? 3910 : \ (oid) == 3913 ? 3912 : \ (oid) == 3927 ? 3926 : \ (oid) == 4090 ? 4089 : \ (oid) == 4097 ? 4096 : \ 0 \ ) #endif #ifndef PHP_PQ_DELIM_OF_ARRAY # define PHP_PQ_DELIM_OF_ARRAY(oid) ((char) ( \ (oid) == 1020 ? ';' : \ (oid) == 603 ? ';' : \ ',' \ )) #endif