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
;
124 static zval
*php_pqtypes_object_read_dimension(zval
*object
, zval
*member
, int type
, zval
*rv
)
126 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(object
, NULL
);
127 zend_string
*key
= NULL
;
131 if (has_dimension(&obj
->intern
->types
, member
, &key
, &index
)) {
133 data
= zend_hash_find(&obj
->intern
->types
, key
);
134 zend_string_release(key
);
136 data
= zend_hash_index_find(&obj
->intern
->types
, index
);
143 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
144 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
145 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
147 static PHP_METHOD(pqtypes
, __construct
) {
148 zend_error_handling zeh
;
149 zval
*zconn
, *znsp
= NULL
;
152 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
153 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
154 zend_restore_error_handling(&zeh
);
157 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
159 if (!conn_obj
->intern
) {
160 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
162 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
164 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
165 obj
->intern
->conn
= conn_obj
;
166 php_pq_object_addref(conn_obj
);
167 zend_hash_init(&obj
->intern
->types
, 512, NULL
, ZVAL_PTR_DTOR
, 0);
170 zend_call_method_with_1_params(getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", NULL
, znsp
);
172 zend_call_method_with_0_params(getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", NULL
);
178 #define PHP_PQ_TYPES_QUERY \
179 "select t.oid, t.* " \
180 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
181 "where typisdefined " \
183 #ifndef PHP_PQ_OID_TEXT
184 # define PHP_PQ_OID_TEXT 25
187 static int apply_nsp(zval
*zp
, int argc
, va_list argv
, zend_hash_key
*key
)
189 unsigned pcount
, tcount
;
190 php_pq_params_t
*params
= va_arg(argv
, php_pq_params_t
*);
191 smart_str
*str
= va_arg(argv
, smart_str
*);
193 tcount
= php_pq_params_add_type_oid(params
, PHP_PQ_OID_TEXT
);
194 pcount
= php_pq_params_add_param(params
, zp
);
196 if (tcount
!= pcount
) {
197 php_error_docref(NULL
, E_WARNING
, "Param/Type count mismatch");
198 return ZEND_HASH_APPLY_STOP
;
201 smart_str_appendc(str
, ',');
203 smart_str_appendc(str
, '$');
204 smart_str_append_unsigned(str
, pcount
);
206 return ZEND_HASH_APPLY_KEEP
;
209 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh
, 0, 0, 0)
210 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
212 static PHP_METHOD(pqtypes
, refresh
) {
213 HashTable
*nsp
= NULL
;
214 zend_error_handling zeh
;
217 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
218 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|H/!", &nsp
);
219 zend_restore_error_handling(&zeh
);
222 php_pqtypes_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
225 throw_exce(EX_UNINITIALIZED
, "pq\\Types not initialized");
229 if (!nsp
|| !zend_hash_num_elements(nsp
)) {
230 res
= PQexec(obj
->intern
->conn
->intern
->conn
, PHP_PQ_TYPES_QUERY
" and nspname in ('public', 'pg_catalog')");
233 php_pq_params_t
*params
= php_pq_params_init(&obj
->intern
->conn
->intern
->converters
, NULL
, NULL
);
235 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
236 zend_hash_apply_with_arguments(nsp TSRMLS_CC
, apply_nsp
, 2, params
, &str
);
237 smart_str_appendc(&str
, ')');
240 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);
242 smart_str_free(&str
);
243 php_pq_params_free(¶ms
);
247 throw_exce(EX_RUNTIME
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
249 if (SUCCESS
== php_pqres_success(res
)) {
252 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
256 row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, &tmp
);
259 zend_hash_index_update(&obj
->intern
->types
, atol(PQgetvalue(res
, r
, 0 )), row
);
260 zend_hash_str_update(&obj
->intern
->types
, PQgetvalue(res
, r
, 1), PQgetlength(res
, r
, 1), row
);
265 php_pqconn_notify_listeners(obj
->intern
->conn
);
271 static zend_function_entry php_pqtypes_methods
[] = {
272 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
273 PHP_ME(pqtypes
, refresh
, ai_pqtypes_refresh
, ZEND_ACC_PUBLIC
)
277 PHP_MSHUTDOWN_FUNCTION(pqtypes
)
279 zend_hash_destroy(&php_pqtypes_object_prophandlers
);
283 PHP_MINIT_FUNCTION(pqtypes
)
285 zend_class_entry ce
= {0};
286 php_pq_object_prophandler_t ph
= {0};
288 INIT_NS_CLASS_ENTRY(ce
, "pq", "Types", php_pqtypes_methods
);
289 php_pqtypes_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
290 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
293 zend_class_implements(php_pqtypes_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess);
296 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
297 php_pqtypes_object_handlers
.offset
= XtOffsetOf(php_pqtypes_object_t
, zo
);
298 php_pqtypes_object_handlers
.free_obj
= php_pqtypes_object_free
;
299 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
300 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
301 php_pqtypes_object_handlers
.clone_obj
= NULL
;
302 php_pqtypes_object_handlers
.get_property_ptr_ptr
= NULL
;
303 php_pqtypes_object_handlers
.get_gc
= php_pq_object_get_gc
;
304 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
305 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
306 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
307 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
308 php_pqtypes_object_handlers
.unset_dimension
= NULL
;
309 php_pqtypes_object_handlers
.write_dimension
= NULL
;
311 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, php_pq_object_prophandler_dtor
, 1);
313 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
314 ph
.read
= php_pqtypes_object_read_connection
;
315 ph
.gc
= php_pqtypes_object_gc_connection
;
316 zend_hash_str_add_mem(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
320 # define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid);
321 # include "php_pq_type.h"
331 * vim600: noet sw=4 ts=4 fdm=marker
332 * vim<600: noet sw=4 ts=4