2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
18 #include <ext/standard/php_smart_str.h>
21 #include "php_pq_misc.h"
22 #include "php_pq_object.h"
23 #include "php_pqexc.h"
24 #include "php_pqres.h"
25 #include "php_pqtypes.h"
27 zend_class_entry
*php_pqtypes_class_entry
;
28 static zend_object_handlers php_pqtypes_object_handlers
;
29 static HashTable php_pqtypes_object_prophandlers
;
31 static void php_pqtypes_object_free(void *o TSRMLS_DC
)
33 php_pqtypes_object_t
*obj
= o
;
35 fprintf(stderr
, "FREE types(#%d) %p (conn(#%d): %p)\n", obj
->zv
.handle
, obj
, obj
->intern
->conn
->zv
.handle
, obj
->intern
->conn
);
38 zend_hash_destroy(&obj
->intern
->types
);
39 php_pq_object_delref(obj
->intern
->conn TSRMLS_CC
);
43 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
47 zend_object_value
php_pqtypes_create_object_ex(zend_class_entry
*ce
, php_pqtypes_t
*intern
, php_pqtypes_object_t
**ptr TSRMLS_DC
)
49 php_pqtypes_object_t
*o
;
51 o
= ecalloc(1, sizeof(*o
));
52 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
53 object_properties_init((zend_object
*) o
, ce
);
54 o
->prophandler
= &php_pqtypes_object_prophandlers
;
64 o
->zv
.handle
= zend_objects_store_put((zend_object
*) o
, NULL
, php_pqtypes_object_free
, NULL TSRMLS_CC
);
65 o
->zv
.handlers
= &php_pqtypes_object_handlers
;
70 static zend_object_value
php_pqtypes_create_object(zend_class_entry
*class_type TSRMLS_DC
)
72 return php_pqtypes_create_object_ex(class_type
, NULL
, NULL TSRMLS_CC
);
75 static void php_pqtypes_object_read_connection(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
77 php_pqtypes_object_t
*obj
= o
;
79 php_pq_object_to_zval(obj
->intern
->conn
, &return_value TSRMLS_CC
);
82 static int has_dimension(HashTable
*ht
, zval
*member
, char **key_str
, int *key_len
, ulong
*index TSRMLS_DC
)
87 switch (Z_TYPE_P(member
)) {
89 convert_to_string_ex(&tmp
);
92 if (!is_numeric_string(Z_STRVAL_P(tmp
), Z_STRLEN_P(tmp
), &lval
, NULL
, 0)) {
93 int exists
= zend_hash_exists(ht
, Z_STRVAL_P(tmp
), Z_STRLEN_P(tmp
) + 1);
96 *key_str
= estrndup(Z_STRVAL_P(tmp
), Z_STRLEN_P(tmp
));
98 *key_len
= Z_STRLEN_P(tmp
) + 1;
109 lval
= Z_LVAL_P(member
);
119 return zend_hash_index_exists(ht
, lval
);
122 static int php_pqtypes_object_has_dimension(zval
*object
, zval
*member
, int check_empty TSRMLS_DC
)
124 php_pqtypes_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
125 char *key_str
= NULL
;
130 if (has_dimension(&obj
->intern
->types
, member
, &key_str
, &key_len
, &index TSRMLS_CC
)) {
133 if (key_str
&& key_len
) {
134 if (SUCCESS
== zend_hash_find(&obj
->intern
->types
, key_str
, key_len
, (void *) &data
)) {
136 return Z_TYPE_PP(data
) != IS_NULL
;
140 if (SUCCESS
== zend_hash_index_find(&obj
->intern
->types
, index
, (void *) &data
)) {
141 return Z_TYPE_PP(data
) != IS_NULL
;
149 return has_dimension(&obj
->intern
->types
, member
, NULL
, NULL
, NULL TSRMLS_CC
);
155 static zval
*php_pqtypes_object_read_dimension(zval
*object
, zval
*member
, int type TSRMLS_DC
)
158 char *key_str
= NULL
;
160 php_pqtypes_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
162 if (has_dimension(&obj
->intern
->types
, member
, &key_str
, &key_len
, &index TSRMLS_CC
)) {
165 if (key_str
&& key_len
) {
166 if (SUCCESS
== zend_hash_find(&obj
->intern
->types
, key_str
, key_len
, (void *) &data
)) {
171 if (SUCCESS
== zend_hash_index_find(&obj
->intern
->types
, index
, (void *) &data
)) {
183 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
184 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
185 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
187 static PHP_METHOD(pqtypes
, __construct
) {
188 zend_error_handling zeh
;
189 zval
*zconn
, *znsp
= NULL
;
192 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
193 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
194 zend_restore_error_handling(&zeh TSRMLS_CC
);
197 php_pqconn_object_t
*conn_obj
= zend_object_store_get_object(zconn TSRMLS_CC
);
199 if (!conn_obj
->intern
) {
200 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
202 php_pqtypes_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
205 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
206 obj
->intern
->conn
= conn_obj
;
207 php_pq_object_addref(conn_obj TSRMLS_CC
);
208 zend_hash_init(&obj
->intern
->types
, 300, NULL
, ZVAL_PTR_DTOR
, 0);
211 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", &retval
, znsp
);
213 zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", &retval
);
217 zval_ptr_dtor(&retval
);
223 #define PHP_PQ_TYPES_QUERY \
224 "select t.oid, t.* " \
225 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
226 "where typisdefined " \
228 #ifndef PHP_PQ_OID_TEXT
229 # define PHP_PQ_OID_TEXT 25
232 static int apply_nsp(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
235 unsigned pcount
, tcount
;
236 php_pq_params_t
*params
= va_arg(argv
, php_pq_params_t
*);
237 smart_str
*str
= va_arg(argv
, smart_str
*);
239 tcount
= php_pq_params_add_type_oid(params
, PHP_PQ_OID_TEXT
);
240 pcount
= php_pq_params_add_param(params
, *zp
);
242 if (tcount
!= pcount
) {
243 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Param/Type count mismatch");
244 return ZEND_HASH_APPLY_STOP
;
247 smart_str_appendc(str
, ',');
249 smart_str_appendc(str
, '$');
250 smart_str_append_unsigned(str
, pcount
);
252 return ZEND_HASH_APPLY_KEEP
;
255 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh
, 0, 0, 0)
256 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
258 static PHP_METHOD(pqtypes
, refresh
) {
259 HashTable
*nsp
= NULL
;
260 zend_error_handling zeh
;
263 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
264 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|H/!", &nsp
);
265 zend_restore_error_handling(&zeh TSRMLS_CC
);
268 php_pqtypes_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
271 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Types not initialized");
275 if (!nsp
|| !zend_hash_num_elements(nsp
)) {
276 res
= PQexec(obj
->intern
->conn
->intern
->conn
, PHP_PQ_TYPES_QUERY
" and nspname in ('public', 'pg_catalog')");
279 php_pq_params_t
*params
= php_pq_params_init(&obj
->intern
->conn
->intern
->converters
, NULL
, NULL TSRMLS_CC
);
281 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
282 zend_hash_apply_with_arguments(nsp TSRMLS_CC
, apply_nsp
, 2, params
, &str
);
283 smart_str_appendc(&str
, ')');
286 res
= PQexecParams(obj
->intern
->conn
->intern
->conn
, str
.c
, params
->param
.count
, params
->type
.oids
, (const char *const*) params
->param
.strings
, NULL
, NULL
, 0);
288 smart_str_free(&str
);
289 php_pq_params_free(¶ms
);
293 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
295 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
298 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
299 zval
*row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, NULL TSRMLS_CC
);
300 long oid
= atol(PQgetvalue(res
, r
, 0 ));
301 char *name
= PQgetvalue(res
, r
, 1);
305 zend_hash_index_update(&obj
->intern
->types
, oid
, (void *) &row
, sizeof(zval
*), NULL
);
306 zend_hash_update(&obj
->intern
->types
, name
, strlen(name
) + 1, (void *) &row
, sizeof(zval
*), NULL
);
311 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
317 static zend_function_entry php_pqtypes_methods
[] = {
318 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
319 PHP_ME(pqtypes
, refresh
, ai_pqtypes_refresh
, ZEND_ACC_PUBLIC
)
323 PHP_MSHUTDOWN_FUNCTION(pqtypes
)
325 zend_hash_destroy(&php_pqtypes_object_prophandlers
);
329 PHP_MINIT_FUNCTION(pqtypes
)
331 zend_class_entry ce
= {0};
332 php_pq_object_prophandler_t ph
= {0};
334 INIT_NS_CLASS_ENTRY(ce
, "pq", "Types", php_pqtypes_methods
);
335 php_pqtypes_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
336 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
338 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
339 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
340 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
341 php_pqtypes_object_handlers
.clone_obj
= NULL
;
342 php_pqtypes_object_handlers
.get_property_ptr_ptr
= NULL
;
343 php_pqtypes_object_handlers
.get_gc
= NULL
;
344 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
345 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
346 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
347 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
348 php_pqtypes_object_handlers
.unset_dimension
= NULL
;
349 php_pqtypes_object_handlers
.write_dimension
= NULL
;
351 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, NULL
, 1);
353 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC
);
354 ph
.read
= php_pqtypes_object_read_connection
;
355 zend_hash_add(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection"), (void *) &ph
, sizeof(ph
), NULL
);
357 #ifdef HAVE_PHP_PQ_TYPE_H
359 # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid TSRMLS_CC);
360 # include "php_pq_type.h"
361 zend_declare_class_constant_bool(php_pqtypes_class_entry
, ZEND_STRL("DEFINED"), 1 TSRMLS_CC
);
363 zend_declare_class_constant_bool(php_pqtypes_class_entry
, ZEND_STRL("DEFINED"), 0 TSRMLS_CC
);
374 * vim600: noet sw=4 ts=4 fdm=marker
375 * vim<600: noet sw=4 ts=4