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 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
147 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
148 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
150 static PHP_METHOD(pqtypes
, __construct
) {
151 zend_error_handling zeh
;
152 zval
*zconn
, *znsp
= NULL
;
155 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
156 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
157 zend_restore_error_handling(&zeh
);
160 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
162 if (!conn_obj
->intern
) {
163 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
165 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
167 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
168 obj
->intern
->conn
= conn_obj
;
169 php_pq_object_addref(conn_obj
);
170 zend_hash_init(&obj
->intern
->types
, 512, NULL
, ZVAL_PTR_DTOR
, 0);
173 zend_call_method_with_1_params(getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", NULL
, znsp
);
175 zend_call_method_with_0_params(getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", NULL
);
181 #define PHP_PQ_TYPES_QUERY \
182 "select t.oid, t.* " \
183 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
184 "where typisdefined " \
186 #ifndef PHP_PQ_OID_TEXT
187 # define PHP_PQ_OID_TEXT 25
190 static int apply_nsp(zval
*zp
, int argc
, va_list argv
, zend_hash_key
*key
)
192 unsigned pcount
, tcount
;
193 php_pq_params_t
*params
= va_arg(argv
, php_pq_params_t
*);
194 smart_str
*str
= va_arg(argv
, smart_str
*);
196 tcount
= php_pq_params_add_type_oid(params
, PHP_PQ_OID_TEXT
);
197 pcount
= php_pq_params_add_param(params
, zp
);
199 if (tcount
!= pcount
) {
200 php_error_docref(NULL
, E_WARNING
, "Param/Type count mismatch");
201 return ZEND_HASH_APPLY_STOP
;
204 smart_str_appendc(str
, ',');
206 smart_str_appendc(str
, '$');
207 smart_str_append_unsigned(str
, pcount
);
209 return ZEND_HASH_APPLY_KEEP
;
212 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh
, 0, 0, 0)
213 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
215 static PHP_METHOD(pqtypes
, refresh
) {
216 HashTable
*nsp
= NULL
;
217 zend_error_handling zeh
;
220 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
221 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|H/!", &nsp
);
222 zend_restore_error_handling(&zeh
);
225 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
228 throw_exce(EX_UNINITIALIZED
, "pq\\Types not initialized");
232 if (!nsp
|| !zend_hash_num_elements(nsp
)) {
233 res
= PQexec(obj
->intern
->conn
->intern
->conn
, PHP_PQ_TYPES_QUERY
" and nspname in ('public', 'pg_catalog')");
236 php_pq_params_t
*params
= php_pq_params_init(&obj
->intern
->conn
->intern
->converters
, NULL
, NULL
);
238 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
239 zend_hash_apply_with_arguments(nsp TSRMLS_CC
, apply_nsp
, 2, params
, &str
);
240 smart_str_appendc(&str
, ')');
243 res
= PQexecParams(obj
->intern
->conn
->intern
->conn
, smart_str_v(&str
), params
->param
.count
, params
->type
.oids
, (const char *const*) params
->param
.strings
, NULL
, NULL
, 0);
245 smart_str_free(&str
);
246 php_pq_params_free(¶ms
);
250 throw_exce(EX_RUNTIME
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
252 if (SUCCESS
== php_pqres_success(res
)) {
255 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
259 row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, &tmp
);
262 zend_hash_index_update(&obj
->intern
->types
, atol(PQgetvalue(res
, r
, 0 )), row
);
263 zend_hash_str_update(&obj
->intern
->types
, PQgetvalue(res
, r
, 1), PQgetlength(res
, r
, 1), row
);
268 php_pqconn_notify_listeners(obj
->intern
->conn
);
274 static zend_function_entry php_pqtypes_methods
[] = {
275 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
276 PHP_ME(pqtypes
, refresh
, ai_pqtypes_refresh
, ZEND_ACC_PUBLIC
)
280 PHP_MSHUTDOWN_FUNCTION(pqtypes
)
282 zend_hash_destroy(&php_pqtypes_object_prophandlers
);
286 PHP_MINIT_FUNCTION(pqtypes
)
288 zend_class_entry ce
= {0};
289 php_pq_object_prophandler_t ph
= {0};
291 INIT_NS_CLASS_ENTRY(ce
, "pq", "Types", php_pqtypes_methods
);
292 php_pqtypes_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
293 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
296 zend_class_implements(php_pqtypes_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess);
299 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
300 php_pqtypes_object_handlers
.offset
= XtOffsetOf(php_pqtypes_object_t
, zo
);
301 php_pqtypes_object_handlers
.free_obj
= php_pqtypes_object_free
;
302 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
303 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
304 php_pqtypes_object_handlers
.clone_obj
= NULL
;
305 php_pqtypes_object_handlers
.get_property_ptr_ptr
= NULL
;
306 php_pqtypes_object_handlers
.get_gc
= php_pq_object_get_gc
;
307 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
308 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
309 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
310 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
311 php_pqtypes_object_handlers
.unset_dimension
= NULL
;
312 php_pqtypes_object_handlers
.write_dimension
= NULL
;
314 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, php_pq_object_prophandler_dtor
, 1);
316 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
317 ph
.read
= php_pqtypes_object_read_connection
;
318 ph
.gc
= php_pqtypes_object_gc_connection
;
319 zend_hash_str_add_mem(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
323 # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid);
324 # include "php_pq_type.h"
334 * vim600: noet sw=4 ts=4 fdm=marker
335 * vim<600: noet sw=4 ts=4