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
;
141 if (SUCCESS
== zend_hash_index_find(&obj
->intern
->types
, index
, (void *) &data
)) {
142 return Z_TYPE_PP(data
) != IS_NULL
;
150 return has_dimension(&obj
->intern
->types
, member
, NULL
, NULL
, NULL TSRMLS_CC
);
156 static zval
*php_pqtypes_object_read_dimension(zval
*object
, zval
*member
, int type TSRMLS_DC
)
159 char *key_str
= NULL
;
161 php_pqtypes_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
163 if (has_dimension(&obj
->intern
->types
, member
, &key_str
, &key_len
, &index TSRMLS_CC
)) {
166 if (key_str
&& key_len
) {
167 if (SUCCESS
== zend_hash_find(&obj
->intern
->types
, key_str
, key_len
, (void *) &data
)) {
172 if (SUCCESS
== zend_hash_index_find(&obj
->intern
->types
, index
, (void *) &data
)) {
185 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
186 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
187 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
189 static PHP_METHOD(pqtypes
, __construct
) {
190 zend_error_handling zeh
;
191 zval
*zconn
, *znsp
= NULL
;
194 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
195 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
196 zend_restore_error_handling(&zeh TSRMLS_CC
);
199 php_pqconn_object_t
*conn_obj
= zend_object_store_get_object(zconn TSRMLS_CC
);
201 if (!conn_obj
->intern
) {
202 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
204 php_pqtypes_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
207 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
208 obj
->intern
->conn
= conn_obj
;
209 php_pq_object_addref(conn_obj TSRMLS_CC
);
210 zend_hash_init(&obj
->intern
->types
, 512, NULL
, ZVAL_PTR_DTOR
, 0);
213 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", &retval
, znsp
);
215 zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", &retval
);
219 zval_ptr_dtor(&retval
);
225 #define PHP_PQ_TYPES_QUERY \
226 "select t.oid, t.* " \
227 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
228 "where typisdefined " \
230 #ifndef PHP_PQ_OID_TEXT
231 # define PHP_PQ_OID_TEXT 25
234 static int apply_nsp(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
237 unsigned pcount
, tcount
;
238 php_pq_params_t
*params
= va_arg(argv
, php_pq_params_t
*);
239 smart_str
*str
= va_arg(argv
, smart_str
*);
241 tcount
= php_pq_params_add_type_oid(params
, PHP_PQ_OID_TEXT
);
242 pcount
= php_pq_params_add_param(params
, *zp
);
244 if (tcount
!= pcount
) {
245 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Param/Type count mismatch");
246 return ZEND_HASH_APPLY_STOP
;
249 smart_str_appendc(str
, ',');
251 smart_str_appendc(str
, '$');
252 smart_str_append_unsigned(str
, pcount
);
254 return ZEND_HASH_APPLY_KEEP
;
257 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh
, 0, 0, 0)
258 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
260 static PHP_METHOD(pqtypes
, refresh
) {
261 HashTable
*nsp
= NULL
;
262 zend_error_handling zeh
;
265 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
266 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|H/!", &nsp
);
267 zend_restore_error_handling(&zeh TSRMLS_CC
);
270 php_pqtypes_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
273 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Types not initialized");
277 if (!nsp
|| !zend_hash_num_elements(nsp
)) {
278 res
= php_pq_exec(obj
->intern
->conn
->intern
->conn
, PHP_PQ_TYPES_QUERY
" and nspname in ('public', 'pg_catalog')");
281 php_pq_params_t
*params
= php_pq_params_init(&obj
->intern
->conn
->intern
->converters
, NULL
, NULL TSRMLS_CC
);
283 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
284 zend_hash_apply_with_arguments(nsp TSRMLS_CC
, apply_nsp
, 2, params
, &str
);
285 smart_str_appendc(&str
, ')');
288 res
= php_pq_exec_params(obj
->intern
->conn
->intern
->conn
, str
.c
, params
->param
.count
, params
->type
.oids
, (const char *const*) params
->param
.strings
, NULL
, NULL
, 0);
290 smart_str_free(&str
);
291 php_pq_params_free(¶ms
);
295 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
297 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
300 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
301 zval
*row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, NULL TSRMLS_CC
);
302 long oid
= atol(PQgetvalue(res
, r
, 0 ));
303 char *name
= PQgetvalue(res
, r
, 1);
307 zend_hash_index_update(&obj
->intern
->types
, oid
, (void *) &row
, sizeof(zval
*), NULL
);
308 zend_hash_update(&obj
->intern
->types
, name
, strlen(name
) + 1, (void *) &row
, sizeof(zval
*), NULL
);
312 php_pqres_clear(res
);
313 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
319 static zend_function_entry php_pqtypes_methods
[] = {
320 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
321 PHP_ME(pqtypes
, refresh
, ai_pqtypes_refresh
, ZEND_ACC_PUBLIC
)
325 PHP_MSHUTDOWN_FUNCTION(pqtypes
)
327 zend_hash_destroy(&php_pqtypes_object_prophandlers
);
331 PHP_MINIT_FUNCTION(pqtypes
)
333 zend_class_entry ce
= {0};
334 php_pq_object_prophandler_t ph
= {0};
336 INIT_NS_CLASS_ENTRY(ce
, "pq", "Types", php_pqtypes_methods
);
337 php_pqtypes_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
338 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
341 zend_class_implements(php_pqtypes_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess);
344 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
345 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
346 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
347 php_pqtypes_object_handlers
.clone_obj
= NULL
;
348 php_pqtypes_object_handlers
.get_property_ptr_ptr
= NULL
;
349 php_pqtypes_object_handlers
.get_gc
= NULL
;
350 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
351 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
352 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
353 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
354 php_pqtypes_object_handlers
.unset_dimension
= NULL
;
355 php_pqtypes_object_handlers
.write_dimension
= NULL
;
357 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, NULL
, 1);
359 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC
);
360 ph
.read
= php_pqtypes_object_read_connection
;
361 zend_hash_add(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection"), (void *) &ph
, sizeof(ph
), NULL
);
364 # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid TSRMLS_CC);
365 # include "php_pq_type.h"
375 * vim600: noet sw=4 ts=4 fdm=marker
376 * vim<600: noet sw=4 ts=4