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_pqconn.h"
25 #include "php_pqres.h"
26 #include "php_pqstm.h"
28 zend_class_entry
*php_pqstm_class_entry
;
29 static zend_object_handlers php_pqstm_object_handlers
;
30 static HashTable php_pqstm_object_prophandlers
;
32 static void php_pqstm_deallocate(php_pqstm_object_t
*obj
, zend_bool async
, zend_bool silent
)
34 if (obj
->intern
->allocated
) {
35 char *quoted_name
= PQescapeIdentifier(obj
->intern
->conn
->intern
->conn
, obj
->intern
->name
, strlen(obj
->intern
->name
));
40 smart_str_appends(&cmd
, "DEALLOCATE ");
41 smart_str_appends(&cmd
, quoted_name
);
45 if (PQsendQuery(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
))) {
46 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
47 php_pqconn_notify_listeners(obj
->intern
->conn
);
49 throw_exce(EX_IO
, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
54 if ((res
= PQexec(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
)))) {
57 throw_exce(EX_RUNTIME
, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
61 PQfreemem(quoted_name
);
65 obj
->intern
->allocated
= 0;
69 static void php_pqstm_object_free(zend_object
*o
)
71 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
73 fprintf(stderr
, "FREE stm(#%d) %p (conn(#%d): %p)\n", obj
->zo
.handle
, obj
, obj
->intern
->conn
->zo
.handle
, obj
->intern
->conn
);
76 if (obj
->intern
->conn
->intern
) {
77 php_pq_callback_dtor(&obj
->intern
->conn
->intern
->onevent
);
78 php_pqstm_deallocate(obj
, 0, 1);
79 php_pq_object_delref(obj
->intern
->conn
);
81 efree(obj
->intern
->name
);
82 efree(obj
->intern
->query
);
83 zend_hash_destroy(&obj
->intern
->bound
);
84 if (obj
->intern
->params
) {
85 php_pq_params_free(&obj
->intern
->params
);
90 php_pq_object_dtor(o
);
93 php_pqstm_object_t
*php_pqstm_create_object_ex(zend_class_entry
*ce
, php_pqstm_t
*intern
)
95 return php_pq_object_create(ce
, intern
, sizeof(php_pqstm_object_t
),
96 &php_pqstm_object_handlers
, &php_pqstm_object_prophandlers
);
99 static zend_object
*php_pqstm_create_object(zend_class_entry
*class_type
)
101 return &php_pqstm_create_object_ex(class_type
, NULL
)->zo
;
104 static void php_pqstm_object_read_name(zval
*object
, void *o
, zval
*return_value
)
106 php_pqstm_object_t
*obj
= o
;
108 RETVAL_STRING(obj
->intern
->name
);
111 static void php_pqstm_object_read_connection(zval
*object
, void *o
, zval
*return_value
)
113 php_pqstm_object_t
*obj
= o
;
115 php_pq_object_to_zval(obj
->intern
->conn
, return_value
);
118 static void php_pqstm_object_gc_connection(zval
*object
, void *o
, zval
*return_value
)
120 php_pqstm_object_t
*obj
= o
;
123 php_pq_object_to_zval_no_addref(obj
->intern
->conn
, &zconn
);
124 add_next_index_zval(return_value
, &zconn
);
127 static void php_pqstm_object_read_query(zval
*object
, void *o
, zval
*return_value
)
129 php_pqstm_object_t
*obj
= o
;
131 RETVAL_STRING(obj
->intern
->query
);
134 static void php_pqstm_object_read_types(zval
*object
, void *o
, zval
*return_value
)
137 php_pqstm_object_t
*obj
= o
;
139 array_init_size(return_value
, obj
->intern
->params
->type
.count
);
140 for (i
= 0; i
< obj
->intern
->params
->type
.count
; i
++) {
141 add_next_index_long(return_value
, (long)obj
->intern
->params
->type
.oids
[i
]);
145 php_pqstm_t
*php_pqstm_init(php_pqconn_object_t
*conn
, const char *name
, const char *query
, php_pq_params_t
*params
)
147 php_pqstm_t
*stm
= ecalloc(1, sizeof(*stm
));
149 php_pq_object_addref(conn
);
151 stm
->name
= estrdup(name
);
152 stm
->params
= params
;
153 stm
->query
= estrdup(query
);
156 ZEND_INIT_SYMTABLE(&stm
->bound
);
161 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct
, 0, 0, 3)
162 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
163 ZEND_ARG_INFO(0, name
)
164 ZEND_ARG_INFO(0, query
)
165 ZEND_ARG_ARRAY_INFO(0, types
, 1)
166 ZEND_ARG_INFO(0, async
)
168 static PHP_METHOD(pqstm
, __construct
) {
169 zend_error_handling zeh
;
170 zval
*zconn
, *ztypes
= NULL
;
171 char *name_str
, *query_str
;
172 size_t name_len
, *query_len
;
176 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
177 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "Oss|a/!b", &zconn
, php_pqconn_class_entry
, &name_str
, &name_len
, &query_str
, &query_len
, &ztypes
, &async
);
178 zend_restore_error_handling(&zeh
);
181 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
182 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
185 throw_exce(EX_BAD_METHODCALL
, "pq\\Statement already initialized");
186 } else if (!conn_obj
->intern
) {
187 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
189 php_pq_params_t
*params
= php_pq_params_init(&conn_obj
->intern
->converters
, ztypes
? Z_ARRVAL_P(ztypes
) : NULL
, NULL
);
192 rv
= php_pqconn_prepare_async(zconn
, conn_obj
, name_str
, query_str
, params
);
194 rv
= php_pqconn_prepare(zconn
, conn_obj
, name_str
, query_str
, params
);
198 obj
->intern
= php_pqstm_init(conn_obj
, name_str
, query_str
, params
);
203 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_bind
, 0, 0, 2)
204 ZEND_ARG_INFO(0, param_no
)
205 ZEND_ARG_INFO(1, param_ref
)
207 static PHP_METHOD(pqstm
, bind
) {
210 zend_error_handling zeh
;
213 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
214 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "lz", ¶m_no
, ¶m_ref
);
215 zend_restore_error_handling(&zeh
);
218 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
221 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
222 } else if (!obj
->intern
->allocated
) {
223 throw_exce(EX_UNINITIALIZED
, "pq\\Statement has been deallocated");
225 Z_ADDREF_P(param_ref
);
226 zend_hash_index_update(&obj
->intern
->bound
, param_no
, param_ref
);
227 zend_hash_sort(&obj
->intern
->bound
, php_pq_compare_index
, 0);
232 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec
, 0, 0, 0)
233 ZEND_ARG_ARRAY_INFO(0, params
, 1)
235 static PHP_METHOD(pqstm
, exec
) {
236 zend_error_handling zeh
;
237 zval
*zparams
= NULL
;
240 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
241 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|a/!", &zparams
);
242 zend_restore_error_handling(&zeh
);
245 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
248 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
249 } else if (!obj
->intern
->allocated
) {
250 throw_exce(EX_UNINITIALIZED
, "pq\\Statement has been deallocated");
254 php_pq_params_set_params(obj
->intern
->params
, zparams
? Z_ARRVAL_P(zparams
) : &obj
->intern
->bound
);
255 res
= PQexecPrepared(obj
->intern
->conn
->intern
->conn
, obj
->intern
->name
, obj
->intern
->params
->param
.count
, (const char *const*) obj
->intern
->params
->param
.strings
, NULL
, NULL
, 0);
256 php_pq_params_set_params(obj
->intern
->params
, NULL
);
259 throw_exce(EX_RUNTIME
, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
260 } else if (SUCCESS
== php_pqres_success(res
)) {
261 php_pq_object_to_zval_no_addref(PQresultInstanceData(res
, php_pqconn_event
), return_value
);
262 php_pqconn_notify_listeners(obj
->intern
->conn
);
268 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async
, 0, 0, 0)
269 ZEND_ARG_ARRAY_INFO(0, params
, 1)
270 ZEND_ARG_INFO(0, callable
)
272 static PHP_METHOD(pqstm
, execAsync
) {
273 zend_error_handling zeh
;
274 zval
*zparams
= NULL
;
275 php_pq_callback_t resolver
= {{0}};
278 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
279 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|a/!f", &zparams
, &resolver
.fci
, &resolver
.fcc
);
280 zend_restore_error_handling(&zeh
);
283 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
286 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
287 } else if (!obj
->intern
->allocated
) {
288 throw_exce(EX_UNINITIALIZED
, "pq\\Statement has been deallocated");
292 php_pq_params_set_params(obj
->intern
->params
, zparams
? Z_ARRVAL_P(zparams
) : &obj
->intern
->bound
);
293 rc
= PQsendQueryPrepared(obj
->intern
->conn
->intern
->conn
, obj
->intern
->name
, obj
->intern
->params
->param
.count
, (const char *const*) obj
->intern
->params
->param
.strings
, NULL
, NULL
, 0);
294 php_pq_params_set_params(obj
->intern
->params
, NULL
);
297 throw_exce(EX_IO
, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
298 #if HAVE_PQSETSINGLEROWMODE
299 } else if (obj
->intern
->conn
->intern
->unbuffered
&& !PQsetSingleRowMode(obj
->intern
->conn
->intern
->conn
)) {
300 throw_exce(EX_RUNTIME
, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
303 php_pq_callback_recurse(&obj
->intern
->conn
->intern
->onevent
, &resolver
);
304 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
307 php_pqconn_notify_listeners(obj
->intern
->conn
);
312 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc
, 0, 0, 0)
314 static PHP_METHOD(pqstm
, desc
) {
315 zend_error_handling zeh
;
318 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
319 rv
= zend_parse_parameters_none();
320 zend_restore_error_handling(&zeh
);
323 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
326 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
327 } else if (!obj
->intern
->allocated
) {
328 throw_exce(EX_UNINITIALIZED
, "pq\\Statement has been deallocated");
330 PGresult
*res
= PQdescribePrepared(obj
->intern
->conn
->intern
->conn
, obj
->intern
->name
);
333 throw_exce(EX_RUNTIME
, "Failed to describe statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
335 if (SUCCESS
== php_pqres_success(res
)) {
338 array_init(return_value
);
339 for (p
= 0, params
= PQnparams(res
); p
< params
; ++p
) {
340 add_next_index_long(return_value
, PQparamtype(res
, p
));
344 php_pqconn_notify_listeners(obj
->intern
->conn
);
350 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc_async
, 0, 0, 1)
351 ZEND_ARG_INFO(0, callable
)
353 static PHP_METHOD(pqstm
, descAsync
) {
354 zend_error_handling zeh
;
355 php_pq_callback_t resolver
= {{0}};
358 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
359 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "f", &resolver
.fci
, &resolver
.fcc
);
360 zend_restore_error_handling(&zeh
);
363 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
366 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
367 } else if (!obj
->intern
->allocated
) {
368 throw_exce(EX_UNINITIALIZED
, "pq\\Statement has been deallocated");
369 } else if (!PQsendDescribePrepared(obj
->intern
->conn
->intern
->conn
, obj
->intern
->name
)) {
370 throw_exce(EX_IO
, "Failed to describe statement: %s", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
372 php_pq_callback_recurse(&obj
->intern
->conn
->intern
->onevent
, &resolver
);
373 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
374 php_pqconn_notify_listeners(obj
->intern
->conn
);
379 static zend_always_inline
void php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAMETERS
, zend_bool async
)
381 zend_error_handling zeh
;
384 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
385 rv
= zend_parse_parameters_none();
386 zend_restore_error_handling(&zeh
);
389 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
392 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
394 php_pqstm_deallocate(obj
, async
, 0);
399 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_deallocate
, 0, 0, 0)
401 static PHP_METHOD(pqstm
, deallocate
)
403 php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU
, 0);
406 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_deallocate_async
, 0, 0, 0)
408 static PHP_METHOD(pqstm
, deallocateAsync
)
410 php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU
, 1);
413 static zend_always_inline
void php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAMETERS
, zend_bool async
)
415 zend_error_handling zeh
;
418 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
419 rv
= zend_parse_parameters_none();
420 zend_restore_error_handling(&zeh
);
423 php_pqstm_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
426 throw_exce(EX_UNINITIALIZED
, "pq\\Statement not initialized");
427 } else if (!obj
->intern
->allocated
) {
429 rv
= php_pqconn_prepare_async(NULL
, obj
->intern
->conn
, obj
->intern
->name
, obj
->intern
->query
, obj
->intern
->params
);
431 rv
= php_pqconn_prepare(NULL
, obj
->intern
->conn
, obj
->intern
->name
, obj
->intern
->query
, obj
->intern
->params
);
435 obj
->intern
->allocated
= 1;
441 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_prepare
, 0, 0, 0)
443 static PHP_METHOD(pqstm
, prepare
)
445 php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU
, 0);
448 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_prepare_async
, 0, 0, 0)
450 static PHP_METHOD(pqstm
, prepareAsync
)
452 php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU
, 1);
455 static zend_function_entry php_pqstm_methods
[] = {
456 PHP_ME(pqstm
, __construct
, ai_pqstm_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
457 PHP_ME(pqstm
, bind
, ai_pqstm_bind
, ZEND_ACC_PUBLIC
)
458 PHP_ME(pqstm
, deallocate
, ai_pqstm_deallocate
, ZEND_ACC_PUBLIC
)
459 PHP_ME(pqstm
, deallocateAsync
, ai_pqstm_deallocate_async
, ZEND_ACC_PUBLIC
)
460 PHP_ME(pqstm
, desc
, ai_pqstm_desc
, ZEND_ACC_PUBLIC
)
461 PHP_ME(pqstm
, descAsync
, ai_pqstm_desc_async
, ZEND_ACC_PUBLIC
)
462 PHP_ME(pqstm
, exec
, ai_pqstm_exec
, ZEND_ACC_PUBLIC
)
463 PHP_ME(pqstm
, execAsync
, ai_pqstm_exec_async
, ZEND_ACC_PUBLIC
)
464 PHP_ME(pqstm
, prepare
, ai_pqstm_prepare
, ZEND_ACC_PUBLIC
)
465 PHP_ME(pqstm
, prepareAsync
, ai_pqstm_prepare_async
, ZEND_ACC_PUBLIC
)
469 PHP_MSHUTDOWN_FUNCTION(pqstm
)
471 zend_hash_destroy(&php_pqstm_object_prophandlers
);
475 PHP_MINIT_FUNCTION(pqstm
)
477 zend_class_entry ce
= {0};
478 php_pq_object_prophandler_t ph
= {0};
480 INIT_NS_CLASS_ENTRY(ce
, "pq", "Statement", php_pqstm_methods
);
481 php_pqstm_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
482 php_pqstm_class_entry
->create_object
= php_pqstm_create_object
;
484 memcpy(&php_pqstm_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
485 php_pqstm_object_handlers
.offset
= XtOffsetOf(php_pqstm_object_t
, zo
);
486 php_pqstm_object_handlers
.free_obj
= php_pqstm_object_free
;
487 php_pqstm_object_handlers
.read_property
= php_pq_object_read_prop
;
488 php_pqstm_object_handlers
.write_property
= php_pq_object_write_prop
;
489 php_pqstm_object_handlers
.clone_obj
= NULL
;
490 php_pqstm_object_handlers
.get_property_ptr_ptr
= NULL
;
491 php_pqstm_object_handlers
.get_gc
= php_pq_object_get_gc
;
492 php_pqstm_object_handlers
.get_properties
= php_pq_object_properties
;
493 php_pqstm_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
495 zend_hash_init(&php_pqstm_object_prophandlers
, 4, NULL
, php_pq_object_prophandler_dtor
, 1);
497 zend_declare_property_null(php_pqstm_class_entry
, ZEND_STRL("name"), ZEND_ACC_PUBLIC
);
498 ph
.read
= php_pqstm_object_read_name
;
499 zend_hash_str_add_mem(&php_pqstm_object_prophandlers
, "name", sizeof("name")-1, (void *) &ph
, sizeof(ph
));
501 zend_declare_property_null(php_pqstm_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
502 ph
.read
= php_pqstm_object_read_connection
;
503 ph
.gc
= php_pqstm_object_gc_connection
;
504 zend_hash_str_add_mem(&php_pqstm_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
507 zend_declare_property_null(php_pqstm_class_entry
, ZEND_STRL("query"), ZEND_ACC_PUBLIC
);
508 ph
.read
= php_pqstm_object_read_query
;
509 zend_hash_str_add_mem(&php_pqstm_object_prophandlers
, "query", sizeof("query")-1, (void *) &ph
, sizeof(ph
));
511 zend_declare_property_null(php_pqstm_class_entry
, ZEND_STRL("types"), ZEND_ACC_PUBLIC
);
512 ph
.read
= php_pqstm_object_read_types
;
513 zend_hash_str_add_mem(&php_pqstm_object_prophandlers
, "types", sizeof("types")-1, (void *) &ph
, sizeof(ph
));
523 * vim600: noet sw=4 ts=4 fdm=marker
524 * vim<600: noet sw=4 ts=4