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(zval
*object
, 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(zval
*object
, 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 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 int php_pqtypes_object_has_dimension(zval
*object
, zval
*member
, int check_empty
)
99 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(object
, NULL
);
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
);
127 static zval
*php_pqtypes_object_read_dimension(zval
*object
, zval
*member
, int type
, zval
*rv
)
129 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(object
, NULL
);
130 zend_string
*key
= NULL
;
134 if (has_dimension(&obj
->intern
->types
, member
, &key
, &index
)) {
136 data
= zend_hash_find(&obj
->intern
->types
, key
);
137 zend_string_release(key
);
139 data
= zend_hash_index_find(&obj
->intern
->types
, index
);
146 static void php_pqtypes_object_write_dimension(zval
*object
, zval
*offset
, zval
*value
)
148 throw_exce(EX_RUNTIME
, "pq\\Types object must not be modified");
151 static void php_pqtypes_object_unset_dimension(zval
*object
, zval
*offset
)
153 throw_exce(EX_RUNTIME
, "pq\\Types object must not be modified");
156 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
157 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
158 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
160 static PHP_METHOD(pqtypes
, __construct
) {
161 zend_error_handling zeh
;
162 zval
*zconn
, *znsp
= NULL
;
165 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
166 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
167 zend_restore_error_handling(&zeh
);
170 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
172 if (!conn_obj
->intern
) {
173 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
175 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
177 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
178 obj
->intern
->conn
= conn_obj
;
179 php_pq_object_addref(conn_obj
);
180 zend_hash_init(&obj
->intern
->types
, 512, NULL
, ZVAL_PTR_DTOR
, 0);
183 zend_call_method_with_1_params(getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", NULL
, znsp
);
185 zend_call_method_with_0_params(getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", NULL
);
191 #define PHP_PQ_TYPES_QUERY \
192 "select t.oid, t.* " \
193 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
195 #ifndef PHP_PQ_OID_TEXT
196 # define PHP_PQ_OID_TEXT 25
199 static int apply_nsp(zval
*zp
, int argc
, va_list argv
, zend_hash_key
*key
)
201 unsigned pcount
, tcount
;
202 php_pq_params_t
*params
= va_arg(argv
, php_pq_params_t
*);
203 smart_str
*str
= va_arg(argv
, smart_str
*);
205 tcount
= php_pq_params_add_type_oid(params
, PHP_PQ_OID_TEXT
);
206 pcount
= php_pq_params_add_param(params
, zp
);
208 if (tcount
!= pcount
) {
209 php_error_docref(NULL
, E_WARNING
, "Param/Type count mismatch");
210 return ZEND_HASH_APPLY_STOP
;
213 smart_str_appendc(str
, ',');
215 smart_str_appendc(str
, '$');
216 smart_str_append_unsigned(str
, pcount
);
218 return ZEND_HASH_APPLY_KEEP
;
221 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh
, 0, 0, 0)
222 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
224 static PHP_METHOD(pqtypes
, refresh
) {
225 HashTable
*nsp
= NULL
;
226 zend_error_handling zeh
;
229 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
230 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|H/!", &nsp
);
231 zend_restore_error_handling(&zeh
);
234 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
237 throw_exce(EX_UNINITIALIZED
, "pq\\Types not initialized");
241 if (!nsp
|| !zend_hash_num_elements(nsp
)) {
242 res
= php_pq_exec(obj
->intern
->conn
->intern
->conn
, PHP_PQ_TYPES_QUERY
" and nspname in ('public', 'pg_catalog')");
245 php_pq_params_t
*params
= php_pq_params_init(&obj
->intern
->conn
->intern
->converters
, NULL
, NULL
);
247 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
248 zend_hash_apply_with_arguments(nsp
, apply_nsp
, 2, params
, &str
);
249 smart_str_appendc(&str
, ')');
252 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);
254 smart_str_free(&str
);
255 php_pq_params_free(¶ms
);
259 throw_exce(EX_RUNTIME
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
261 if (SUCCESS
== php_pqres_success(res
)) {
264 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
268 row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, &tmp
);
271 zend_hash_index_update(&obj
->intern
->types
, atol(PQgetvalue(res
, r
, 0 )), row
);
272 zend_hash_str_update(&obj
->intern
->types
, PQgetvalue(res
, r
, 1), PQgetlength(res
, r
, 1), row
);
276 php_pqres_clear(res
);
277 php_pqconn_notify_listeners(obj
->intern
->conn
);
283 static zend_function_entry php_pqtypes_methods
[] = {
284 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
)
285 PHP_ME(pqtypes
, refresh
, ai_pqtypes_refresh
, ZEND_ACC_PUBLIC
)
289 PHP_MSHUTDOWN_FUNCTION(pqtypes
)
291 zend_hash_destroy(&php_pqtypes_object_prophandlers
);
295 PHP_MINIT_FUNCTION(pqtypes
)
297 zend_class_entry ce
= {0};
298 php_pq_object_prophandler_t ph
= {0};
300 INIT_NS_CLASS_ENTRY(ce
, "pq", "Types", php_pqtypes_methods
);
301 php_pqtypes_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
302 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
305 zend_class_implements(php_pqtypes_class_entry, 1, zend_ce_arrayaccess);
308 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
309 php_pqtypes_object_handlers
.offset
= XtOffsetOf(php_pqtypes_object_t
, zo
);
310 php_pqtypes_object_handlers
.free_obj
= php_pqtypes_object_free
;
311 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
312 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
313 php_pqtypes_object_handlers
.clone_obj
= NULL
;
314 php_pqtypes_object_handlers
.get_property_ptr_ptr
= php_pq_object_get_prop_ptr_null
;
315 php_pqtypes_object_handlers
.get_gc
= php_pq_object_get_gc
;
316 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
317 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
318 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
319 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
320 php_pqtypes_object_handlers
.unset_dimension
= php_pqtypes_object_unset_dimension
;
321 php_pqtypes_object_handlers
.write_dimension
= php_pqtypes_object_write_dimension
;
323 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, php_pq_object_prophandler_dtor
, 1);
325 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
326 ph
.read
= php_pqtypes_object_read_connection
;
327 ph
.gc
= php_pqtypes_object_gc_connection
;
328 zend_hash_str_add_mem(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
332 # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid);
333 # include "php_pq_type.h"
343 * vim600: noet sw=4 ts=4 fdm=marker
344 * vim<600: noet sw=4 ts=4