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 <Zend/zend_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(zend_object
*o
)
33 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
35 fprintf(stderr
, "FREE types(#%d) %p (conn(#%d): %p)\n", obj
->zo
.handle
, obj
, obj
->intern
->conn
->zo
.handle
, obj
->intern
->conn
);
38 zend_hash_destroy(&obj
->intern
->types
);
39 php_pq_object_delref(obj
->intern
->conn
);
43 php_pq_object_dtor(o
);
46 php_pqtypes_object_t
*php_pqtypes_create_object_ex(zend_class_entry
*ce
, php_pqtypes_t
*intern
)
48 return php_pq_object_create(ce
, intern
, sizeof(php_pqtypes_object_t
),
49 &php_pqtypes_object_handlers
, &php_pqtypes_object_prophandlers
);
52 static zend_object
*php_pqtypes_create_object(zend_class_entry
*class_type
)
54 return &php_pqtypes_create_object_ex(class_type
, NULL
)->zo
;
57 static void php_pqtypes_object_read_connection(void *o
, zval
*return_value
)
59 php_pqtypes_object_t
*obj
= o
;
61 php_pq_object_to_zval(obj
->intern
->conn
, return_value
);
63 static void php_pqtypes_object_gc_connection(void *o
, zval
*return_value
)
65 php_pqtypes_object_t
*obj
= o
;
68 php_pq_object_to_zval_no_addref(obj
->intern
->conn
, &zconn
);
69 add_next_index_zval(return_value
, &zconn
);
72 static inline int has_dimension(HashTable
*ht
, zval
*member
, zend_string
**key
, zend_long
*index
)
74 if (Z_TYPE_P(member
) == IS_LONG
) {
75 *index
= Z_LVAL_P(member
);
78 return zend_hash_index_exists(ht
, *index
);
80 zend_string
*str
= zval_get_string(member
);
82 if (is_numeric_str_function(str
, index
, NULL
)) {
83 zend_string_release(str
);
87 if (zend_hash_exists(ht
, str
)) {
92 zend_string_release(str
);
97 static inline int php_pqtypes_object_has_dimension_ex(zend_object
*object
, zval
*member
, int check_empty
)
99 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(NULL
, object
);
100 zend_string
*key
= NULL
;
103 if (has_dimension(&obj
->intern
->types
, member
, &key
, &index
)) {
108 if ((data
= zend_hash_find(&obj
->intern
->types
, key
))) {
109 zend_string_release(key
);
110 return Z_TYPE_P(data
) != IS_NULL
;
112 zend_string_release(key
);
113 } else if ((data
= zend_hash_index_find(&obj
->intern
->types
, index
))) {
114 return Z_TYPE_P(data
) != IS_NULL
;
118 zend_string_release(key
);
126 #if PHP_VERSION_ID >= 80000
127 static int php_pqtypes_object_has_dimension(zend_object
*object
, zval
*member
, int check_empty
)
129 return php_pqtypes_object_has_dimension_ex(object
, member
, check_empty
);
132 static int php_pqtypes_object_has_dimension(zval
*object
, zval
*member
, int check_empty
)
134 return php_pqtypes_object_has_dimension_ex(Z_OBJ_P(object
), member
, check_empty
);
138 static inline zval
*php_pqtypes_object_read_dimension_ex(zend_object
*object
, zval
*member
, int type
, zval
*rv
)
140 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(NULL
, object
);
141 zend_string
*key
= NULL
;
145 if (has_dimension(&obj
->intern
->types
, member
, &key
, &index
)) {
147 data
= zend_hash_find(&obj
->intern
->types
, key
);
148 zend_string_release(key
);
150 data
= zend_hash_index_find(&obj
->intern
->types
, index
);
156 #if PHP_VERSION_ID >= 80000
157 static zval
*php_pqtypes_object_read_dimension(zend_object
*object
, zval
*member
, int type
, zval
*rv
)
159 return php_pqtypes_object_read_dimension_ex(object
, member
, type
, rv
);
162 static zval
*php_pqtypes_object_read_dimension(zval
*object
, zval
*member
, int type
, zval
*rv
)
164 return php_pqtypes_object_read_dimension_ex(Z_OBJ_P(object
), member
, type
, rv
);
168 #if PHP_VERSION_ID >= 80000
169 static void php_pqtypes_object_write_dimension(zend_object
*object
, zval
*offset
, zval
*value
)
171 throw_exce(EX_RUNTIME
, "pq\\Types object must not be modified");
174 static void php_pqtypes_object_write_dimension(zval
*object
, zval
*offset
, zval
*value
)
176 throw_exce(EX_RUNTIME
, "pq\\Types object must not be modified");
180 #if PHP_VERSION_ID >= 80000
181 static void php_pqtypes_object_unset_dimension(zend_object
*object
, zval
*offset
)
183 throw_exce(EX_RUNTIME
, "pq\\Types object must not be modified");
186 static void php_pqtypes_object_unset_dimension(zval
*object
, zval
*offset
)
188 throw_exce(EX_RUNTIME
, "pq\\Types object must not be modified");
192 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
193 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
194 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
196 static PHP_METHOD(pqtypes
, __construct
) {
197 zend_error_handling zeh
;
198 zval
*zconn
, *znsp
= NULL
;
201 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
202 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
203 zend_restore_error_handling(&zeh
);
206 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
208 if (!conn_obj
->intern
) {
209 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
211 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
213 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
214 obj
->intern
->conn
= conn_obj
;
215 php_pq_object_addref(conn_obj
);
216 zend_hash_init(&obj
->intern
->types
, 512, NULL
, ZVAL_PTR_DTOR
, 0);
219 php_pq_call_method(getThis(), "refresh", 1, NULL
, znsp
);
221 php_pq_call_method(getThis(), "refresh", 0, NULL
);
227 #define PHP_PQ_TYPES_QUERY \
228 "select t.oid, t.typname, t.* " \
229 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
231 #ifndef PHP_PQ_OID_TEXT
232 # define PHP_PQ_OID_TEXT 25
235 static int apply_nsp(zval
*zp
, 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
, 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
);
266 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|H/!", &nsp
);
267 zend_restore_error_handling(&zeh
);
270 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
273 throw_exce(EX_UNINITIALIZED
, "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
);
283 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
284 zend_hash_apply_with_arguments(nsp
, apply_nsp
, 2, params
, &str
);
285 smart_str_appendc(&str
, ')');
288 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);
290 smart_str_free(&str
);
291 php_pq_params_free(¶ms
);
295 throw_exce(EX_RUNTIME
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
297 if (SUCCESS
== php_pqres_success(res
)) {
300 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
304 row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, &tmp
);
307 zend_hash_index_update(&obj
->intern
->types
, atol(PQgetvalue(res
, r
, 0 )), row
);
308 zend_hash_str_update(&obj
->intern
->types
, PQgetvalue(res
, r
, 1), PQgetlength(res
, r
, 1), row
);
312 php_pqres_clear(res
);
313 php_pqconn_notify_listeners(obj
->intern
->conn
);
319 static zend_function_entry php_pqtypes_methods
[] = {
320 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
)
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
);
338 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
341 zend_class_implements(php_pqtypes_class_entry, 1, zend_ce_arrayaccess);
344 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
345 php_pqtypes_object_handlers
.offset
= XtOffsetOf(php_pqtypes_object_t
, zo
);
346 php_pqtypes_object_handlers
.free_obj
= php_pqtypes_object_free
;
347 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
348 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
349 php_pqtypes_object_handlers
.clone_obj
= NULL
;
350 php_pqtypes_object_handlers
.get_property_ptr_ptr
= php_pq_object_get_prop_ptr_null
;
351 php_pqtypes_object_handlers
.get_gc
= php_pq_object_get_gc
;
352 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
353 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
354 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
355 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
356 php_pqtypes_object_handlers
.unset_dimension
= php_pqtypes_object_unset_dimension
;
357 php_pqtypes_object_handlers
.write_dimension
= php_pqtypes_object_write_dimension
;
359 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, php_pq_object_prophandler_dtor
, 1);
361 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
362 ph
.read
= php_pqtypes_object_read_connection
;
363 ph
.gc
= php_pqtypes_object_gc_connection
;
364 zend_hash_str_add_mem(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
368 # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid);
369 # include "php_pq_type.h"
379 * vim600: noet sw=4 ts=4 fdm=marker
380 * vim<600: noet sw=4 ts=4