Add deallocate() and prepare() to Statement
[m6w6/ext-pq] / src / php_pqstm.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: pq |
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 +--------------------------------------------------------------------+
11 */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <php.h>
18 #include <ext/standard/php_smart_str.h>
19
20 #include "php_pq.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"
27
28 zend_class_entry *php_pqstm_class_entry;
29 static zend_object_handlers php_pqstm_object_handlers;
30 static HashTable php_pqstm_object_prophandlers;
31
32 static void php_pqstm_deallocate(php_pqstm_object_t *obj, zend_bool async, zend_bool silent)
33 {
34 if (obj->intern->allocated) {
35 char *quoted_name = PQescapeIdentifier(obj->intern->conn->intern->conn, obj->intern->name, strlen(obj->intern->name));
36
37 if (quoted_name) {
38 smart_str cmd = {0};
39
40 smart_str_appends(&cmd, "DEALLOCATE ");
41 smart_str_appends(&cmd, quoted_name);
42 smart_str_0(&cmd);
43
44 if (async) {
45 if (PQsendQuery(obj->intern->conn->intern->conn, cmd.c)) {
46 obj->intern->conn->intern->poller = PQconsumeInput;
47 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
48 } else if (!silent) {
49 throw_exce(EX_IO TSRMLS_CC, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
50 }
51 } else {
52 PGresult *res;
53
54 if ((res = PQexec(obj->intern->conn->intern->conn, cmd.c))) {
55 PHP_PQclear(res);
56 } else if (!silent) {
57 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
58 }
59 }
60
61 PQfreemem(quoted_name);
62 smart_str_free(&cmd);
63 }
64
65 obj->intern->allocated = 0;
66 }
67 }
68
69 static void php_pqstm_object_free(void *o TSRMLS_DC)
70 {
71 php_pqstm_object_t *obj = o;
72 #if DBG_GC
73 fprintf(stderr, "FREE stm(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn);
74 #endif
75 if (obj->intern) {
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 TSRMLS_CC);
80 }
81 efree(obj->intern->name);
82 zend_hash_destroy(&obj->intern->bound);
83 if (obj->intern->params) {
84 php_pq_params_free(&obj->intern->params);
85 }
86 efree(obj->intern);
87 obj->intern = NULL;
88 }
89 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
90 efree(obj);
91 }
92
93 zend_object_value php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern, php_pqstm_object_t **ptr TSRMLS_DC)
94 {
95 php_pqstm_object_t *o;
96
97 o = ecalloc(1, sizeof(*o));
98 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
99 object_properties_init((zend_object *) o, ce);
100 o->prophandler = &php_pqstm_object_prophandlers;
101
102 if (ptr) {
103 *ptr = o;
104 }
105
106 if (intern) {
107 o->intern = intern;
108 }
109
110 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqstm_object_free, NULL TSRMLS_CC);
111 o->zv.handlers = &php_pqstm_object_handlers;
112
113 return o->zv;
114 }
115
116 static zend_object_value php_pqstm_create_object(zend_class_entry *class_type TSRMLS_DC)
117 {
118 return php_pqstm_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
119 }
120
121 static void php_pqstm_object_read_name(zval *object, void *o, zval *return_value TSRMLS_DC)
122 {
123 php_pqstm_object_t *obj = o;
124
125 RETVAL_STRING(obj->intern->name, 1);
126 }
127
128 static void php_pqstm_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
129 {
130 php_pqstm_object_t *obj = o;
131
132 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
133 }
134
135 php_pqstm_t *php_pqstm_init(php_pqconn_object_t *conn, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC)
136 {
137 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
138
139 php_pq_object_addref(conn TSRMLS_CC);
140 stm->conn = conn;
141 stm->name = estrdup(name);
142 stm->params = params;
143 stm->query = estrdup(query);
144 stm->allocated = 1;
145
146 ZEND_INIT_SYMTABLE(&stm->bound);
147
148 return stm;
149 }
150
151 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
152 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
153 ZEND_ARG_INFO(0, name)
154 ZEND_ARG_INFO(0, query)
155 ZEND_ARG_ARRAY_INFO(0, types, 1)
156 ZEND_ARG_INFO(0, async)
157 ZEND_END_ARG_INFO();
158 static PHP_METHOD(pqstm, __construct) {
159 zend_error_handling zeh;
160 zval *zconn, *ztypes = NULL;
161 char *name_str, *query_str;
162 int name_len, *query_len;
163 zend_bool async = 0;
164 STATUS rv;
165
166 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
167 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|a/!b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes, &async);
168 zend_restore_error_handling(&zeh TSRMLS_CC);
169
170 if (SUCCESS == rv) {
171 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
172 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
173
174 if (obj->intern) {
175 throw_exce(EX_BAD_METHODCALL TSRMLS_CC, "pq\\Statement already initialized");
176 } else if (!conn_obj->intern) {
177 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
178 } else {
179 php_pq_params_t *params = php_pq_params_init(&conn_obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC);
180
181 if (async) {
182 rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, params TSRMLS_CC);
183 } else {
184 rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, params TSRMLS_CC);
185 }
186
187 if (SUCCESS == rv) {
188 obj->intern = php_pqstm_init(conn_obj, name_str, query_str, params TSRMLS_CC);
189 }
190 }
191 }
192 }
193 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_bind, 0, 0, 2)
194 ZEND_ARG_INFO(0, param_no)
195 ZEND_ARG_INFO(1, param_ref)
196 ZEND_END_ARG_INFO();
197 static PHP_METHOD(pqstm, bind) {
198 long param_no;
199 zval **param_ref;
200 zend_error_handling zeh;
201 STATUS rv;
202
203 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
204 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lZ", &param_no, &param_ref);
205 zend_restore_error_handling(&zeh TSRMLS_CC);
206
207 if (SUCCESS == rv) {
208 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
209
210 if (!obj->intern) {
211 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
212 } else if (!obj->intern->allocated) {
213 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement has been deallocated");
214 } else {
215 SEPARATE_ZVAL_TO_MAKE_IS_REF(param_ref);
216 Z_ADDREF_PP(param_ref);
217 zend_hash_index_update(&obj->intern->bound, param_no, (void *) param_ref, sizeof(zval *), NULL);
218 zend_hash_sort(&obj->intern->bound, zend_qsort, php_pq_compare_index, 0 TSRMLS_CC);
219 }
220 }
221 }
222
223 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
224 ZEND_ARG_ARRAY_INFO(0, params, 1)
225 ZEND_END_ARG_INFO();
226 static PHP_METHOD(pqstm, exec) {
227 zend_error_handling zeh;
228 zval *zparams = NULL;
229 STATUS rv;
230
231 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
232 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams);
233 zend_restore_error_handling(&zeh TSRMLS_CC);
234
235 if (SUCCESS == rv) {
236 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
237
238 if (!obj->intern) {
239 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
240 } else if (!obj->intern->allocated) {
241 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement has been deallocated");
242 } else {
243 PGresult *res;
244
245 php_pq_params_set_params(obj->intern->params, zparams ? Z_ARRVAL_P(zparams) : &obj->intern->bound);
246 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);
247 php_pq_params_set_params(obj->intern->params, NULL);
248
249 if (!res) {
250 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
251 } else if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
252 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
253 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
254 }
255 }
256 }
257 }
258
259 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0)
260 ZEND_ARG_ARRAY_INFO(0, params, 1)
261 ZEND_ARG_INFO(0, callable)
262 ZEND_END_ARG_INFO();
263 static PHP_METHOD(pqstm, execAsync) {
264 zend_error_handling zeh;
265 zval *zparams = NULL;
266 php_pq_callback_t resolver = {{0}};
267 STATUS rv;
268
269 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
270 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc);
271 zend_restore_error_handling(&zeh TSRMLS_CC);
272
273 if (SUCCESS == rv) {
274 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
275
276 if (!obj->intern) {
277 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
278 } else if (!obj->intern->allocated) {
279 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement has been deallocated");
280 } else {
281 int rc;
282
283 php_pq_params_set_params(obj->intern->params, zparams ? Z_ARRVAL_P(zparams) : &obj->intern->bound);
284 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);
285 php_pq_params_set_params(obj->intern->params, NULL);
286
287 if (!rc) {
288 throw_exce(EX_IO TSRMLS_CC, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
289 #if HAVE_PQSETSINGLEROWMODE
290 } else if (obj->intern->conn->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn->intern->conn)) {
291 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
292 #endif
293 } else {
294 php_pq_callback_recurse(&obj->intern->conn->intern->onevent, &resolver TSRMLS_CC);
295 obj->intern->conn->intern->poller = PQconsumeInput;
296 }
297
298 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
299 }
300 }
301 }
302
303 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
304 ZEND_END_ARG_INFO();
305 static PHP_METHOD(pqstm, desc) {
306 zend_error_handling zeh;
307 STATUS rv;
308
309 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
310 rv = zend_parse_parameters_none();
311 zend_restore_error_handling(&zeh TSRMLS_CC);
312
313 if (SUCCESS == rv) {
314 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
315
316 if (!obj->intern) {
317 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
318 } else if (!obj->intern->allocated) {
319 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement has been deallocated");
320 } else {
321 PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name);
322
323 if (!res) {
324 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to describe statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
325 } else {
326 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
327 int p, params;
328
329 array_init(return_value);
330 for (p = 0, params = PQnparams(res); p < params; ++p) {
331 add_next_index_long(return_value, PQparamtype(res, p));
332 }
333 }
334 PHP_PQclear(res);
335 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
336 }
337 }
338 }
339 }
340
341 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc_async, 0, 0, 1)
342 ZEND_ARG_INFO(0, callable)
343 ZEND_END_ARG_INFO();
344 static PHP_METHOD(pqstm, descAsync) {
345 zend_error_handling zeh;
346 php_pq_callback_t resolver = {{0}};
347 STATUS rv;
348
349 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
350 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", &resolver.fci, &resolver.fcc);
351 zend_restore_error_handling(&zeh TSRMLS_CC);
352
353 if (SUCCESS == rv) {
354 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
355
356 if (!obj->intern) {
357 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
358 } else if (!obj->intern->allocated) {
359 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement has been deallocated");
360 } else if (!PQsendDescribePrepared(obj->intern->conn->intern->conn, obj->intern->name)) {
361 throw_exce(EX_IO TSRMLS_CC, "Failed to describe statement: %s", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
362 } else {
363 php_pq_callback_recurse(&obj->intern->conn->intern->onevent, &resolver TSRMLS_CC);
364 obj->intern->conn->intern->poller = PQconsumeInput;
365 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
366 }
367 }
368 }
369
370 static zend_always_inline void php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAMETERS, zend_bool async)
371 {
372 zend_error_handling zeh;
373 STATUS rv;
374
375 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
376 rv = zend_parse_parameters_none();
377 zend_restore_error_handling(&zeh TSRMLS_CC);
378
379 if (rv == SUCCESS) {
380 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
381
382 if (!obj->intern) {
383 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
384 } else {
385 php_pqstm_deallocate(obj, async, 0 TSRMLS_CC);
386 }
387 }
388 }
389
390 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_deallocate, 0, 0, 0)
391 ZEND_END_ARG_INFO();
392 static PHP_METHOD(pqstm, deallocate)
393 {
394 php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
395 }
396
397 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_deallocate_async, 0, 0, 0)
398 ZEND_END_ARG_INFO();
399 static PHP_METHOD(pqstm, deallocateAsync)
400 {
401 php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
402 }
403
404 static zend_always_inline void php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAMETERS, zend_bool async)
405 {
406 zend_error_handling zeh;
407 STATUS rv;
408
409 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
410 rv = zend_parse_parameters_none();
411 zend_restore_error_handling(&zeh TSRMLS_CC);
412
413 if (rv == SUCCESS) {
414 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
415
416 if (!obj->intern) {
417 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
418 } else if (!obj->intern->allocated) {
419 if (async) {
420 rv = php_pqconn_prepare_async(NULL, obj->intern->conn, obj->intern->name, obj->intern->query, obj->intern->params TSRMLS_CC);
421 } else {
422 rv = php_pqconn_prepare(NULL, obj->intern->conn, obj->intern->name, obj->intern->query, obj->intern->params TSRMLS_CC);
423 }
424
425 if (SUCCESS == rv) {
426 obj->intern->allocated = 1;
427 }
428 }
429 }
430 }
431
432 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_prepare, 0, 0, 0)
433 ZEND_END_ARG_INFO();
434 static PHP_METHOD(pqstm, prepare)
435 {
436 php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
437 }
438
439 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_prepare_async, 0, 0, 0)
440 ZEND_END_ARG_INFO();
441 static PHP_METHOD(pqstm, prepareAsync)
442 {
443 php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
444 }
445
446 static zend_function_entry php_pqstm_methods[] = {
447 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
448 PHP_ME(pqstm, bind, ai_pqstm_bind, ZEND_ACC_PUBLIC)
449 PHP_ME(pqstm, deallocate, ai_pqstm_deallocate, ZEND_ACC_PUBLIC)
450 PHP_ME(pqstm, deallocateAsync, ai_pqstm_deallocate_async, ZEND_ACC_PUBLIC)
451 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
452 PHP_ME(pqstm, descAsync, ai_pqstm_desc_async, ZEND_ACC_PUBLIC)
453 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
454 PHP_ME(pqstm, execAsync, ai_pqstm_exec_async, ZEND_ACC_PUBLIC)
455 PHP_ME(pqstm, prepare, ai_pqstm_prepare, ZEND_ACC_PUBLIC)
456 PHP_ME(pqstm, prepareAsync, ai_pqstm_prepare_async, ZEND_ACC_PUBLIC)
457 {0}
458 };
459
460 PHP_MSHUTDOWN_FUNCTION(pqstm)
461 {
462 zend_hash_destroy(&php_pqstm_object_prophandlers);
463 return SUCCESS;
464 }
465
466 PHP_MINIT_FUNCTION(pqstm)
467 {
468 zend_class_entry ce = {0};
469 php_pq_object_prophandler_t ph = {0};
470
471 INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods);
472 php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
473 php_pqstm_class_entry->create_object = php_pqstm_create_object;
474
475 memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
476 php_pqstm_object_handlers.read_property = php_pq_object_read_prop;
477 php_pqstm_object_handlers.write_property = php_pq_object_write_prop;
478 php_pqstm_object_handlers.clone_obj = NULL;
479 php_pqstm_object_handlers.get_property_ptr_ptr = NULL;
480 php_pqstm_object_handlers.get_gc = NULL;
481 php_pqstm_object_handlers.get_properties = php_pq_object_properties;
482 php_pqstm_object_handlers.get_debug_info = php_pq_object_debug_info;
483
484 zend_hash_init(&php_pqstm_object_prophandlers, 2, NULL, NULL, 1);
485
486 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
487 ph.read = php_pqstm_object_read_name;
488 zend_hash_add(&php_pqstm_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
489
490 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
491 ph.read = php_pqstm_object_read_connection;
492 zend_hash_add(&php_pqstm_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
493
494 return SUCCESS;
495 }
496
497 /*
498 * Local variables:
499 * tab-width: 4
500 * c-basic-offset: 4
501 * End:
502 * vim600: noet sw=4 ts=4 fdm=marker
503 * vim<600: noet sw=4 ts=4
504 */