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
;
140 if (SUCCESS
== zend_hash_index_find(&obj
->intern
->types
, index
, (void *) &data
)) {
141 return Z_TYPE_PP(data
) != IS_NULL
;
149 return has_dimension(&obj
->intern
->types
, member
, NULL
, NULL
, NULL TSRMLS_CC
);
155 static zval
*php_pqtypes_object_read_dimension(zval
*object
, zval
*member
, int type TSRMLS_DC
)
158 char *key_str
= NULL
;
160 php_pqtypes_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
162 if (has_dimension(&obj
->intern
->types
, member
, &key_str
, &key_len
, &index TSRMLS_CC
)) {
165 if (key_str
&& key_len
) {
166 if (SUCCESS
== zend_hash_find(&obj
->intern
->types
, key_str
, key_len
, (void *) &data
)) {
171 if (SUCCESS
== zend_hash_index_find(&obj
->intern
->types
, index
, (void *) &data
)) {
183 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct
, 0, 0, 1)
184 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
185 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
187 static PHP_METHOD(pqtypes
, __construct
) {
188 zend_error_handling zeh
;
189 zval
*zconn
, *znsp
= NULL
;
192 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
193 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|a!", &zconn
, php_pqconn_class_entry
, &znsp
);
194 zend_restore_error_handling(&zeh TSRMLS_CC
);
197 php_pqconn_object_t
*conn_obj
= zend_object_store_get_object(zconn TSRMLS_CC
);
199 if (!conn_obj
->intern
) {
200 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
202 php_pqtypes_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
205 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
206 obj
->intern
->conn
= conn_obj
;
207 php_pq_object_addref(conn_obj TSRMLS_CC
);
208 zend_hash_init(&obj
->intern
->types
, 300, NULL
, ZVAL_PTR_DTOR
, 0);
211 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", &retval
, znsp
);
213 zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "refresh", &retval
);
217 zval_ptr_dtor(&retval
);
223 #define PHP_PQ_TYPES_QUERY \
224 "select t.oid, t.* " \
225 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
226 "where typisdefined " \
228 #define PHP_PQ_OID_TEXT 25
230 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh
, 0, 0, 0)
231 ZEND_ARG_ARRAY_INFO(0, namespaces
, 1)
233 static PHP_METHOD(pqtypes
, refresh
) {
234 HashTable
*nsp
= NULL
;
235 zend_error_handling zeh
;
238 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
239 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|H/!", &nsp
);
240 zend_restore_error_handling(&zeh TSRMLS_CC
);
243 php_pqtypes_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
246 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Types not initialized");
250 if (!nsp
|| !zend_hash_num_elements(nsp
)) {
251 res
= PQexec(obj
->intern
->conn
->intern
->conn
, PHP_PQ_TYPES_QUERY
" and nspname in ('public', 'pg_catalog')");
255 char **params
= NULL
;
259 smart_str_appends(&str
, PHP_PQ_TYPES_QUERY
" and nspname in(");
260 zend_hash_init(&zdtor
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
261 count
= php_pq_params_to_array(nsp
, ¶ms
, &zdtor TSRMLS_CC
);
262 oids
= ecalloc(count
+ 1, sizeof(*oids
));
263 for (i
= 0; i
< count
; ++i
) {
264 oids
[i
] = PHP_PQ_OID_TEXT
;
266 smart_str_appendc(&str
, ',');
268 smart_str_appendc(&str
, '$');
269 smart_str_append_unsigned(&str
, i
+1);
271 smart_str_appendc(&str
, ')');
274 res
= PQexecParams(obj
->intern
->conn
->intern
->conn
, str
.c
, count
, oids
, (const char *const*) params
, NULL
, NULL
, 0);
276 smart_str_free(&str
);
279 zend_hash_destroy(&zdtor
);
283 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
285 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
288 for (r
= 0, rows
= PQntuples(res
); r
< rows
; ++r
) {
289 zval
*row
= php_pqres_row_to_zval(res
, r
, PHP_PQRES_FETCH_OBJECT
, NULL TSRMLS_CC
);
290 long oid
= atol(PQgetvalue(res
, r
, 0 ));
291 char *name
= PQgetvalue(res
, r
, 1);
295 zend_hash_index_update(&obj
->intern
->types
, oid
, (void *) &row
, sizeof(zval
*), NULL
);
296 zend_hash_add(&obj
->intern
->types
, name
, strlen(name
) + 1, (void *) &row
, sizeof(zval
*), NULL
);
301 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
307 static zend_function_entry php_pqtypes_methods
[] = {
308 PHP_ME(pqtypes
, __construct
, ai_pqtypes_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
309 PHP_ME(pqtypes
, refresh
, ai_pqtypes_refresh
, ZEND_ACC_PUBLIC
)
313 PHP_MINIT_FUNCTION(pqtypes
)
315 zend_class_entry ce
= {0};
316 php_pq_object_prophandler_t ph
= {0};
318 INIT_NS_CLASS_ENTRY(ce
, "pq", "Types", php_pqtypes_methods
);
319 php_pqtypes_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
320 php_pqtypes_class_entry
->create_object
= php_pqtypes_create_object
;
322 memcpy(&php_pqtypes_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
323 php_pqtypes_object_handlers
.read_property
= php_pq_object_read_prop
;
324 php_pqtypes_object_handlers
.write_property
= php_pq_object_write_prop
;
325 php_pqtypes_object_handlers
.clone_obj
= NULL
;
326 php_pqtypes_object_handlers
.get_property_ptr_ptr
= NULL
;
327 php_pqtypes_object_handlers
.get_properties
= php_pq_object_properties
;
328 php_pqtypes_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
329 php_pqtypes_object_handlers
.has_dimension
= php_pqtypes_object_has_dimension
;
330 php_pqtypes_object_handlers
.read_dimension
= php_pqtypes_object_read_dimension
;
331 php_pqtypes_object_handlers
.unset_dimension
= NULL
;
332 php_pqtypes_object_handlers
.write_dimension
= NULL
;
334 zend_hash_init(&php_pqtypes_object_prophandlers
, 1, NULL
, NULL
, 1);
336 zend_declare_property_null(php_pqtypes_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC
);
337 ph
.read
= php_pqtypes_object_read_connection
;
338 zend_hash_add(&php_pqtypes_object_prophandlers
, "connection", sizeof("connection"), (void *) &ph
, sizeof(ph
), NULL
);
348 * vim600: noet sw=4 ts=4 fdm=marker
349 * vim<600: noet sw=4 ts=4