test
[m6w6/ext-pq] / src / php_pqconn.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
19 #define SMART_STR_PREALLOC 256
20 #include <ext/standard/php_smart_str.h>
21
22 #include <libpq-events.h>
23 #include <fnmatch.h>
24
25 #include "php_pq.h"
26 #include "php_pq_misc.h"
27 #include "php_pq_object.h"
28 #include "php_pqexc.h"
29 #include "php_pqconn.h"
30 #include "php_pqconn_event.h"
31 #include "php_pqres.h"
32 #include "php_pqstm.h"
33 #include "php_pqtxn.h"
34
35 zend_class_entry *php_pqconn_class_entry;
36 static zend_object_handlers php_pqconn_object_handlers;
37 static HashTable php_pqconn_object_prophandlers;
38
39 /*
40 static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC)
41 {
42 zval **evhs;
43
44 if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
45 zend_hash_index_del(Z_ARRVAL_PP(evhs), id);
46 }
47 }
48 */
49
50 static ulong php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, php_pq_callback_t *cb TSRMLS_DC)
51 {
52 ulong h;
53 HashTable *evhs;
54
55 if (SUCCESS != zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
56 HashTable evh;
57
58 zend_hash_init(&evh, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
59 zend_hash_add(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(evh), (void *) &evhs);
60 }
61
62 php_pq_callback_addref(cb);
63 h = zend_hash_next_free_element(evhs);
64 zend_hash_index_update(evhs, h, (void *) cb, sizeof(*cb), NULL);
65
66 return h;
67 }
68
69 static void php_pqconn_object_free(void *o TSRMLS_DC)
70 {
71 php_pqconn_object_t *obj = o;
72 #if DBG_GC
73 fprintf(stderr, "FREE conn(#%d) %p\n", obj->zv.handle, obj);
74 #endif
75 if (obj->intern) {
76 php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn TSRMLS_CC);
77 php_resource_factory_dtor(&obj->intern->factory);
78 php_pq_callback_dtor(&obj->intern->onevent);
79 zend_hash_destroy(&obj->intern->listeners);
80 zend_hash_destroy(&obj->intern->eventhandlers);
81 efree(obj->intern);
82 obj->intern = NULL;
83 }
84 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
85 efree(obj);
86 }
87
88
89 zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern, php_pqconn_object_t **ptr TSRMLS_DC)
90 {
91 php_pqconn_object_t *o;
92
93 o = ecalloc(1, sizeof(*o));
94 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
95 object_properties_init((zend_object *) o, ce);
96 o->prophandler = &php_pqconn_object_prophandlers;
97
98 if (ptr) {
99 *ptr = o;
100 }
101
102 if (intern) {
103 o->intern = intern;
104 }
105
106 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqconn_object_free, NULL TSRMLS_CC);
107 o->zv.handlers = &php_pqconn_object_handlers;
108
109 return o->zv;
110 }
111
112 static zend_object_value php_pqconn_create_object(zend_class_entry *class_type TSRMLS_DC)
113 {
114 return php_pqconn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
115 }
116
117 static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
118 {
119 php_pqconn_object_t *obj = o;
120
121 RETVAL_LONG(PQstatus(obj->intern->conn));
122 }
123
124 static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value TSRMLS_DC)
125 {
126 php_pqconn_object_t *obj = o;
127
128 RETVAL_LONG(PQtransactionStatus(obj->intern->conn));
129 }
130
131 static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
132 {
133 php_pqconn_object_t *obj = o;
134 char *error = PHP_PQerrorMessage(obj->intern->conn);
135
136 if (error) {
137 RETVAL_STRING(error, 1);
138 } else {
139 RETVAL_NULL();
140 }
141 }
142
143 static int apply_notify_listener(void *p, void *arg TSRMLS_DC)
144 {
145 php_pq_callback_t *listener = p;
146 PGnotify *nfy = arg;
147 zval *zpid, *zchannel, *zmessage;
148
149 MAKE_STD_ZVAL(zpid);
150 ZVAL_LONG(zpid, nfy->be_pid);
151 MAKE_STD_ZVAL(zchannel);
152 ZVAL_STRING(zchannel, nfy->relname, 1);
153 MAKE_STD_ZVAL(zmessage);
154 ZVAL_STRING(zmessage, nfy->extra, 1);
155
156 zend_fcall_info_argn(&listener->fci TSRMLS_CC, 3, &zchannel, &zmessage, &zpid);
157 zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL TSRMLS_CC);
158
159 zval_ptr_dtor(&zchannel);
160 zval_ptr_dtor(&zmessage);
161 zval_ptr_dtor(&zpid);
162
163 return ZEND_HASH_APPLY_KEEP;
164 }
165
166 static int apply_notify_listeners(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
167 {
168 HashTable *listeners = p;
169 PGnotify *nfy = va_arg(argv, PGnotify *);
170
171 if (0 == fnmatch(key->arKey, nfy->relname, 0)) {
172 zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy TSRMLS_CC);
173 }
174
175 return ZEND_HASH_APPLY_KEEP;
176 }
177
178 void php_pqconn_notify_listeners(php_pqconn_object_t *obj TSRMLS_DC)
179 {
180 PGnotify *nfy;
181
182 while ((nfy = PQnotifies(obj->intern->conn))) {
183 zend_hash_apply_with_arguments(&obj->intern->listeners TSRMLS_CC, apply_notify_listeners, 1, nfy);
184 PQfreemem(nfy);
185 }
186 }
187
188 static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value TSRMLS_DC)
189 {
190 php_pqconn_object_t *obj = o;
191
192 RETVAL_BOOL(PQisBusy(obj->intern->conn));
193 }
194
195 static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value TSRMLS_DC)
196 {
197 php_pqconn_object_t *obj = o;
198
199 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn)), 1);
200 }
201
202 static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value TSRMLS_DC)
203 {
204 php_pqconn_object_t *obj = o;
205 zval *zenc = value;
206
207 if (Z_TYPE_P(value) != IS_STRING) {
208 if (Z_REFCOUNT_P(value) > 1) {
209 zval *tmp;
210 MAKE_STD_ZVAL(tmp);
211 ZVAL_ZVAL(tmp, zenc, 1, 0);
212 convert_to_string(tmp);
213 zenc = tmp;
214 } else {
215 convert_to_string_ex(&zenc);
216 }
217 }
218
219 if (0 > PQsetClientEncoding(obj->intern->conn, Z_STRVAL_P(zenc))) {
220 zend_error(E_NOTICE, "Unrecognized encoding '%s'", Z_STRVAL_P(zenc));
221 }
222
223 if (zenc != value) {
224 zval_ptr_dtor(&zenc);
225 }
226 }
227
228 static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value TSRMLS_DC)
229 {
230 php_pqconn_object_t *obj = o;
231
232 RETVAL_BOOL(obj->intern->unbuffered);
233 }
234
235 static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value TSRMLS_DC)
236 {
237 php_pqconn_object_t *obj = o;
238
239 obj->intern->unbuffered = zend_is_true(value);
240 }
241
242 static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value TSRMLS_DC)
243 {
244 php_pqconn_object_t *obj = o;
245 char *db = PQdb(obj->intern->conn);
246
247 if (db) {
248 RETVAL_STRING(db, 1);
249 } else {
250 RETVAL_EMPTY_STRING();
251 }
252 }
253
254 static void php_pqconn_object_read_user(zval *object, void *o, zval *return_value TSRMLS_DC)
255 {
256 php_pqconn_object_t *obj = o;
257 char *user = PQuser(obj->intern->conn);
258
259 if (user) {
260 RETVAL_STRING(user, 1);
261 } else {
262 RETVAL_EMPTY_STRING();
263 }
264 }
265
266 static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_value TSRMLS_DC)
267 {
268 php_pqconn_object_t *obj = o;
269 char *pass = PQpass(obj->intern->conn);
270
271 if (pass) {
272 RETVAL_STRING(pass, 1);
273 } else {
274 RETVAL_EMPTY_STRING();
275 }
276 }
277
278 static void php_pqconn_object_read_host(zval *object, void *o, zval *return_value TSRMLS_DC)
279 {
280 php_pqconn_object_t *obj = o;
281 char *host = PQhost(obj->intern->conn);
282
283 if (host) {
284 RETVAL_STRING(host, 1);
285 } else {
286 RETVAL_EMPTY_STRING();
287 }
288 }
289
290 static void php_pqconn_object_read_port(zval *object, void *o, zval *return_value TSRMLS_DC)
291 {
292 php_pqconn_object_t *obj = o;
293 char *port = PQport(obj->intern->conn);
294
295 if (port) {
296 RETVAL_STRING(port, 1);
297 } else {
298 RETVAL_EMPTY_STRING();
299 }
300 }
301
302 static void php_pqconn_object_read_options(zval *object, void *o, zval *return_value TSRMLS_DC)
303 {
304 php_pqconn_object_t *obj = o;
305 char *options = PQoptions(obj->intern->conn);
306
307 if (options) {
308 RETVAL_STRING(options, 1);
309 } else {
310 RETVAL_EMPTY_STRING();
311 }
312 }
313
314 static int apply_read_event_handler_ex(void *p, void *arg TSRMLS_DC)
315 {
316 HashTable *rv = arg;
317 zval *zcb = php_pq_callback_to_zval(p);
318
319 zend_hash_next_index_insert(rv, &zcb, sizeof(zval *), NULL);
320
321 return ZEND_HASH_APPLY_KEEP;
322 }
323
324 static int apply_read_event_handlers(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
325 {
326 HashTable *evhs = p, *rv = va_arg(argv, HashTable *);
327 zval *entry, **entry_ptr;
328
329 MAKE_STD_ZVAL(entry);
330 array_init_size(entry, zend_hash_num_elements(evhs));
331
332 if (key->nKeyLength) {
333 zend_hash_add(rv, key->arKey, key->nKeyLength, &entry, sizeof(zval *), (void *) &entry_ptr);
334 } else {
335 zend_hash_index_update(rv, key->h, &entry, sizeof(zval *), (void *) &entry_ptr);
336 }
337
338 zend_hash_apply_with_argument(evhs, apply_read_event_handler_ex, Z_ARRVAL_PP(entry_ptr) TSRMLS_CC);
339
340 return ZEND_HASH_APPLY_KEEP;
341 }
342 static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value TSRMLS_DC)
343 {
344 php_pqconn_object_t *obj = o;
345
346 array_init(return_value);
347 zend_hash_apply_with_arguments(&obj->intern->eventhandlers TSRMLS_CC, apply_read_event_handlers, 1, Z_ARRVAL_P(return_value) TSRMLS_CC);
348 }
349
350 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
351 {
352 zval *zsocket, zmember;
353 php_stream *stream;
354 STATUS retval;
355 int socket;
356
357 if (!obj) {
358 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
359 }
360
361 INIT_PZVAL(&zmember);
362 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
363 MAKE_STD_ZVAL(zsocket);
364
365 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
366 && (-1 < (socket = PQsocket(obj->intern->conn)))
367 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
368 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
369 php_stream_to_zval(stream, zsocket);
370 retval = SUCCESS;
371 } else {
372 ZVAL_NULL(zsocket);
373 retval = FAILURE;
374 }
375 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
376 zval_ptr_dtor(&zsocket);
377
378 return retval;
379 }
380
381 static void *php_pqconn_resource_factory_ctor(void *data, void *init_arg TSRMLS_DC)
382 {
383 php_pqconn_resource_factory_data_t *o = init_arg;
384 PGconn *conn = NULL;;
385
386 if (o->flags & PHP_PQCONN_ASYNC) {
387 conn = PQconnectStart(o->dsn);
388 } else {
389 conn = PQconnectdb(o->dsn);
390 }
391
392 if (conn) {
393 PQregisterEventProc(conn, php_pqconn_event, "ext-pq", NULL);
394 }
395
396 return conn;
397 }
398
399 static void php_pqconn_resource_factory_dtor(void *opaque, void *handle TSRMLS_DC)
400 {
401 php_pqconn_event_data_t *evdata = PQinstanceData(handle, php_pqconn_event);
402
403 /* we don't care for anything, except free'ing evdata */
404 if (evdata) {
405 PQsetInstanceData(handle, php_pqconn_event, NULL);
406 memset(evdata, 0, sizeof(*evdata));
407 efree(evdata);
408 }
409
410 PQfinish(handle);
411 }
412
413 static php_resource_factory_ops_t php_pqconn_resource_factory_ops = {
414 php_pqconn_resource_factory_ctor,
415 NULL,
416 php_pqconn_resource_factory_dtor
417 };
418
419 php_resource_factory_ops_t *php_pqconn_get_resource_factory_ops(void)
420 {
421 return &php_pqconn_resource_factory_ops;
422 }
423
424 static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC)
425 {
426 // FIXME: ping server
427 }
428
429 static int apply_unlisten(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
430 {
431 php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
432 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, key->arKey, key->nKeyLength - 1);
433
434 if (quoted_channel) {
435 PGresult *res;
436 char *cmd;
437
438 spprintf(&cmd, 0, "UNLISTEN %s", quoted_channel);
439 if ((res = PQexec(obj->intern->conn, cmd))) {
440 PHP_PQclear(res);
441 }
442
443 efree(cmd);
444 PQfreemem(quoted_channel);
445 }
446
447 return ZEND_HASH_APPLY_REMOVE;
448 }
449
450 static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC)
451 {
452 php_pqconn_event_data_t *evdata = PQinstanceData(*handle, php_pqconn_event);
453 PGcancel *cancel;
454 PGresult *res;
455
456 /* go away */
457 PQsetInstanceData(*handle, php_pqconn_event, NULL);
458
459 /* ignore notices */
460 PQsetNoticeReceiver(*handle, php_pqconn_notice_ignore, NULL);
461
462 /* cancel async queries */
463 if (PQisBusy(*handle) && (cancel = PQgetCancel(*handle))) {
464 char err[256] = {0};
465
466 PQcancel(cancel, err, sizeof(err));
467 PQfreeCancel(cancel);
468 }
469 /* clean up async results */
470 while ((res = PQgetResult(*handle))) {
471 PHP_PQclear(res);
472 }
473
474 /* clean up transaction & session */
475 switch (PQtransactionStatus(*handle)) {
476 case PQTRANS_IDLE:
477 res = PQexec(*handle, "RESET ALL");
478 break;
479 default:
480 res = PQexec(*handle, "ROLLBACK; RESET ALL");
481 break;
482 }
483
484 if (res) {
485 PHP_PQclear(res);
486 }
487
488 if (evdata) {
489 /* clean up notify listeners */
490 zend_hash_apply_with_arguments(&evdata->obj->intern->listeners TSRMLS_CC, apply_unlisten, 1, evdata->obj);
491
492 /* release instance data */
493 memset(evdata, 0, sizeof(*evdata));
494 efree(evdata);
495 }
496 }
497
498 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
499 ZEND_ARG_INFO(0, dsn)
500 ZEND_ARG_INFO(0, async)
501 ZEND_END_ARG_INFO();
502 static PHP_METHOD(pqconn, __construct) {
503 zend_error_handling zeh;
504 char *dsn_str = "";
505 int dsn_len = 0;
506 long flags = 0;
507 STATUS rv;
508
509 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
510 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &dsn_str, &dsn_len, &flags);
511 zend_restore_error_handling(&zeh TSRMLS_CC);
512
513 if (SUCCESS == rv) {
514 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
515
516 if (obj->intern) {
517 throw_exce(EX_BAD_METHODCALL TSRMLS_CC, "pq\\Connection already initialized");
518 } else {
519 php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj TSRMLS_CC);
520 php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags};
521
522 obj->intern = ecalloc(1, sizeof(*obj->intern));
523
524 zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
525 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
526
527 if (flags & PHP_PQCONN_PERSISTENT) {
528 php_persistent_handle_factory_t *phf = php_persistent_handle_concede(NULL, ZEND_STRL("pq\\Connection"), dsn_str, dsn_len, php_pqconn_wakeup, php_pqconn_retire TSRMLS_CC);
529 php_resource_factory_init(&obj->intern->factory, php_persistent_handle_get_resource_factory_ops(), phf, (void (*)(void*)) php_persistent_handle_abandon);
530 } else {
531 php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL);
532 }
533
534 if (flags & PHP_PQCONN_ASYNC) {
535 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
536 }
537
538 obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata TSRMLS_CC);
539
540 PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata);
541 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata);
542
543 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
544 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn));
545 }
546 }
547 }
548 }
549
550 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
551 ZEND_END_ARG_INFO();
552 static PHP_METHOD(pqconn, reset) {
553 zend_error_handling zeh;
554 STATUS rv;
555
556 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
557 rv = zend_parse_parameters_none();
558 zend_restore_error_handling(&zeh TSRMLS_CC);
559
560 if (SUCCESS == rv) {
561 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
562
563 if (!obj->intern) {
564 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
565 } else {
566 PQreset(obj->intern->conn);
567
568 if (CONNECTION_OK != PQstatus(obj->intern->conn)) {
569 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn));
570 }
571
572 php_pqconn_notify_listeners(obj TSRMLS_CC);
573 }
574 }
575 }
576
577 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
578 ZEND_END_ARG_INFO();
579 static PHP_METHOD(pqconn, resetAsync) {
580 zend_error_handling zeh;
581 STATUS rv;
582
583 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
584 rv = zend_parse_parameters_none();
585 zend_restore_error_handling(&zeh TSRMLS_CC);
586
587 if (SUCCESS == rv) {
588 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
589
590 if (!obj->intern) {
591 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
592 } else {
593 if (!PQresetStart(obj->intern->conn)) {
594 throw_exce(EX_IO TSRMLS_CC, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn));
595 } else {
596 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
597 }
598
599 php_pqconn_notify_listeners(obj TSRMLS_CC);
600 }
601 }
602 }
603
604 static void php_pqconn_add_listener(php_pqconn_object_t *obj, const char *channel_str, size_t channel_len, php_pq_callback_t *listener TSRMLS_DC)
605 {
606 HashTable ht, *existing_listeners;
607
608 php_pq_callback_addref(listener);
609
610 if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
611 zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
612 } else {
613 zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
614 zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
615 zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
616 }
617 }
618
619 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
620 ZEND_ARG_INFO(0, channel)
621 ZEND_ARG_INFO(0, callable)
622 ZEND_END_ARG_INFO();
623 static PHP_METHOD(pqconn, listen) {
624 zend_error_handling zeh;
625 char *channel_str = NULL;
626 int channel_len = 0;
627 php_pq_callback_t listener;
628 STATUS rv;
629
630 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
631 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
632 zend_restore_error_handling(&zeh TSRMLS_CC);
633
634 if (SUCCESS == rv) {
635 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
636
637 if (!obj->intern) {
638 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
639 } else {
640 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
641
642 if (!quoted_channel) {
643 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
644 } else {
645 PGresult *res;
646 smart_str cmd = {0};
647
648 smart_str_appends(&cmd, "LISTEN ");
649 smart_str_appends(&cmd, quoted_channel);
650 smart_str_0(&cmd);
651
652 res = PQexec(obj->intern->conn, cmd.c);
653
654 smart_str_free(&cmd);
655 PQfreemem(quoted_channel);
656
657 if (!res) {
658 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
659 } else {
660 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
661 obj->intern->poller = PQconsumeInput;
662 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
663 }
664 PHP_PQclear(res);
665 }
666
667 php_pqconn_notify_listeners(obj TSRMLS_CC);
668 }
669 }
670 }
671 }
672
673 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async, 0, 0, 0)
674 ZEND_ARG_INFO(0, channel)
675 ZEND_ARG_INFO(0, callable)
676 ZEND_END_ARG_INFO();
677 static PHP_METHOD(pqconn, listenAsync) {
678 zend_error_handling zeh;
679 char *channel_str = NULL;
680 int channel_len = 0;
681 php_pq_callback_t listener;
682 STATUS rv;
683
684 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
685 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
686 zend_restore_error_handling(&zeh TSRMLS_CC);
687
688 if (SUCCESS == rv) {
689 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
690
691 if (!obj->intern) {
692 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
693 } else {
694 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
695
696 if (!quoted_channel) {
697 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
698 } else {
699 smart_str cmd = {0};
700
701 smart_str_appends(&cmd, "LISTEN ");
702 smart_str_appends(&cmd, quoted_channel);
703 smart_str_0(&cmd);
704
705 if (!PQsendQuery(obj->intern->conn, cmd.c)) {
706 throw_exce(EX_IO TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
707 } else {
708 obj->intern->poller = PQconsumeInput;
709 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
710 }
711
712 smart_str_free(&cmd);
713 PQfreemem(quoted_channel);
714 php_pqconn_notify_listeners(obj TSRMLS_CC);
715 }
716 }
717 }
718 }
719
720 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
721 ZEND_ARG_INFO(0, channel)
722 ZEND_ARG_INFO(0, message)
723 ZEND_END_ARG_INFO();
724 static PHP_METHOD(pqconn, notify) {
725 zend_error_handling zeh;
726 char *channel_str, *message_str;
727 int channel_len, message_len;
728 STATUS rv;
729
730 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
731 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len);
732 zend_restore_error_handling(&zeh TSRMLS_CC);
733
734 if (SUCCESS == rv) {
735 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
736
737 if (!obj->intern) {
738 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
739 } else {
740 PGresult *res;
741 char *params[2] = {channel_str, message_str};
742
743 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
744
745 if (!res) {
746 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
747 } else {
748 php_pqres_success(res TSRMLS_CC);
749 PHP_PQclear(res);
750 }
751
752 php_pqconn_notify_listeners(obj TSRMLS_CC);
753 }
754 }
755 }
756
757 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async, 0, 0, 2)
758 ZEND_ARG_INFO(0, channel)
759 ZEND_ARG_INFO(0, message)
760 ZEND_END_ARG_INFO();
761 static PHP_METHOD(pqconn, notifyAsync) {
762 zend_error_handling zeh;
763 char *channel_str, *message_str;
764 int channel_len, message_len;
765 STATUS rv;
766
767 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
768 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len);
769 zend_restore_error_handling(&zeh TSRMLS_CC);
770
771 if (SUCCESS == rv) {
772 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
773
774 if (!obj->intern) {
775 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
776 } else {
777 char *params[2] = {channel_str, message_str};
778
779 if (!PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) {
780 throw_exce(EX_IO TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
781 } else {
782 obj->intern->poller = PQconsumeInput;
783 }
784
785 php_pqconn_notify_listeners(obj TSRMLS_CC);
786 }
787 }
788 }
789
790 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
791 ZEND_END_ARG_INFO();
792 static PHP_METHOD(pqconn, poll) {
793 zend_error_handling zeh;
794 STATUS rv;
795
796 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
797 rv = zend_parse_parameters_none();
798 zend_restore_error_handling(&zeh TSRMLS_CC);
799
800 if (SUCCESS == rv) {
801 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
802
803 if (!obj->intern) {
804 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
805 } else if (!obj->intern->poller) {
806 throw_exce(EX_RUNTIME TSRMLS_CC, "No asynchronous operation active");
807 } else {
808 if (obj->intern->poller == PQconsumeInput) {
809 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
810 } else {
811 RETVAL_LONG(obj->intern->poller(obj->intern->conn));
812 }
813 php_pqconn_notify_listeners(obj TSRMLS_CC);
814 }
815 }
816 }
817
818 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
819 ZEND_ARG_INFO(0, query)
820 ZEND_END_ARG_INFO();
821 static PHP_METHOD(pqconn, exec) {
822 zend_error_handling zeh;
823 char *query_str;
824 int query_len;
825 STATUS rv;
826
827 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
828 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len);
829 zend_restore_error_handling(&zeh TSRMLS_CC);
830
831 if (SUCCESS == rv) {
832 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
833
834 if (!obj->intern) {
835 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
836 } else {
837 PGresult *res = PQexec(obj->intern->conn, query_str);
838
839 if (!res) {
840 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
841 } else if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
842 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
843 } else {
844 PHP_PQclear(res);
845 }
846
847 php_pqconn_notify_listeners(obj TSRMLS_CC);
848 }
849 }
850 }
851
852 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
853 ZEND_END_ARG_INFO();
854 static PHP_METHOD(pqconn, getResult) {
855 zend_error_handling zeh;
856 STATUS rv;
857
858 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
859 rv = zend_parse_parameters_none();
860 zend_restore_error_handling(&zeh TSRMLS_CC);
861
862 if (SUCCESS == rv) {
863 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
864
865 if (!obj->intern) {
866 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
867 } else {
868 PGresult *res = PQgetResult(obj->intern->conn);
869
870 if (!res) {
871 RETVAL_NULL();
872 } else {
873 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
874 }
875
876 php_pqconn_notify_listeners(obj TSRMLS_CC);
877 }
878 }
879 }
880
881 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
882 ZEND_ARG_INFO(0, query)
883 ZEND_ARG_INFO(0, callable)
884 ZEND_END_ARG_INFO();
885 static PHP_METHOD(pqconn, execAsync) {
886 zend_error_handling zeh;
887 php_pq_callback_t resolver = {{0}};
888 char *query_str;
889 int query_len;
890 STATUS rv;
891
892 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
893 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc);
894 zend_restore_error_handling(&zeh TSRMLS_CC);
895
896 if (SUCCESS == rv) {
897 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
898
899 if (!obj->intern) {
900 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
901 } else if (!PQsendQuery(obj->intern->conn, query_str)) {
902 throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
903 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
904 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
905 } else {
906 obj->intern->poller = PQconsumeInput;
907 php_pq_callback_dtor(&obj->intern->onevent);
908 if (resolver.fci.size > 0) {
909 obj->intern->onevent = resolver;
910 php_pq_callback_addref(&obj->intern->onevent);
911 }
912 php_pqconn_notify_listeners(obj TSRMLS_CC);
913 }
914 }
915 }
916
917 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
918 ZEND_ARG_INFO(0, query)
919 ZEND_ARG_ARRAY_INFO(0, params, 0)
920 ZEND_ARG_ARRAY_INFO(0, types, 1)
921 ZEND_END_ARG_INFO();
922 static PHP_METHOD(pqconn, execParams) {
923 zend_error_handling zeh;
924 char *query_str;
925 int query_len;
926 zval *zparams;
927 zval *ztypes = NULL;
928 STATUS rv;
929
930 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
931 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes);
932 zend_restore_error_handling(&zeh TSRMLS_CC);
933
934 if (SUCCESS == rv) {
935 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
936
937 if (!obj->intern) {
938 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
939 } else {
940 PGresult *res;
941 int count;
942 Oid *types = NULL;
943 char **params = NULL;
944 HashTable zdtor;
945
946 ZEND_INIT_SYMTABLE(&zdtor);
947 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
948
949 if (ztypes) {
950 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
951 }
952
953 res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
954
955 zend_hash_destroy(&zdtor);
956 if (types) {
957 efree(types);
958 }
959 if (params) {
960 efree(params);
961 }
962
963 if (!res) {
964 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
965 } else {
966 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
967 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
968 } else {
969 PHP_PQclear(res);
970 }
971
972 php_pqconn_notify_listeners(obj TSRMLS_CC);
973 }
974 }
975 }
976 }
977
978 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
979 ZEND_ARG_INFO(0, query)
980 ZEND_ARG_ARRAY_INFO(0, params, 0)
981 ZEND_ARG_ARRAY_INFO(0, types, 1)
982 ZEND_ARG_INFO(0, callable)
983 ZEND_END_ARG_INFO();
984 static PHP_METHOD(pqconn, execParamsAsync) {
985 zend_error_handling zeh;
986 php_pq_callback_t resolver = {{0}};
987 char *query_str;
988 int query_len;
989 zval *zparams;
990 zval *ztypes = NULL;
991 STATUS rv;
992
993 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
994 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc);
995 zend_restore_error_handling(&zeh TSRMLS_CC);
996
997 if (SUCCESS == rv) {
998 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
999
1000 if (!obj->intern) {
1001 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1002 } else {
1003 int count;
1004 Oid *types = NULL;
1005 char **params = NULL;
1006 HashTable zdtor;
1007
1008 ZEND_INIT_SYMTABLE(&zdtor);
1009 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
1010
1011 if (ztypes) {
1012 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
1013 }
1014
1015 if (!PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) {
1016 throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
1017 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1018 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1019 } else {
1020 obj->intern->poller = PQconsumeInput;
1021 php_pq_callback_dtor(&obj->intern->onevent);
1022 if (resolver.fci.size > 0) {
1023 obj->intern->onevent = resolver;
1024 php_pq_callback_addref(&obj->intern->onevent);
1025 }
1026 php_pqconn_notify_listeners(obj TSRMLS_CC);
1027 }
1028
1029 zend_hash_destroy(&zdtor);
1030 if (types) {
1031 efree(types);
1032 }
1033 if (params) {
1034 efree(params);
1035 }
1036 }
1037 }
1038 zend_restore_error_handling(&zeh TSRMLS_CC);
1039 }
1040
1041 STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
1042 {
1043 Oid *types = NULL;
1044 int count = 0;
1045 PGresult *res;
1046 STATUS rv;
1047
1048 if (!obj) {
1049 obj = zend_object_store_get_object(object TSRMLS_CC);
1050 }
1051
1052 if (typest) {
1053 count = zend_hash_num_elements(typest);
1054 php_pq_types_to_array(typest, &types TSRMLS_CC);
1055 }
1056
1057 res = PQprepare(obj->intern->conn, name, query, count, types);
1058
1059 if (types) {
1060 efree(types);
1061 }
1062
1063 if (!res) {
1064 rv = FAILURE;
1065 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
1066 } else {
1067 rv = php_pqres_success(res TSRMLS_CC);
1068 PHP_PQclear(res);
1069 php_pqconn_notify_listeners(obj TSRMLS_CC);
1070 }
1071
1072 return rv;
1073 }
1074
1075 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
1076 ZEND_ARG_INFO(0, type)
1077 ZEND_ARG_INFO(0, query)
1078 ZEND_ARG_ARRAY_INFO(0, types, 1)
1079 ZEND_END_ARG_INFO();
1080 static PHP_METHOD(pqconn, prepare) {
1081 zend_error_handling zeh;
1082 zval *ztypes = NULL;
1083 char *name_str, *query_str;
1084 int name_len, *query_len;
1085 STATUS rv;
1086
1087 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1088 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
1089 zend_restore_error_handling(&zeh TSRMLS_CC);
1090
1091 if (SUCCESS == rv) {
1092 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1093
1094 if (!obj->intern) {
1095 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1096 } else if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1097 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1098
1099 php_pq_object_addref(obj TSRMLS_CC);
1100 stm->conn = obj;
1101 stm->name = estrdup(name_str);
1102 ZEND_INIT_SYMTABLE(&stm->bound);
1103
1104 return_value->type = IS_OBJECT;
1105 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1106 }
1107 }
1108 }
1109
1110 STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
1111 {
1112 STATUS rv;
1113 int count;
1114 Oid *types = NULL;
1115
1116 if (!obj) {
1117 obj = zend_object_store_get_object(object TSRMLS_CC);
1118 }
1119
1120 if (typest) {
1121 count = php_pq_types_to_array(typest, &types TSRMLS_CC);
1122 }
1123
1124 if (!PQsendPrepare(obj->intern->conn, name, query, count, types)) {
1125 rv = FAILURE;
1126 throw_exce(EX_IO TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
1127 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1128 rv = FAILURE;
1129 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1130 } else {
1131 rv = SUCCESS;
1132 obj->intern->poller = PQconsumeInput;
1133 php_pqconn_notify_listeners(obj TSRMLS_CC);
1134 }
1135
1136 if (types) {
1137 efree(types);
1138 }
1139
1140 return rv;
1141 }
1142
1143 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
1144 ZEND_ARG_INFO(0, type)
1145 ZEND_ARG_INFO(0, query)
1146 ZEND_ARG_ARRAY_INFO(0, types, 1)
1147 ZEND_END_ARG_INFO();
1148 static PHP_METHOD(pqconn, prepareAsync) {
1149 zend_error_handling zeh;
1150 zval *ztypes = NULL;
1151 char *name_str, *query_str;
1152 int name_len, *query_len;
1153 STATUS rv;
1154
1155 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1156 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
1157 zend_restore_error_handling(&zeh TSRMLS_CC);
1158
1159 if (SUCCESS == rv) {
1160 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1161
1162 if (!obj->intern) {
1163 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1164 } else if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1165 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1166
1167 php_pq_object_addref(obj TSRMLS_CC);
1168 stm->conn = obj;
1169 stm->name = estrdup(name_str);
1170 ZEND_INIT_SYMTABLE(&stm->bound);
1171
1172 return_value->type = IS_OBJECT;
1173 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1174 }
1175 }
1176 }
1177
1178 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
1179 ZEND_ARG_INFO(0, string)
1180 ZEND_END_ARG_INFO();
1181 static PHP_METHOD(pqconn, quote) {
1182 char *str;
1183 int len;
1184
1185 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1186 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1187
1188 if (!obj->intern) {
1189 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1190 } else {
1191 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
1192
1193 if (!quoted) {
1194 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote string (%s)", PHP_PQerrorMessage(obj->intern->conn));
1195 RETVAL_FALSE;
1196 } else {
1197 RETVAL_STRING(quoted, 1);
1198 PQfreemem(quoted);
1199 }
1200 }
1201 }
1202 }
1203
1204 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
1205 ZEND_ARG_INFO(0, type)
1206 ZEND_END_ARG_INFO();
1207 static PHP_METHOD(pqconn, quoteName) {
1208 char *str;
1209 int len;
1210
1211 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1212 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1213
1214 if (!obj->intern) {
1215 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1216 } else {
1217 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
1218
1219 if (!quoted) {
1220 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote name (%s)", PHP_PQerrorMessage(obj->intern->conn));
1221 RETVAL_FALSE;
1222 } else {
1223 RETVAL_STRING(quoted, 1);
1224 PQfreemem(quoted);
1225 }
1226 }
1227 }
1228 }
1229
1230 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
1231 ZEND_ARG_INFO(0, bytea)
1232 ZEND_END_ARG_INFO();
1233 static PHP_METHOD(pqconn, escapeBytea) {
1234 char *str;
1235 int len;
1236
1237 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1238 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1239
1240 if (!obj->intern) {
1241 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1242 } else {
1243 size_t escaped_len;
1244 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
1245
1246 if (!escaped_str) {
1247 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
1248 RETVAL_FALSE;
1249 } else {
1250 RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
1251 PQfreemem(escaped_str);
1252 }
1253 }
1254 }
1255 }
1256
1257 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
1258 ZEND_ARG_INFO(0, bytea)
1259 ZEND_END_ARG_INFO();
1260 static PHP_METHOD(pqconn, unescapeBytea) {
1261 char *str;
1262 int len;
1263
1264 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1265 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1266
1267 if (!obj->intern) {
1268 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1269 } else {
1270 size_t unescaped_len;
1271 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
1272
1273 if (!unescaped_str) {
1274 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
1275 RETVAL_FALSE;
1276 } else {
1277 RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
1278 PQfreemem(unescaped_str);
1279 }
1280 }
1281 }
1282 }
1283
1284 STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
1285 {
1286 STATUS rv = FAILURE;
1287
1288 if (!conn_obj) {
1289 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
1290 }
1291
1292 if (!conn_obj->intern) {
1293 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1294 } else {
1295 PGresult *res;
1296 smart_str cmd = {0};
1297 const char *il = isolation_level(&isolation);
1298
1299 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
1300 smart_str_appends(&cmd, il);
1301 smart_str_appends(&cmd, ", READ ");
1302 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
1303 smart_str_appends(&cmd, ",");
1304 smart_str_appends(&cmd, deferrable ? "" : " NOT");
1305 smart_str_appends(&cmd, " DEFERRABLE");
1306 smart_str_0(&cmd);
1307
1308 res = PQexec(conn_obj->intern->conn, cmd.c);
1309
1310 if (!res) {
1311 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
1312 } else {
1313 rv = php_pqres_success(res TSRMLS_CC);
1314 PHP_PQclear(res);
1315 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
1316 }
1317
1318 smart_str_free(&cmd);
1319 }
1320
1321 return rv;
1322 }
1323
1324 STATUS php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
1325 {
1326 STATUS rv = FAILURE;
1327
1328 if (!conn_obj) {
1329 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
1330 }
1331
1332 if (!conn_obj->intern) {
1333 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1334 } else {
1335 smart_str cmd = {0};
1336 const char *il = isolation_level(&isolation);
1337
1338 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
1339 smart_str_appends(&cmd, il);
1340 smart_str_appends(&cmd, ", READ ");
1341 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
1342 smart_str_appends(&cmd, ",");
1343 smart_str_appends(&cmd, deferrable ? "" : "NOT ");
1344 smart_str_appends(&cmd, " DEFERRABLE");
1345 smart_str_0(&cmd);
1346
1347 if (!PQsendQuery(conn_obj->intern->conn, cmd.c)) {
1348 throw_exce(EX_IO TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
1349 } else {
1350 rv = SUCCESS;
1351 conn_obj->intern->poller = PQconsumeInput;
1352 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
1353 }
1354
1355 smart_str_free(&cmd);
1356 }
1357
1358 return rv;
1359 }
1360
1361 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
1362 ZEND_ARG_INFO(0, isolation)
1363 ZEND_ARG_INFO(0, readonly)
1364 ZEND_ARG_INFO(0, deferrable)
1365 ZEND_END_ARG_INFO();
1366 static PHP_METHOD(pqconn, startTransaction) {
1367 zend_error_handling zeh;
1368 long isolation = PHP_PQTXN_READ_COMMITTED;
1369 zend_bool readonly = 0, deferrable = 0;
1370 STATUS rv;
1371
1372 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1373 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable);
1374 zend_restore_error_handling(&zeh TSRMLS_CC);
1375
1376 if (SUCCESS == rv) {
1377 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1378
1379 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
1380
1381 if (SUCCESS == rv) {
1382 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
1383
1384 php_pq_object_addref(obj TSRMLS_CC);
1385 txn->conn = obj;
1386 txn->open = 1;
1387 txn->isolation = isolation;
1388 txn->readonly = readonly;
1389 txn->deferrable = deferrable;
1390
1391 return_value->type = IS_OBJECT;
1392 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
1393 }
1394 }
1395 }
1396
1397 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
1398 ZEND_ARG_INFO(0, isolation)
1399 ZEND_ARG_INFO(0, readonly)
1400 ZEND_ARG_INFO(0, deferrable)
1401 ZEND_END_ARG_INFO();
1402 static PHP_METHOD(pqconn, startTransactionAsync) {
1403 zend_error_handling zeh;
1404 long isolation = PHP_PQTXN_READ_COMMITTED;
1405 zend_bool readonly = 0, deferrable = 0;
1406 STATUS rv;
1407
1408 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1409 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable);
1410 zend_restore_error_handling(&zeh TSRMLS_CC);
1411 if (SUCCESS == rv) {
1412 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1413
1414 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
1415
1416 if (SUCCESS == rv) {
1417 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
1418
1419 php_pq_object_addref(obj TSRMLS_CC);
1420 txn->conn = obj;
1421 txn->isolation = isolation;
1422 txn->readonly = readonly;
1423 txn->deferrable = deferrable;
1424
1425 return_value->type = IS_OBJECT;
1426 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
1427 }
1428 }
1429 }
1430
1431 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
1432 ZEND_ARG_INFO(0, stdio_stream)
1433 ZEND_END_ARG_INFO();
1434 static PHP_METHOD(pqconn, trace) {
1435 zval *zstream = NULL;
1436
1437 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) {
1438 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1439
1440 if (!obj->intern) {
1441 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1442 } else {
1443 if (!zstream) {
1444 PQuntrace(obj->intern->conn);
1445 RETVAL_TRUE;
1446 } else {
1447 FILE *fp;
1448 php_stream *stream = NULL;
1449
1450 php_stream_from_zval(stream, &zstream);
1451
1452 if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
1453 RETVAL_FALSE;
1454 } else {
1455 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
1456 PQtrace(obj->intern->conn, fp);
1457 RETVAL_TRUE;
1458 }
1459 }
1460 }
1461 }
1462 }
1463
1464 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_on, 0, 0, 2)
1465 ZEND_ARG_INFO(0, type)
1466 ZEND_ARG_INFO(0, callable)
1467 ZEND_END_ARG_INFO();
1468 static PHP_METHOD(pqconn, on) {
1469 zend_error_handling zeh;
1470 char *type_str;
1471 int type_len;
1472 php_pq_callback_t cb;
1473 STATUS rv;
1474
1475 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1476 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &type_str, &type_len, &cb.fci, &cb.fcc);
1477 zend_restore_error_handling(&zeh TSRMLS_CC);
1478
1479 if (SUCCESS == rv) {
1480 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1481
1482 if (!obj->intern) {
1483 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1484 } else {
1485 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1486
1487 RETVAL_LONG(php_pqconn_add_eventhandler(obj, type_str, type_len, &cb TSRMLS_CC));
1488 }
1489 }
1490 }
1491
1492 static zend_function_entry php_pqconn_methods[] = {
1493 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1494 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
1495 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
1496 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
1497 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
1498 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
1499 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
1500 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
1501 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
1502 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
1503 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
1504 PHP_ME(pqconn, listenAsync, ai_pqconn_listen_async, ZEND_ACC_PUBLIC)
1505 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
1506 PHP_ME(pqconn, notifyAsync, ai_pqconn_notify_async, ZEND_ACC_PUBLIC)
1507 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
1508 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
1509 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
1510 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
1511 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
1512 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
1513 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
1514 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
1515 PHP_ME(pqconn, on, ai_pqconn_on, ZEND_ACC_PUBLIC)
1516 {0}
1517 };
1518
1519 PHP_MINIT_FUNCTION(pqconn)
1520 {
1521 zend_class_entry ce = {0};
1522 php_pq_object_prophandler_t ph = {0};
1523
1524 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
1525 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1526 php_pqconn_class_entry->create_object = php_pqconn_create_object;
1527
1528 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1529 php_pqconn_object_handlers.read_property = php_pq_object_read_prop;
1530 php_pqconn_object_handlers.write_property = php_pq_object_write_prop;
1531 php_pqconn_object_handlers.clone_obj = NULL;
1532 php_pqconn_object_handlers.get_property_ptr_ptr = NULL;
1533 php_pqconn_object_handlers.get_gc = NULL;
1534 php_pqconn_object_handlers.get_properties = php_pq_object_properties;
1535 php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info;
1536
1537 zend_hash_init(&php_pqconn_object_prophandlers, 14, NULL, NULL, 1);
1538
1539 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
1540 ph.read = php_pqconn_object_read_status;
1541 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1542
1543 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
1544 ph.read = php_pqconn_object_read_transaction_status;
1545 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
1546
1547 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
1548 ph.read = NULL; /* forward to std prophandler */
1549 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
1550
1551 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1552 ph.read = php_pqconn_object_read_error_message;
1553 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1554
1555 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1556 ph.read = php_pqconn_object_read_busy;
1557 zend_hash_add(&php_pqconn_object_prophandlers, "busy", sizeof("busy"), (void *) &ph, sizeof(ph), NULL);
1558
1559 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC TSRMLS_CC);
1560 ph.read = php_pqconn_object_read_encoding;
1561 ph.write = php_pqconn_object_write_encoding;
1562 zend_hash_add(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding"), (void *) &ph, sizeof(ph), NULL);
1563 ph.write = NULL;
1564
1565 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1566 ph.read = php_pqconn_object_read_unbuffered;
1567 ph.write = php_pqconn_object_write_unbuffered;
1568 zend_hash_add(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered"), (void *) &ph, sizeof(ph), NULL);
1569 ph.write = NULL;
1570
1571 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC TSRMLS_CC);
1572 ph.read = php_pqconn_object_read_db;
1573 zend_hash_add(&php_pqconn_object_prophandlers, "db", sizeof("db"), (void *) &ph, sizeof(ph), NULL);
1574
1575 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC);
1576 ph.read = php_pqconn_object_read_user;
1577 zend_hash_add(&php_pqconn_object_prophandlers, "user", sizeof("user"), (void *) &ph, sizeof(ph), NULL);
1578
1579 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC);
1580 ph.read = php_pqconn_object_read_pass;
1581 zend_hash_add(&php_pqconn_object_prophandlers, "pass", sizeof("pass"), (void *) &ph, sizeof(ph), NULL);
1582
1583 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
1584 ph.read = php_pqconn_object_read_host;
1585 zend_hash_add(&php_pqconn_object_prophandlers, "host", sizeof("host"), (void *) &ph, sizeof(ph), NULL);
1586
1587 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC);
1588 ph.read = php_pqconn_object_read_port;
1589 zend_hash_add(&php_pqconn_object_prophandlers, "port", sizeof("port"), (void *) &ph, sizeof(ph), NULL);
1590
1591 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC TSRMLS_CC);
1592 ph.read = php_pqconn_object_read_options;
1593 zend_hash_add(&php_pqconn_object_prophandlers, "options", sizeof("options"), (void *) &ph, sizeof(ph), NULL);
1594
1595 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC TSRMLS_CC);
1596 ph.read = php_pqconn_object_read_event_handlers;
1597 zend_hash_add(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers"), (void *) &ph, sizeof(ph), NULL);
1598
1599 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
1600 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
1601 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
1602 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
1603 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
1604 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
1605 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
1606 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
1607
1608 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
1609 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
1610 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
1611 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
1612 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
1613
1614 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
1615 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
1616 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
1617 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
1618
1619 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_NOTICE"), ZEND_STRL("notice") TSRMLS_CC);
1620 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESULT"), ZEND_STRL("result") TSRMLS_CC);
1621 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESET"), ZEND_STRL("reset") TSRMLS_CC);
1622
1623 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("ASYNC"), 0x1 TSRMLS_CC);
1624 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("PERSISTENT"), 0x2 TSRMLS_CC);
1625
1626 return SUCCESS;
1627 }
1628
1629 /*
1630 * Local variables:
1631 * tab-width: 4
1632 * c-basic-offset: 4
1633 * End:
1634 * vim600: noet sw=4 ts=4 fdm=marker
1635 * vim<600: noet sw=4 ts=4
1636 */