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\
</lead>
<date>2013-05-03</date>
<version>
- <release>0.3.0</release>
- <api>0.3.0</api>
+ <release>0.4.0dev</release>
+ <api>0.4.0</api>
</version>
<stability>
<release>beta</release>
</stability>
<license>BSD, revised</license>
<notes><![CDATA[
-* Added parser for result arrays ('{{1,2},{3,4}}')
+* Added pq\ConverterInterface and pq\Connection::setConverter()
]]></notes>
<contents>
<dir name="/">
<file role="src" name="php_pq_module.c" />
<file role="src" name="php_pq_object.c" />
<file role="src" name="php_pq_object.h" />
+ <file role="src" name="php_pq_params.c" />
+ <file role="src" name="php_pq_params.h" />
<file role="src" name="php_pqres.c" />
<file role="src" name="php_pqres.h" />
<file role="src" name="php_pqstm.c" />
<file role="test" name="bound001.phpt" />
<file role="test" name="bound002.phpt" />
<file role="test" name="cancel001.phpt" />
+ <file role="test" name="conv001.phpt" />
<file role="test" name="copy001.phpt" />
<file role="test" name="encoding001.phpt" />
<file role="test" name="exceptions001.phpt" />
return 0;
}
-static int apply_to_oid(void *p, void *arg TSRMLS_DC)
-{
- Oid **types = arg;
- zval **ztype = p;
-
- if (Z_TYPE_PP(ztype) != IS_LONG) {
- convert_to_long_ex(ztype);
- }
-
- **types = Z_LVAL_PP(ztype);
- ++*types;
-
- if (*ztype != *(zval **)p) {
- zval_ptr_dtor(ztype);
- }
- return ZEND_HASH_APPLY_KEEP;
-}
-
-static int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
-{
- zval **zparam = p;
- unsigned j, *i = va_arg(argv, unsigned *);
- smart_str *s = va_arg(argv, smart_str *);
- char *tmp;
- size_t len;
- int tmp_len;
-
- if ((*i)++) {
- smart_str_appendc(s, ',');
- }
-
- switch (Z_TYPE_PP(zparam)) {
- case IS_NULL:
- smart_str_appends(s, "NULL");
- break;
-
- case IS_BOOL:
- smart_str_appends(s, Z_BVAL_PP(zparam) ? "t" : "f");
- break;
-
- case IS_LONG:
- smart_str_append_long(s, Z_LVAL_PP(zparam));
- break;
-
- case IS_DOUBLE:
- len = spprintf(&tmp, 0, "%F", Z_DVAL_PP(zparam));
- smart_str_appendl(s, tmp, len);
- efree(tmp);
- break;
-
- case IS_ARRAY:
- j = 0;
- smart_str_appendc(s, '{');
- zend_hash_apply_with_arguments(Z_ARRVAL_PP(zparam) TSRMLS_CC, apply_to_param_from_array, 2, &j, s);
- smart_str_appendc(s, '}');
- break;
-
- default:
- {
- SEPARATE_ZVAL(zparam);
- if (Z_TYPE_PP(zparam) != IS_STRING) {
- convert_to_string(*zparam);
- }
-
- tmp = php_addslashes(Z_STRVAL_PP(zparam), Z_STRLEN_PP(zparam), &tmp_len, 0 TSRMLS_CC);
- smart_str_appendc(s, '"');
- smart_str_appendl(s, tmp, tmp_len);
- smart_str_appendc(s, '"');
-
- if (*zparam != *((zval **) p)) {
- zval_ptr_dtor(zparam);
- }
- break;
- }
- }
-
- ++(*i);
- return ZEND_HASH_APPLY_KEEP;
-}
-
-static void array_param_to_string(HashTable *ht, char **str, int *len TSRMLS_DC)
-{
- smart_str s = {0};
- unsigned i = 0;
-
- smart_str_appendc(&s, '{');
- zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param_from_array, 2, &i, &s);
- smart_str_appendc(&s, '}');
-
- smart_str_0(&s);
- *str = s.c;
- *len = s.len;
-}
-
-static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
-{
- char ***params;
- HashTable *zdtor;
- zval **zparam = p;
-
- params = (char ***) va_arg(argv, char ***);
- zdtor = (HashTable *) va_arg(argv, HashTable *);
-
- switch (Z_TYPE_PP(zparam)) {
- case IS_NULL:
- **params = NULL;
- ++*params;
- return ZEND_HASH_APPLY_KEEP;
-
- case IS_BOOL:
- **params = Z_BVAL_PP(zparam) ? "t" : "f";
- ++*params;
- return ZEND_HASH_APPLY_KEEP;
-
- case IS_DOUBLE:
- SEPARATE_ZVAL(zparam);
- Z_TYPE_PP(zparam) = IS_STRING;
- Z_STRLEN_PP(zparam) = spprintf(&Z_STRVAL_PP(zparam), 0, "%F", Z_DVAL_PP((zval **)p));
- break;
-
- case IS_ARRAY:
- {
- zval *tmp;
- MAKE_STD_ZVAL(tmp);
- Z_TYPE_P(tmp) = IS_STRING;
- array_param_to_string(Z_ARRVAL_PP(zparam), &Z_STRVAL_P(tmp), &Z_STRLEN_P(tmp) TSRMLS_CC);
- zparam = &tmp;
- break;
- }
-
- default:
- convert_to_string_ex(zparam);
- break;
- }
-
- **params = Z_STRVAL_PP(zparam);
- ++*params;
-
- if (*zparam != *(zval **)p) {
- zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
- }
- return ZEND_HASH_APPLY_KEEP;
-}
-
-int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC)
-{
- int count = zend_hash_num_elements(ht);
-
- *types = NULL;
-
- if (count) {
- Oid *tmp;
-
- /* +1 for when less types than params are specified */
- *types = tmp = ecalloc(count + 1, sizeof(**types));
- zend_hash_apply_with_argument(ht, apply_to_oid, &tmp TSRMLS_CC);
- }
-
- return count;
-}
-
-int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC)
-{
- int count = zend_hash_num_elements(ht);
-
- *params = NULL;
-
- if (count) {
- char **tmp;
-
- *params = tmp = ecalloc(count, sizeof(char *));
- zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param, 2, &tmp, zdtor);
- }
-
- return count;
-}
-
-/*
-Oid *php_pq_ntypes_to_array(zend_bool fill, int argc, ...)
-{
- int i;
- Oid *oids = ecalloc(argc + 1, sizeof(*oids));
- va_list argv;
-
- va_start(argv, argc);
- for (i = 0; i < argc; ++i) {
- if (!fill || !i) {
- oids[i] = va_arg(argv, Oid);
- } else {
- oids[i] = oids[0];
- }
- }
- va_end(argv);
-
- return oids;
-}
-*/
-
zend_class_entry *php_pqdt_class_entry;
ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_to_string, 0, 0, 0)
return zv;
}
+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, 1)
+ ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_to_string, 0, 0, 1)
+ ZEND_ARG_INFO(0, data)
+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", "ConverterInterface", php_pqconv_methods);
+ php_pqconv_class_entry = zend_register_internal_interface(&ce TSRMLS_CC);
+
+ 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(), "DateTime" TSRMLS_CC);
#define PHP_PQerrorMessage(c) rtrim(PQerrorMessage((c)))
#define PHP_PQresultErrorMessage(r) rtrim(PQresultErrorMessage((r)))
-int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC);
-int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC);
-
zend_class_entry *php_pqdt_class_entry;
zval *php_pqdt_from_string(char *datetime_str, size_t datetime_len, char *fmt, zval *zv TSRMLS_DC);
+zend_class_entry *php_pqconv_class_entry;
+
HashTable *php_pq_parse_array(const char *val_str, size_t val_len, Oid typ TSRMLS_DC);
zval *php_pq_typed_zval(char *val_str, size_t val_len, Oid typ TSRMLS_DC);
return php_persistent_handle_provide(ZEND_STRL("pq\\Connection"), php_pqconn_get_resource_factory_ops(), NULL, NULL TSRMLS_CC);
}
+#define PHP_MSHUT_CALL(i) do { \
+ if (SUCCESS != PHP_MSHUTDOWN(i)(type, module_number TSRMLS_CC)) { \
+ return FAILURE; \
+ } \
+} while(0)
+
static PHP_MSHUTDOWN_FUNCTION(pq)
{
php_persistent_handle_cleanup(ZEND_STRL("pq\\Connection"), NULL, 0 TSRMLS_CC);
+
+ PHP_MSHUT_CALL(pqlob);
+ PHP_MSHUT_CALL(pqcopy);
+ 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;
}
{
php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
php_pq_object_prophandler_t *handler;
- zval *return_value;
+ zval *return_value = NULL;
if (!obj->intern) {
zend_error(E_WARNING, "%s not initialized", ancestor(obj->zo.ce)->name);
handler->read(object, obj, return_value TSRMLS_CC);
} else {
zend_error(E_ERROR, "Cannot access %s properties by reference or array key/index", ancestor(obj->zo.ce)->name);
- return_value = NULL;
}
} else {
return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | 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 <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <php.h>
+#include <ext/standard/php_string.h>
+#include <ext/standard/php_smart_str.h>
+
+#include <Zend/zend_interfaces.h>
+
+#include <libpq-fe.h>
+
+#include "php_pq.h"
+#include "php_pq_params.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, NULL, sizeof(zval *));
+}
+
+static int apply_to_oid(void *p, void *arg TSRMLS_DC)
+{
+ Oid **types = arg;
+ zval **ztype = p;
+
+ if (Z_TYPE_PP(ztype) != IS_LONG) {
+ convert_to_long_ex(ztype);
+ }
+
+ **types = Z_LVAL_PP(ztype);
+ ++*types;
+
+ if (*ztype != *(zval **)p) {
+ zval_ptr_dtor(ztype);
+ }
+ 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;
+ TSRMLS_DF(p);
+
+ 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 TSRMLS_CC);
+ }
+ 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 int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
+{
+ zval **zparam = p;
+ unsigned j, *i = va_arg(argv, unsigned *);
+ smart_str *s = va_arg(argv, smart_str *);
+ zval **zconv = va_arg(argv, zval **);
+ char *tmp;
+ size_t len;
+ int tmp_len;
+
+ if ((*i)++) {
+ smart_str_appendc(s, ',');
+ }
+
+ if (zconv) {
+ zval *rv = NULL;
+
+ zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zparam);
+ convert_to_string(rv);
+ smart_str_appendl(s, Z_STRVAL_P(rv), Z_STRLEN_P(rv));
+ zval_ptr_dtor(&rv);
+ } else {
+ switch (Z_TYPE_PP(zparam)) {
+ case IS_NULL:
+ smart_str_appends(s, "NULL");
+ break;
+
+ case IS_BOOL:
+ smart_str_appends(s, Z_BVAL_PP(zparam) ? "t" : "f");
+ break;
+
+ case IS_LONG:
+ smart_str_append_long(s, Z_LVAL_PP(zparam));
+ break;
+
+ case IS_DOUBLE:
+ len = spprintf(&tmp, 0, "%F", Z_DVAL_PP(zparam));
+ smart_str_appendl(s, tmp, len);
+ efree(tmp);
+ break;
+
+ case IS_ARRAY:
+ j = 0;
+ smart_str_appendc(s, '{');
+ zend_hash_apply_with_arguments(Z_ARRVAL_PP(zparam) TSRMLS_CC, apply_to_param_from_array, 2, &j, s, zconv);
+ smart_str_appendc(s, '}');
+ break;
+
+ default:
+ SEPARATE_ZVAL(zparam);
+ if (Z_TYPE_PP(zparam) != IS_STRING) {
+ convert_to_string(*zparam);
+ }
+
+ tmp = php_addslashes(Z_STRVAL_PP(zparam), Z_STRLEN_PP(zparam), &tmp_len, 0 TSRMLS_CC);
+ smart_str_appendc(s, '"');
+ smart_str_appendl(s, tmp, tmp_len);
+ smart_str_appendc(s, '"');
+
+ if (*zparam != *((zval **) p)) {
+ zval_ptr_dtor(zparam);
+ }
+ break;
+ }
+ }
+ ++(*i);
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+static void array_param_to_string(zval **zconv, HashTable *ht, char **str, int *len TSRMLS_DC)
+{
+ smart_str s = {0};
+ unsigned i = 0;
+
+ smart_str_appendc(&s, '{');
+ zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param_from_array, 3, &i, &s, zconv);
+ smart_str_appendc(&s, '}');
+
+ smart_str_0(&s);
+ *str = s.c;
+ *len = s.len;
+}
+
+static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval **zp)
+{
+ zval **zconv = NULL;
+ Oid type = p->type.count > index ? p->type.oids[index] : 0;
+ TSRMLS_DF(p);
+
+ if (type && SUCCESS == zend_hash_index_find(&p->type.conv, type, (void *) &zconv)) {
+ zval *rv = NULL;
+
+ zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zp);
+ convert_to_string(rv);
+ p->param.strings[index] = Z_STRVAL_P(rv);
+ zend_hash_next_index_insert(&p->param.dtor, (void *) &rv, sizeof(zval *), NULL);
+ } else {
+ zval **zpp = zp;
+
+ switch (Z_TYPE_PP(zp)) {
+ case IS_NULL:
+ p->param.strings[index] = NULL;
+ return;
+
+ case IS_BOOL:
+ p->param.strings[index] = Z_BVAL_PP(zp) ? "t" : "f";
+ return;
+
+ case IS_DOUBLE:
+ SEPARATE_ZVAL(zp);
+ Z_TYPE_PP(zp) = IS_STRING;
+ Z_STRLEN_PP(zp) = spprintf(&Z_STRVAL_PP(zp), 0, "%F", Z_DVAL_PP((zval **)p));
+ break;
+
+ case IS_ARRAY:
+ {
+
+#if HAVE_PHP_PQ_TYPE_H
+# undef PHP_PQ_TYPE
+# include "php_pq_type.h"
+#else
+# define PHP_PQ_TYPE_OF_ARRAY(oid) 0
+#endif
+
+ zval *tmp;
+ MAKE_STD_ZVAL(tmp);
+ Z_TYPE_P(tmp) = IS_STRING;
+ zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &zconv);
+ array_param_to_string(zconv, Z_ARRVAL_PP(zp), &Z_STRVAL_P(tmp), &Z_STRLEN_P(tmp) TSRMLS_CC);
+ zp = &tmp;
+ break;
+ }
+
+ default:
+ convert_to_string_ex(zp);
+ break;
+ }
+
+ p->param.strings[index] = Z_STRVAL_PP(zp);
+
+ if (*zp != *zpp) {
+ zend_hash_next_index_insert(&p->param.dtor, zp, sizeof(zval *), NULL);
+ }
+ }
+}
+
+static int apply_to_params(void *zp TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
+{
+ php_pq_params_t *p = (php_pq_params_t *) va_arg(argv, php_pq_params_t *);
+ unsigned *index = (unsigned *) va_arg(argv, unsigned *);
+
+ php_pq_params_set_param(p, (*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, ¶m);
+ 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;
+ TSRMLS_DF(p);
+
+ if (p->param.strings) {
+ efree(p->param.strings);
+ p->param.strings = NULL;
+ }
+ zend_hash_clean(&p->param.dtor);
+ if (p->param.count) {
+ unsigned index = 0;
+ p->param.strings = ecalloc(p->param.count, sizeof(*p->param.strings));
+ zend_hash_apply_with_arguments(params TSRMLS_CC, apply_to_params, 2, p, &index);
+ }
+ 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 TSRMLS_DC)
+{
+ php_pq_params_t *p = ecalloc(1, sizeof(*p));
+
+ TSRMLS_CF(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
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | 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 <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+#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;
+#ifdef ZTS
+ void ***ts;
+#endif
+} php_pq_params_t;
+
+php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params TSRMLS_DC);
+void php_pq_params_free(php_pq_params_t **p);
+unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params);
+unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids);
+unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type);
+unsigned php_pq_params_add_param(php_pq_params_t *p, zval *param);
+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
+ */
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqcancel)
+{
+ zend_hash_destroy(&php_pqcancel_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqcancel)
{
zend_class_entry ce = {0};
zend_object_value php_pqcancel_create_object_ex(zend_class_entry *ce, php_pqcancel_t *intern, php_pqcancel_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqcancel);
+PHP_MSHUTDOWN_FUNCTION(pqcancel);
#endif
php_resource_factory_dtor(&obj->intern->factory);
php_pq_callback_dtor(&obj->intern->onevent);
zend_hash_destroy(&obj->intern->listeners);
+ zend_hash_destroy(&obj->intern->converters);
zend_hash_destroy(&obj->intern->eventhandlers);
efree(obj->intern);
obj->intern = NULL;
obj->intern = ecalloc(1, sizeof(*obj->intern));
zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
+ zend_hash_init(&obj->intern->converters, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_init(&obj->intern->eventhandlers, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
if (flags & PHP_PQCONN_PERSISTENT) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
} else {
PGresult *res;
- int count;
- Oid *types = NULL;
- char **params = NULL;
- HashTable zdtor;
+ php_pq_params_t *params;
- ZEND_INIT_SYMTABLE(&zdtor);
- count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC);
-
- if (ztypes) {
- php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
- }
-
- res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
-
- zend_hash_destroy(&zdtor);
- if (types) {
- efree(types);
- }
- if (params) {
- efree(params);
- }
+ params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams) TSRMLS_CC);
+ res = PQexecParams(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 TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
if (!obj->intern) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
} else {
- int count;
- Oid *types = NULL;
- char **params = NULL;
- HashTable zdtor;
+ int rc;
+ php_pq_params_t *params;
- ZEND_INIT_SYMTABLE(&zdtor);
- count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC);
-
- if (ztypes) {
- php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
- }
+ params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams) TSRMLS_CC);
+ 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 (!PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) {
+ if (!rc) {
throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
} else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
}
php_pqconn_notify_listeners(obj TSRMLS_CC);
}
-
- zend_hash_destroy(&zdtor);
- if (types) {
- efree(types);
- }
- if (params) {
- efree(params);
- }
}
}
zend_restore_error_handling(&zeh TSRMLS_CC);
}
-STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
+STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC)
{
- Oid *types = NULL;
- int count = 0;
PGresult *res;
STATUS rv;
obj = zend_object_store_get_object(object TSRMLS_CC);
}
- if (typest) {
- count = zend_hash_num_elements(typest);
- php_pq_types_to_array(typest, &types TSRMLS_CC);
- }
-
- res = PQprepare(obj->intern->conn, name, query, count, types);
-
- if (types) {
- efree(types);
- }
+ res = PQprepare(obj->intern->conn, name, query, params->type.count, params->type.oids);
if (!res) {
rv = FAILURE;
if (!obj->intern) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
- } else if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
- php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
+ } else {
+ php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC);
- php_pq_object_addref(obj TSRMLS_CC);
- stm->conn = obj;
- stm->name = estrdup(name_str);
- ZEND_INIT_SYMTABLE(&stm->bound);
+ if (SUCCESS != php_pqconn_prepare(getThis(), obj, name_str, query_str, params TSRMLS_CC)) {
+ php_pq_params_free(¶ms);
+ } else {
+ php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
- return_value->type = IS_OBJECT;
- return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
+ php_pq_object_addref(obj TSRMLS_CC);
+ stm->conn = obj;
+ stm->name = estrdup(name_str);
+ stm->params = params;
+ ZEND_INIT_SYMTABLE(&stm->bound);
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
+ }
}
}
}
-STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
+STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC)
{
STATUS rv;
- int count;
- Oid *types = NULL;
if (!obj) {
obj = zend_object_store_get_object(object TSRMLS_CC);
}
- if (typest) {
- count = php_pq_types_to_array(typest, &types TSRMLS_CC);
- }
-
- if (!PQsendPrepare(obj->intern->conn, name, query, count, types)) {
+ if (!PQsendPrepare(obj->intern->conn, name, query, params->type.count, params->type.oids)) {
rv = FAILURE;
throw_exce(EX_IO TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
} else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
php_pqconn_notify_listeners(obj TSRMLS_CC);
}
- if (types) {
- efree(types);
- }
-
return rv;
}
if (!obj->intern) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
- } else if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
- php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
+ } else {
+ php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC);
- php_pq_object_addref(obj TSRMLS_CC);
- stm->conn = obj;
- stm->name = estrdup(name_str);
- ZEND_INIT_SYMTABLE(&stm->bound);
+ if (SUCCESS != php_pqconn_prepare_async(getThis(), obj, name_str, query_str, params TSRMLS_CC)) {
+ php_pq_params_free(¶ms);
+ } else {
+ php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
- return_value->type = IS_OBJECT;
- return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
+ php_pq_object_addref(obj TSRMLS_CC);
+ stm->conn = obj;
+ stm->name = estrdup(name_str);
+ stm->params = params;
+ ZEND_INIT_SYMTABLE(&stm->bound);
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
+ }
}
}
}
}
}
+static int apply_set_converter(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
+{
+ zval *tmp, **zoid = p, **zcnv = va_arg(argv, zval **);
+ HashTable *converters = va_arg(argv, HashTable *);
+
+ tmp = *zoid;
+ convert_to_long_ex(&tmp);
+ Z_ADDREF_PP(zcnv);
+ zend_hash_index_update(converters, Z_LVAL_P(tmp), zcnv, sizeof(zval *), NULL);
+ if (tmp != *zoid) {
+ zval_ptr_dtor(&tmp);
+ }
+
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_set_converter, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, converter, pq\\ConverterInterface, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, setConverter) {
+ STATUS rv;
+ zend_error_handling zeh;
+ zval *zcnv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zcnv, php_pqconv_class_entry);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
+ } else {
+ zval *tmp, *zoids = NULL;
+
+ zend_call_method_with_0_params(&zcnv, NULL, NULL, "converttypes", &zoids);
+ tmp = zoids;
+ convert_to_array_ex(&zoids);
+ zend_hash_apply_with_arguments(Z_ARRVAL_P(zoids) TSRMLS_CC, apply_set_converter, 2, &zcnv, &obj->intern->converters);
+ if (tmp != zoids) {
+ 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|ZEND_ACC_CTOR)
PHP_ME(pqconn, reset, ai_pqconn_reset, 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, on, ai_pqconn_on, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, setConverter, ai_pqconn_set_converter, ZEND_ACC_PUBLIC)
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqconn)
+{
+ zend_hash_destroy(&php_pqconn_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqconn)
{
zend_class_entry ce = {0};
#include <ext/raphf/php_raphf.h>
#include "php_pq_callback.h"
+#include "php_pq_params.h"
typedef struct php_pqconn {
PGconn *conn;
int (*poller)(PGconn *);
php_resource_factory_t factory;
HashTable listeners;
+ HashTable converters;
HashTable eventhandlers;
php_pq_callback_t onevent;
unsigned unbuffered:1;
zend_class_entry *php_pqconn_class_entry;
zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern, php_pqconn_object_t **ptr TSRMLS_DC);
void php_pqconn_notify_listeners(php_pqconn_object_t *obj TSRMLS_DC);
-STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC);
-STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC);
+STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC);
+STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC);
STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC);
STATUS php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC);
PHP_MINIT_FUNCTION(pqconn);
+PHP_MSHUTDOWN_FUNCTION(pqconn);
#endif
HashTable *evhs;
TSRMLS_DF(data);
- php_pqres_init_instance_data(event->result, &obj TSRMLS_CC);
+ php_pqres_init_instance_data(event->result, data->obj, &obj TSRMLS_CC);
/* event listener */
if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) {
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqcopy)
+{
+ zend_hash_destroy(&php_pqcopy_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqcopy)
{
zend_class_entry ce = {0};
zend_object_value php_pqcopy_create_object_ex(zend_class_entry *ce, php_pqcopy_t *intern, php_pqcopy_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqcopy);
+PHP_MSHUTDOWN_FUNCTION(pqcopy);
#endif
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqlob)
+{
+ zend_hash_destroy(&php_pqlob_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqlob)
{
zend_class_entry ce = {0};
zend_object_value php_pqlob_create_object_ex(zend_class_entry *ce, php_pqlob_t *intern, php_pqlob_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqlob);
+PHP_MSHUTDOWN_FUNCTION(pqlob);
#endif
{
zval *data = NULL;
int c, cols;
+ php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event);
if (data_ptr) {
data = *data_ptr;
break;
}
} else {
- zval *zv = php_pq_typed_zval(PQgetvalue(res, row, c), PQgetlength(res, row, c), PQftype(res, c) TSRMLS_CC);
+ zval *zv, **zconv;
+
+ if (res_obj && (SUCCESS == zend_hash_index_find(&res_obj->intern->converters, PQftype(res, c), (void *) &zconv))) {
+ zval *tmp = NULL;
+
+ MAKE_STD_ZVAL(zv);
+ ZVAL_STRINGL(zv, PQgetvalue(res, row, c), PQgetlength(res, row, c), 1);
+ zend_call_method_with_1_params(zconv, NULL, NULL, "convertfromstring", &tmp, zv);
+
+ if (tmp) {
+ zval_ptr_dtor(&zv);
+ zv = tmp;
+ }
+ } else {
+ zv = php_pq_typed_zval(PQgetvalue(res, row, c), PQgetlength(res, row, c), PQftype(res, c) TSRMLS_CC);
+ }
switch (fetch_type) {
case PHP_PQRES_FETCH_OBJECT:
}
}
-void php_pqres_init_instance_data(PGresult *res, php_pqres_object_t **ptr TSRMLS_DC)
+void php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *conn_obj, php_pqres_object_t **ptr TSRMLS_DC)
{
php_pqres_object_t *obj;
php_pqres_t *r = ecalloc(1, sizeof(*r));
r->res = res;
- ZEND_INIT_SYMTABLE(&r->bound);
+ zend_hash_init(&r->bound, 0, 0, ZVAL_PTR_DTOR, 0);
+ zend_hash_init(&r->converters, 0, 0, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(&r->converters, &conn_obj->intern->converters, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
php_pqres_create_object_ex(php_pqres_class_entry, r, &obj TSRMLS_CC);
PQresultSetInstanceData(res, php_pqconn_event, obj);
}
zend_hash_destroy(&obj->intern->bound);
+ zend_hash_destroy(&obj->intern->converters);
efree(obj->intern);
obj->intern = NULL;
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqres)
+{
+ zend_hash_destroy(&php_pqres_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqres)
{
zend_class_entry ce = {0};
#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,
PGresult *res;
php_pqres_iterator_t *iter;
HashTable bound;
+ HashTable converters;
} php_pqres_t;
typedef struct php_pqres_object {
} php_pqres_object_t;
STATUS php_pqres_success(PGresult *res TSRMLS_DC);
-void php_pqres_init_instance_data(PGresult *res, php_pqres_object_t **ptr TSRMLS_DC);
+void php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *obj, php_pqres_object_t **ptr TSRMLS_DC);
zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval **data_ptr TSRMLS_DC);
#include "php_pq_object.h"
zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern, php_pqres_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqres);
+PHP_MSHUTDOWN_FUNCTION(pqres);
#endif
php_pq_object_delref(obj->intern->conn TSRMLS_CC);
efree(obj->intern->name);
zend_hash_destroy(&obj->intern->bound);
+ if (obj->intern->params) {
+ php_pq_params_free(&obj->intern->params);
+ }
efree(obj->intern);
obj->intern = NULL;
}
if (!conn_obj->intern) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "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 TSRMLS_CC);
+
if (async) {
- rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
+ rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, params TSRMLS_CC);
} else {
- rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
+ rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, params TSRMLS_CC);
}
if (SUCCESS == rv) {
php_pq_object_addref(conn_obj TSRMLS_CC);
stm->conn = conn_obj;
stm->name = estrdup(name_str);
+ stm->params = params;
ZEND_INIT_SYMTABLE(&stm->bound);
obj->intern = stm;
}
if (!obj->intern) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
} else {
- int count = 0;
- char **params = NULL;
- HashTable zdtor;
PGresult *res;
- ZEND_INIT_SYMTABLE(&zdtor);
-
- if (zparams) {
- count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC);
- } else {
- count = php_pq_params_to_array(&obj->intern->bound, ¶ms, &zdtor TSRMLS_CC);
- }
-
- res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0);
-
- if (params) {
- efree(params);
- }
- zend_hash_destroy(&zdtor);
+ php_pq_params_set_params(obj->intern->params, zparams ? Z_ARRVAL_P(zparams) : &obj->intern->bound);
+ res = PQexecPrepared(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 TSRMLS_CC, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
if (!obj->intern) {
throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
} else {
- int count;
- char **params = NULL;
- HashTable zdtor;
+ int rc;
- if (zparams) {
- ZEND_INIT_SYMTABLE(&zdtor);
- count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC);
- }
+ 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 (!PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0)) {
+ if (!rc) {
throw_exce(EX_IO TSRMLS_CC, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
} else if (obj->intern->conn->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn->intern->conn)) {
throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
obj->intern->conn->intern->poller = PQconsumeInput;
}
- if (params) {
- efree(params);
- }
- if (zparams) {
- zend_hash_destroy(&zdtor);
- }
-
php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
}
}
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqstm)
+{
+ zend_hash_destroy(&php_pqstm_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqstm)
{
zend_class_entry ce = {0};
php_pqconn_object_t *conn;
char *name;
HashTable bound;
+ php_pq_params_t *params;
} php_pqstm_t;
typedef struct php_pqstm_object {
zend_object_value php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern, php_pqstm_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqstm);
+PHP_MSHUTDOWN_FUNCTION(pqstm);
#endif
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqtxn)
+{
+ zend_hash_destroy(&php_pqtxn_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqtxn)
{
zend_class_entry ce = {0};
zend_object_value php_pqtxn_create_object_ex(zend_class_entry *ce, php_pqtxn_t *intern, php_pqtxn_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqtxn);
+PHP_MSHUTDOWN_FUNCTION(pqtxn);
#endif
# define PHP_PQ_OID_TEXT 25
#endif
+static int apply_nsp(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
+{
+ zval **zp = p;
+ 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 TSRMLS_CC, 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();
if (!nsp || !zend_hash_num_elements(nsp)) {
res = PQexec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')");
} else {
- int i, count;
- Oid *oids;
- char **params = NULL;
- HashTable zdtor;
smart_str str = {0};
+ php_pq_params_t *params = php_pq_params_init(&obj->intern->conn->intern->converters, NULL, NULL TSRMLS_CC);
smart_str_appends(&str, PHP_PQ_TYPES_QUERY " and nspname in(");
- zend_hash_init(&zdtor, 0, NULL, ZVAL_PTR_DTOR, 0);
- count = php_pq_params_to_array(nsp, ¶ms, &zdtor TSRMLS_CC);
- oids = ecalloc(count + 1, sizeof(*oids));
- for (i = 0; i < count; ++i) {
- oids[i] = PHP_PQ_OID_TEXT;
- if (i) {
- smart_str_appendc(&str, ',');
- }
- smart_str_appendc(&str, '$');
- smart_str_append_unsigned(&str, i+1);
- }
+ zend_hash_apply_with_arguments(nsp TSRMLS_CC, apply_nsp, 2, params, &str);
smart_str_appendc(&str, ')');
smart_str_0(&str);
- res = PQexecParams(obj->intern->conn->intern->conn, str.c, count, oids, (const char *const*) params, NULL, NULL, 0);
+ res = PQexecParams(obj->intern->conn->intern->conn, str.c, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
smart_str_free(&str);
- efree(oids);
- efree(params);
- zend_hash_destroy(&zdtor);
+ php_pq_params_free(¶ms);
}
if (!res) {
Z_ADDREF_P(row);
zend_hash_index_update(&obj->intern->types, oid, (void *) &row, sizeof(zval *), NULL);
- zend_hash_add(&obj->intern->types, name, strlen(name) + 1, (void *) &row, sizeof(zval *), NULL);
+ zend_hash_update(&obj->intern->types, name, strlen(name) + 1, (void *) &row, sizeof(zval *), NULL);
}
}
{0}
};
+PHP_MSHUTDOWN_FUNCTION(pqtypes)
+{
+ zend_hash_destroy(&php_pqtypes_object_prophandlers);
+ return SUCCESS;
+}
+
PHP_MINIT_FUNCTION(pqtypes)
{
zend_class_entry ce = {0};
zend_object_value php_pqtypes_create_object_ex(zend_class_entry *ce, php_pqtypes_t *intern, php_pqtypes_object_t **ptr TSRMLS_DC);
PHP_MINIT_FUNCTION(pqtypes);
+PHP_MSHUTDOWN_FUNCTION(pqtypes);
#endif
$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 (7) {
["status"]=>
int(7)
--- /dev/null
+--TEST--
+converter
+--SKIPIF--
+<?php
+include "_skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+include "_setup.inc";
+
+abstract class Converter implements pq\ConverterInterface
+{
+ protected $types;
+
+ function __construct(\pq\Types $types) {
+ $this->types = $types;
+ }
+}
+
+class HStoreConverter extends Converter
+{
+ function convertTypes() {
+ return [ $this->types["hstore"]->oid ];
+ }
+
+ function convertFromString($string) {
+ return eval("return [$string];");
+ }
+
+ function convertToString($data) {
+ $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) {
+ return array_map("intval", explode(" ", $string));
+ }
+
+ function convertToString($data) {
+ return implode(" ", $data);
+ }
+}
+
+class JSONConverter extends Converter
+{
+ function convertTypes() {
+ return [ $this->types["json"]->oid ];
+ }
+
+ function convertFromString($string) {
+ return json_decode($string);
+ }
+
+ function convertToString($data) {
+ return json_encode($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));
+$c->setConverter(new JSONConverter($t));
+
+$r = $c->execParams("SELECT \$1 as hs, \$2 as iv, \$3 as oids, \$4 as js",
+ 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" => "äüö"
+ )
+ ),
+ array(
+ $t["hstore"]->oid,
+ $t["int2vector"]->oid,
+ $t["oidvector"]->oid,
+ $t["json"]->oid
+ )
+);
+
+var_dump($r->fetchAll());
+
+?>
+Done
+--EXPECTF--
+Test
+array(1) {
+ [0]=>
+ array(4) {
+ [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]=>
+ object(stdClass)#%d (3) {
+ ["int"]=>
+ int(123)
+ ["obj"]=>
+ object(stdClass)#%d (3) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ }
+ ["str"]=>
+ string(6) "äüö"
+ }
+ }
+}
+Done
$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);
}
--EXPECT--
Test
bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
DONE
include "_setup.inc";
$c = new pq\Connection(PQ_DSN);
-$t = new pq\Types($c);
+$t = new pq\Types($c, array("pg_catalog", "public"));
var_dump($t->connection === $c);
var_dump(isset($t["int4"]), empty($t["int4"]));
var_dump(isset($t["whatthahell"]), empty($t["whatthahell"]));