Merge branch 'v1.1.x'
[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 #include <Zend/zend_smart_str.h>
19
20 #include <libpq-events.h>
21 #include <fnmatch.h>
22
23 #include "php_pq.h"
24 #include "php_pq_misc.h"
25 #include "php_pq_object.h"
26 #include "php_pqexc.h"
27 #include "php_pqconn.h"
28 #include "php_pqconn_event.h"
29 #include "php_pqres.h"
30 #include "php_pqstm.h"
31 #include "php_pqtxn.h"
32 #include "php_pqcur.h"
33
34 zend_class_entry *php_pqconn_class_entry;
35 static zend_object_handlers php_pqconn_object_handlers;
36 static HashTable php_pqconn_object_prophandlers;
37
38 static void php_pq_callback_hash_dtor(zval *p)
39 {
40 php_pq_callback_dtor(Z_PTR_P(p));
41 efree(Z_PTR_P(p));
42 }
43
44 /*
45 static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id)
46 {
47 zval **evhs;
48
49 if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
50 zend_hash_index_del(Z_ARRVAL_PP(evhs), id);
51 }
52 }
53 */
54
55 static zend_long php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, php_pq_callback_t *cb)
56 {
57 zend_long h;
58 zval *zevhs;
59
60 if (!(zevhs = zend_hash_str_find(&obj->intern->eventhandlers, type_str, type_len))) {
61 HashTable *evhs;
62 zval tmp;
63
64 ALLOC_HASHTABLE(evhs);
65 zend_hash_init(evhs, 1, NULL, php_pq_callback_hash_dtor, 0);
66
67 ZVAL_ARR(&tmp, evhs);
68 zevhs = zend_hash_str_add(&obj->intern->eventhandlers, type_str, type_len, &tmp);
69 }
70
71 php_pq_callback_addref(cb);
72 h = zend_hash_next_free_element(Z_ARRVAL_P(zevhs));
73 zend_hash_index_update_mem(Z_ARRVAL_P(zevhs), h, (void *) cb, sizeof(*cb));
74
75 return h;
76 }
77
78 static void php_pqconn_object_free(zend_object *o)
79 {
80 php_pqconn_object_t *obj = PHP_PQ_OBJ(NULL, o);
81 #if DBG_GC
82 fprintf(stderr, "FREE conn(#%d) %p\n", obj->zo.handle, obj);
83 #endif
84 if (obj->intern) {
85 php_pq_callback_dtor(&obj->intern->onevent);
86 php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn);
87 php_resource_factory_dtor(&obj->intern->factory);
88 zend_hash_destroy(&obj->intern->listeners);
89 zend_hash_destroy(&obj->intern->statements);
90 zend_hash_destroy(&obj->intern->converters);
91 zend_hash_destroy(&obj->intern->eventhandlers);
92 efree(obj->intern);
93 obj->intern = NULL;
94 }
95 php_pq_object_dtor(o);
96 }
97
98
99 php_pqconn_object_t *php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern)
100 {
101 return php_pq_object_create(ce, intern, sizeof(php_pqconn_object_t),
102 &php_pqconn_object_handlers, &php_pqconn_object_prophandlers);
103 }
104
105 static zend_object *php_pqconn_create_object(zend_class_entry *class_type)
106 {
107 return &php_pqconn_create_object_ex(class_type, NULL)->zo;
108 }
109
110 static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value)
111 {
112 php_pqconn_object_t *obj = o;
113
114 RETVAL_LONG(PQstatus(obj->intern->conn));
115 }
116
117 static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value)
118 {
119 php_pqconn_object_t *obj = o;
120
121 RETVAL_LONG(PQtransactionStatus(obj->intern->conn));
122 }
123
124 static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value)
125 {
126 php_pqconn_object_t *obj = o;
127 char *error = PHP_PQerrorMessage(obj->intern->conn);
128
129 if (error) {
130 RETVAL_STRING(error);
131 } else {
132 RETVAL_NULL();
133 }
134 }
135
136 static int apply_notify_listener(zval *p, void *arg)
137 {
138 php_pq_callback_t *listener = Z_PTR_P(p);
139 PGnotify *nfy = arg;
140 zval zpid, zchannel, zmessage;
141
142 ZVAL_LONG(&zpid, nfy->be_pid);
143 ZVAL_STRING(&zchannel, nfy->relname);
144 ZVAL_STRING(&zmessage, nfy->extra);
145
146 zend_fcall_info_argn(&listener->fci, 3, &zchannel, &zmessage, &zpid);
147 zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL);
148 zend_fcall_info_args_clear(&listener->fci, 0);
149
150 zval_ptr_dtor(&zchannel);
151 zval_ptr_dtor(&zmessage);
152 zval_ptr_dtor(&zpid);
153
154 return ZEND_HASH_APPLY_KEEP;
155 }
156
157 static int apply_notify_listeners(zval *p, int argc, va_list argv, zend_hash_key *key)
158 {
159 HashTable *listeners = Z_ARRVAL_P(p);
160 PGnotify *nfy = va_arg(argv, PGnotify *);
161
162 if (0 == fnmatch(key->key->val, nfy->relname, 0)) {
163 zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy);
164 }
165
166 return ZEND_HASH_APPLY_KEEP;
167 }
168
169 void php_pqconn_notify_listeners(php_pqconn_object_t *obj)
170 {
171 PGnotify *nfy;
172
173 while ((nfy = PQnotifies(obj->intern->conn))) {
174 zend_hash_apply_with_arguments(&obj->intern->listeners, apply_notify_listeners, 1, nfy);
175 PQfreemem(nfy);
176 }
177 }
178
179 static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value)
180 {
181 php_pqconn_object_t *obj = o;
182
183 RETVAL_BOOL(PQisBusy(obj->intern->conn));
184 }
185
186 static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value)
187 {
188 php_pqconn_object_t *obj = o;
189
190 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn)));
191 }
192
193 static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value)
194 {
195 php_pqconn_object_t *obj = o;
196 zend_string *zenc = zval_get_string(value);
197
198 if (0 > PQsetClientEncoding(obj->intern->conn, zenc->val)) {
199 php_error(E_NOTICE, "Unrecognized encoding '%s'", zenc->val);
200 }
201
202 zend_string_release(zenc);
203 }
204
205 static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value)
206 {
207 php_pqconn_object_t *obj = o;
208
209 RETVAL_BOOL(obj->intern->unbuffered);
210 }
211
212 static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value)
213 {
214 php_pqconn_object_t *obj = o;
215
216 obj->intern->unbuffered = z_is_true(value);
217 }
218
219 static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value)
220 {
221 php_pqconn_object_t *obj = o;
222 char *db = PQdb(obj->intern->conn);
223
224 if (db) {
225 RETVAL_STRING(db);
226 } else {
227 RETVAL_EMPTY_STRING();
228 }
229 }
230
231 static void php_pqconn_object_read_user(zval *object, void *o, zval *return_value)
232 {
233 php_pqconn_object_t *obj = o;
234 char *user = PQuser(obj->intern->conn);
235
236 if (user) {
237 RETVAL_STRING(user);
238 } else {
239 RETVAL_EMPTY_STRING();
240 }
241 }
242
243 static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_value)
244 {
245 php_pqconn_object_t *obj = o;
246 char *pass = PQpass(obj->intern->conn);
247
248 if (pass) {
249 RETVAL_STRING(pass);
250 } else {
251 RETVAL_EMPTY_STRING();
252 }
253 }
254
255 static void php_pqconn_object_read_host(zval *object, void *o, zval *return_value)
256 {
257 php_pqconn_object_t *obj = o;
258 char *host = PQhost(obj->intern->conn);
259
260 if (host) {
261 RETVAL_STRING(host);
262 } else {
263 RETVAL_EMPTY_STRING();
264 }
265 }
266
267 static void php_pqconn_object_read_port(zval *object, void *o, zval *return_value)
268 {
269 php_pqconn_object_t *obj = o;
270 char *port = PQport(obj->intern->conn);
271
272 if (port) {
273 RETVAL_STRING(port);
274 } else {
275 RETVAL_EMPTY_STRING();
276 }
277 }
278
279 #if HAVE_PQCONNINFO
280 static void php_pqconn_object_read_params(zval *object, void *o, zval *return_value)
281 {
282 php_pqconn_object_t *obj = o;
283 PQconninfoOption *ptr, *params = PQconninfo(obj->intern->conn);
284
285 array_init(return_value);
286
287 if (params) {
288 for (ptr = params; ptr->keyword; ++ptr) {
289 if (ptr->val) {
290 add_assoc_string(return_value, ptr->keyword, ptr->val);
291 } else {
292 add_assoc_null(return_value, ptr->keyword);
293 }
294 }
295 PQconninfoFree(params);
296 }
297 }
298 #endif
299
300 static void php_pqconn_object_read_options(zval *object, void *o, zval *return_value)
301 {
302 php_pqconn_object_t *obj = o;
303 char *options = PQoptions(obj->intern->conn);
304
305 if (options) {
306 RETVAL_STRING(options);
307 } else {
308 RETVAL_EMPTY_STRING();
309 }
310 }
311
312 static int apply_read_callback_ex(zval *p, void *arg)
313 {
314 HashTable *rv = arg;
315 zval zcb;
316
317 zend_hash_next_index_insert(rv, php_pq_callback_to_zval(Z_PTR_P(p), &zcb));
318
319 return ZEND_HASH_APPLY_KEEP;
320 }
321
322 static int apply_read_callbacks(zval *p, int argc, va_list argv, zend_hash_key *key)
323 {
324 HashTable *evhs = Z_ARRVAL_P(p), *rv = va_arg(argv, HashTable *);
325 zval entry, *entry_ptr;
326
327 array_init_size(&entry, zend_hash_num_elements(evhs));
328
329 if (key->key->len) {
330 entry_ptr = zend_hash_add(rv, key->key, &entry);
331 } else {
332 entry_ptr = zend_hash_index_update(rv, key->h, &entry);
333 }
334
335 zend_hash_apply_with_argument(evhs, apply_read_callback_ex, Z_ARRVAL_P(entry_ptr));
336
337 return ZEND_HASH_APPLY_KEEP;
338 }
339 static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value)
340 {
341 php_pqconn_object_t *obj = o;
342
343 array_init(return_value);
344 zend_hash_apply_with_arguments(&obj->intern->eventhandlers, apply_read_callbacks, 1, Z_ARRVAL_P(return_value));
345 }
346
347 static void php_pqconn_object_gc_event_handlers(zval *object, void *o, zval *return_value)
348 {
349 php_pqconn_object_t *obj = o;
350 zval *evhs;
351
352 ZEND_HASH_FOREACH_VAL(&obj->intern->eventhandlers, evhs)
353 {
354 zval *evh;
355
356 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(evhs), evh)
357 {
358 zval zcb;
359
360 add_next_index_zval(return_value, php_pq_callback_to_zval_no_addref(Z_PTR_P(evh), &zcb));
361 }
362 ZEND_HASH_FOREACH_END();
363 }
364 ZEND_HASH_FOREACH_END();
365 }
366
367 static void php_pqconn_object_read_listeners(zval *object, void *o, zval *return_value)
368 {
369 php_pqconn_object_t *obj = o;
370
371 array_init(return_value);
372 zend_hash_apply_with_arguments(&obj->intern->listeners, apply_read_callbacks, 1, Z_ARRVAL_P(return_value));
373 }
374
375 static void php_pqconn_object_gc_listeners(zval *object, void *o, zval *return_value)
376 {
377 php_pqconn_object_t *obj = o;
378 zval *listeners;
379
380 ZEND_HASH_FOREACH_VAL(&obj->intern->listeners, listeners)
381 {
382 zval *listener;
383
384 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(listeners), listener)
385 {
386 zval zcb;
387
388 add_next_index_zval(return_value, php_pq_callback_to_zval_no_addref(Z_PTR_P(listener), &zcb));
389 }
390 ZEND_HASH_FOREACH_END();
391 }
392 ZEND_HASH_FOREACH_END();
393 }
394
395 static void php_pqconn_object_read_converters(zval *object, void *o, zval *return_value)
396 {
397 php_pqconn_object_t *obj = o;
398
399 array_init(return_value);
400 zend_hash_copy(Z_ARRVAL_P(return_value), &obj->intern->converters, zval_add_ref);
401 }
402
403 static void php_pqconn_object_gc_converters(zval *object, void *o, zval *return_value)
404 {
405 php_pqconn_object_t *obj = o;
406 zval *converter;
407
408 ZEND_HASH_FOREACH_VAL(&obj->intern->converters, converter)
409 {
410 add_next_index_zval(return_value, converter);
411 }
412 ZEND_HASH_FOREACH_END();
413 }
414
415 static void php_pqconn_object_read_def_fetch_type(zval *object, void *o, zval *return_value)
416 {
417 php_pqconn_object_t *obj = o;
418
419 RETVAL_LONG(obj->intern->default_fetch_type);
420 }
421 static void php_pqconn_object_write_def_fetch_type(zval *object, void *o, zval *value)
422 {
423 php_pqconn_object_t *obj = o;
424
425 obj->intern->default_fetch_type = zval_get_long(value) & 0x3; /* two bits only */
426 }
427
428 static void php_pqconn_object_read_def_txn_isolation(zval *object, void *o, zval *return_value)
429 {
430 php_pqconn_object_t *obj = o;
431
432 RETVAL_LONG(obj->intern->default_txn_isolation);
433 }
434 static void php_pqconn_object_write_def_txn_isolation(zval *object, void *o, zval *value)
435 {
436 php_pqconn_object_t *obj = o;
437
438 obj->intern->default_txn_isolation = zval_get_long(value) & 0x3; /* two bits only */
439 }
440
441 static void php_pqconn_object_read_def_txn_readonly(zval *object, void *o, zval *return_value)
442 {
443 php_pqconn_object_t *obj = o;
444
445 RETVAL_BOOL(obj->intern->default_txn_readonly);
446 }
447 static void php_pqconn_object_write_def_txn_readonly(zval *object, void *o, zval *value)
448 {
449 php_pqconn_object_t *obj = o;
450
451 obj->intern->default_txn_readonly = z_is_true(value);
452 }
453
454 static void php_pqconn_object_read_def_txn_deferrable(zval *object, void *o, zval *return_value)
455 {
456 php_pqconn_object_t *obj = o;
457
458 RETVAL_BOOL(obj->intern->default_txn_deferrable);
459 }
460 static void php_pqconn_object_write_def_txn_deferrable(zval *object, void *o, zval *value)
461 {
462 php_pqconn_object_t *obj = o;
463
464 obj->intern->default_txn_deferrable = zend_is_true(value);
465 }
466
467 static void php_pqconn_object_read_def_auto_conv(zval *object, void *o, zval *return_value)
468 {
469 php_pqconn_object_t *obj = o;
470
471 RETVAL_LONG(obj->intern->default_auto_convert);
472 }
473 static void php_pqconn_object_write_def_auto_conv(zval*object, void *o, zval *value)
474 {
475 php_pqconn_object_t *obj = o;
476
477 obj->intern->default_auto_convert = zval_get_long(value) & PHP_PQRES_CONV_ALL;
478 }
479
480 static ZEND_RESULT_CODE php_pqconn_update_socket(zval *zobj, php_pqconn_object_t *obj)
481 {
482 zval zsocket, zmember;
483 php_stream *stream;
484 ZEND_RESULT_CODE retval;
485 int socket;
486
487 if (!obj) {
488 obj = PHP_PQ_OBJ(zobj, NULL);
489 }
490
491 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1);
492
493 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
494 && (-1 < (socket = PQsocket(obj->intern->conn)))
495 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
496 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
497 php_stream_to_zval(stream, &zsocket);
498 retval = SUCCESS;
499 } else {
500 ZVAL_NULL(&zsocket);
501 retval = FAILURE;
502 }
503 zend_get_std_object_handlers()->write_property(zobj, &zmember, &zsocket, NULL);
504 zval_ptr_dtor(&zsocket);
505 zval_ptr_dtor(&zmember);
506
507 return retval;
508 }
509
510 static void *php_pqconn_resource_factory_ctor(void *data, void *init_arg)
511 {
512 php_pqconn_resource_factory_data_t *o = init_arg;
513 PGconn *conn = NULL;;
514
515 if (o->flags & PHP_PQCONN_ASYNC) {
516 conn = PQconnectStart(o->dsn);
517 } else {
518 conn = PQconnectdb(o->dsn);
519 }
520
521 if (conn) {
522 PQregisterEventProc(conn, php_pqconn_event, "ext-pq", NULL);
523 }
524
525 return conn;
526 }
527
528 static void php_pqconn_resource_factory_dtor(void *opaque, void *handle)
529 {
530 php_pqconn_event_data_t *evdata = PQinstanceData(handle, php_pqconn_event);
531
532 /* we don't care for anything, except free'ing evdata */
533 if (evdata) {
534 PQsetInstanceData(handle, php_pqconn_event, NULL);
535 memset(evdata, 0, sizeof(*evdata));
536 efree(evdata);
537 }
538
539 PQfinish(handle);
540 }
541
542 static php_resource_factory_ops_t php_pqconn_resource_factory_ops = {
543 php_pqconn_resource_factory_ctor,
544 NULL,
545 php_pqconn_resource_factory_dtor
546 };
547
548 php_resource_factory_ops_t *php_pqconn_get_resource_factory_ops(void)
549 {
550 return &php_pqconn_resource_factory_ops;
551 }
552
553 static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle)
554 {
555 PGresult *res = PQexec(*handle, "");
556 php_pqres_clear(res);
557
558 if (CONNECTION_OK != PQstatus(*handle)) {
559 PQreset(*handle);
560 }
561 }
562
563 static inline PGresult *unlisten(PGconn *conn, const char *channel_str, size_t channel_len)
564 {
565 char *quoted_channel = PQescapeIdentifier(conn, channel_str, channel_len);
566 PGresult *res = NULL;
567
568 if (quoted_channel) {
569 smart_str cmd = {0};
570
571 smart_str_appends(&cmd, "UNLISTEN ");
572 smart_str_appends(&cmd, quoted_channel);
573 smart_str_0(&cmd);
574
575 res = PQexec(conn, smart_str_v(&cmd));
576
577 smart_str_free(&cmd);
578 PQfreemem(quoted_channel);
579 }
580
581 return res;
582 }
583
584 static int apply_unlisten(zval *p, int argc, va_list argv, zend_hash_key *key)
585 {
586 php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
587 PGresult *res = unlisten(obj->intern->conn, key->key->val, key->key->len);
588
589 if (res) {
590 php_pqres_clear(res);
591 }
592
593 return ZEND_HASH_APPLY_REMOVE;
594 }
595
596 static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle)
597 {
598 php_pqconn_event_data_t *evdata = PQinstanceData(*handle, php_pqconn_event);
599 PGcancel *cancel;
600 PGresult *res;
601
602 /* go away */
603 PQsetInstanceData(*handle, php_pqconn_event, NULL);
604
605 /* ignore notices */
606 PQsetNoticeReceiver(*handle, php_pqconn_notice_ignore, NULL);
607
608 /* cancel async queries */
609 if (PQisBusy(*handle) && (cancel = PQgetCancel(*handle))) {
610 char err[256] = {0};
611
612 PQcancel(cancel, err, sizeof(err));
613 PQfreeCancel(cancel);
614 }
615 /* clean up async results */
616 while ((res = PQgetResult(*handle))) {
617 php_pqres_clear(res);
618 }
619
620 /* clean up transaction & session */
621 switch (PQtransactionStatus(*handle)) {
622 case PQTRANS_IDLE:
623 res = PQexec(*handle, "RESET ALL");
624 break;
625 default:
626 res = PQexec(*handle, "ROLLBACK; RESET ALL");
627 break;
628 }
629
630 if (res) {
631 php_pqres_clear(res);
632 }
633
634 if (evdata) {
635 /* clean up notify listeners */
636 zend_hash_apply_with_arguments(&evdata->obj->intern->listeners, apply_unlisten, 1, evdata->obj);
637
638 /* release instance data */
639 efree(evdata);
640 }
641 }
642
643 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
644 ZEND_ARG_INFO(0, dsn)
645 ZEND_ARG_INFO(0, flags)
646 ZEND_END_ARG_INFO();
647 static PHP_METHOD(pqconn, __construct) {
648 zend_error_handling zeh;
649 char *dsn_str = "";
650 size_t dsn_len = 0;
651 zend_long flags = 0;
652 ZEND_RESULT_CODE rv;
653
654 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
655 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &dsn_str, &dsn_len, &flags);
656 zend_restore_error_handling(&zeh);
657
658 if (SUCCESS == rv) {
659 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
660
661 if (obj->intern) {
662 throw_exce(EX_BAD_METHODCALL, "pq\\Connection already initialized");
663 } else {
664 php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj);
665 php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags};
666
667 obj->intern = ecalloc(1, sizeof(*obj->intern));
668
669 obj->intern->default_auto_convert = PHP_PQRES_CONV_ALL;
670
671 zend_hash_init(&obj->intern->listeners, 0, NULL, ZVAL_PTR_DTOR, 0);
672 zend_hash_init(&obj->intern->statements, 0, NULL, NULL, 0);
673 zend_hash_init(&obj->intern->converters, 0, NULL, ZVAL_PTR_DTOR, 0);
674 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);
675
676 if (flags & PHP_PQCONN_PERSISTENT) {
677 zend_string *dsn = zend_string_init(dsn_str, dsn_len, 0);
678 php_persistent_handle_factory_t *phf = php_persistent_handle_concede(NULL, PHP_PQ_G->connection.name, dsn, php_pqconn_wakeup, php_pqconn_retire);
679 php_persistent_handle_resource_factory_init(&obj->intern->factory, phf);
680 zend_string_release(dsn);
681 } else {
682 php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL);
683 }
684
685 if (flags & PHP_PQCONN_ASYNC) {
686 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
687 }
688
689 obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata);
690
691 PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata);
692 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata);
693
694 if (SUCCESS != php_pqconn_update_socket(getThis(), obj)) {
695 throw_exce(EX_CONNECTION_FAILED, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn));
696 }
697 }
698 }
699 }
700
701 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
702 ZEND_END_ARG_INFO();
703 static PHP_METHOD(pqconn, reset) {
704 zend_error_handling zeh;
705 ZEND_RESULT_CODE rv;
706
707 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
708 rv = zend_parse_parameters_none();
709 zend_restore_error_handling(&zeh);
710
711 if (SUCCESS == rv) {
712 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
713
714 if (!obj->intern) {
715 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
716 } else {
717 PQreset(obj->intern->conn);
718
719 if (CONNECTION_OK != PQstatus(obj->intern->conn)) {
720 throw_exce(EX_CONNECTION_FAILED, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn));
721 }
722
723 php_pqconn_notify_listeners(obj);
724 }
725 }
726 }
727
728 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
729 ZEND_END_ARG_INFO();
730 static PHP_METHOD(pqconn, resetAsync) {
731 zend_error_handling zeh;
732 ZEND_RESULT_CODE rv;
733
734 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
735 rv = zend_parse_parameters_none();
736 zend_restore_error_handling(&zeh);
737
738 if (SUCCESS == rv) {
739 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
740
741 if (!obj->intern) {
742 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
743 } else {
744 if (!PQresetStart(obj->intern->conn)) {
745 throw_exce(EX_IO, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn));
746 } else {
747 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
748 }
749
750 php_pqconn_notify_listeners(obj);
751 }
752 }
753 }
754
755 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unlisten, 0, 0, 1)
756 ZEND_ARG_INFO(0, channel)
757 ZEND_END_ARG_INFO();
758 static PHP_METHOD(pqconn, unlisten)
759 {
760 zend_error_handling zeh;
761 char *channel_str;
762 size_t channel_len;
763 ZEND_RESULT_CODE rv;
764
765 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
766 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &channel_str, &channel_len);
767 zend_restore_error_handling(&zeh);
768
769 if (SUCCESS == rv) {
770 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
771
772 if (!obj->intern) {
773 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
774 } else if (SUCCESS == zend_hash_str_del(&obj->intern->listeners, channel_str, channel_len)) {
775 PGresult *res = unlisten(obj->intern->conn, channel_str, channel_len);
776
777 if (res) {
778 php_pqres_success(res);
779 php_pqres_clear(res);
780 }
781 }
782 }
783 }
784
785 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unlisten_async, 0, 0, 1)
786 ZEND_ARG_INFO(0, channel)
787 ZEND_END_ARG_INFO();
788 static PHP_METHOD(pqconn, unlistenAsync) {
789 zend_error_handling zeh;
790 char *channel_str;
791 size_t channel_len;
792 ZEND_RESULT_CODE rv;
793
794 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
795 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &channel_str, &channel_len);
796 zend_restore_error_handling(&zeh);
797
798 if (SUCCESS == rv) {
799 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
800
801 if (!obj->intern) {
802 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
803 } else {
804 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
805
806 if (!quoted_channel) {
807 throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
808 } else {
809 smart_str cmd = {0};
810
811 smart_str_appends(&cmd, "UNLISTEN ");
812 smart_str_appends(&cmd, quoted_channel);
813 smart_str_0(&cmd);
814
815 if (!PQsendQuery(obj->intern->conn, smart_str_v(&cmd))) {
816 throw_exce(EX_IO, "Failed to uninstall listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
817 } else {
818 obj->intern->poller = PQconsumeInput;
819 zend_hash_str_del(&obj->intern->listeners, channel_str, channel_len);
820 }
821
822 smart_str_free(&cmd);
823 PQfreemem(quoted_channel);
824 php_pqconn_notify_listeners(obj);
825 }
826 }
827 }
828 }
829
830 static void php_pqconn_add_listener(php_pqconn_object_t *obj, const char *channel_str, size_t channel_len, php_pq_callback_t *listener)
831 {
832 zval *existing;
833
834 php_pq_callback_addref(listener);
835
836 if ((existing = zend_hash_str_find(&obj->intern->listeners, channel_str, channel_len))) {
837 zend_hash_next_index_insert_mem(Z_ARRVAL_P(existing), (void *) listener, sizeof(*listener));
838 } else {
839 zval tmp;
840 HashTable *ht;
841
842 ALLOC_HASHTABLE(ht);
843 zend_hash_init(ht, 0, NULL, php_pq_callback_hash_dtor, 0);
844 zend_hash_next_index_insert_mem(ht, (void *) listener, sizeof(*listener));
845
846 ZVAL_ARR(&tmp, ht);
847 zend_hash_str_add(&obj->intern->listeners, channel_str, channel_len, &tmp);
848 }
849 }
850
851 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 2)
852 ZEND_ARG_INFO(0, channel)
853 ZEND_ARG_INFO(0, callable)
854 ZEND_END_ARG_INFO();
855 static PHP_METHOD(pqconn, listen) {
856 zend_error_handling zeh;
857 char *channel_str = NULL;
858 size_t channel_len = 0;
859 php_pq_callback_t listener = {{0}};
860 ZEND_RESULT_CODE rv;
861
862 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
863 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
864 zend_restore_error_handling(&zeh);
865
866 if (SUCCESS == rv) {
867 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
868
869 if (!obj->intern) {
870 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
871 } else {
872 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
873
874 if (!quoted_channel) {
875 throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
876 } else {
877 PGresult *res;
878 smart_str cmd = {0};
879
880 smart_str_appends(&cmd, "LISTEN ");
881 smart_str_appends(&cmd, quoted_channel);
882 smart_str_0(&cmd);
883
884 res = php_pq_exec(obj->intern->conn, smart_str_v(&cmd));
885
886 smart_str_free(&cmd);
887 PQfreemem(quoted_channel);
888
889 if (!res) {
890 throw_exce(EX_RUNTIME, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
891 } else {
892 if (SUCCESS == php_pqres_success(res)) {
893 obj->intern->poller = PQconsumeInput;
894 php_pqconn_add_listener(obj, channel_str, channel_len, &listener);
895 }
896 php_pqres_clear(res);
897 }
898
899 php_pqconn_notify_listeners(obj);
900 }
901 }
902 }
903 }
904
905 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async, 0, 0, 0)
906 ZEND_ARG_INFO(0, channel)
907 ZEND_ARG_INFO(0, callable)
908 ZEND_END_ARG_INFO();
909 static PHP_METHOD(pqconn, listenAsync) {
910 zend_error_handling zeh;
911 char *channel_str = NULL;
912 size_t channel_len = 0;
913 php_pq_callback_t listener = {{0}};
914 ZEND_RESULT_CODE rv;
915
916 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
917 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
918 zend_restore_error_handling(&zeh);
919
920 if (SUCCESS == rv) {
921 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
922
923 if (!obj->intern) {
924 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
925 } else {
926 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
927
928 if (!quoted_channel) {
929 throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
930 } else {
931 smart_str cmd = {0};
932
933 smart_str_appends(&cmd, "LISTEN ");
934 smart_str_appends(&cmd, quoted_channel);
935 smart_str_0(&cmd);
936
937 if (!PQsendQuery(obj->intern->conn, smart_str_v(&cmd))) {
938 throw_exce(EX_IO, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
939 } else {
940 obj->intern->poller = PQconsumeInput;
941 php_pqconn_add_listener(obj, channel_str, channel_len, &listener);
942 }
943
944 smart_str_free(&cmd);
945 PQfreemem(quoted_channel);
946 php_pqconn_notify_listeners(obj);
947 }
948 }
949 }
950 }
951
952 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
953 ZEND_ARG_INFO(0, channel)
954 ZEND_ARG_INFO(0, message)
955 ZEND_END_ARG_INFO();
956 static PHP_METHOD(pqconn, notify) {
957 zend_error_handling zeh;
958 char *channel_str, *message_str;
959 size_t channel_len, message_len;
960 ZEND_RESULT_CODE rv;
961
962 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
963 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &channel_str, &channel_len, &message_str, &message_len);
964 zend_restore_error_handling(&zeh);
965
966 if (SUCCESS == rv) {
967 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
968
969 if (!obj->intern) {
970 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
971 } else {
972 PGresult *res;
973 char *params[2] = {channel_str, message_str};
974
975 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
976
977 if (!res) {
978 throw_exce(EX_RUNTIME, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
979 } else {
980 php_pqres_success(res);
981 php_pqres_clear(res);
982 }
983
984 php_pqconn_notify_listeners(obj);
985 }
986 }
987 }
988
989 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async, 0, 0, 2)
990 ZEND_ARG_INFO(0, channel)
991 ZEND_ARG_INFO(0, message)
992 ZEND_END_ARG_INFO();
993 static PHP_METHOD(pqconn, notifyAsync) {
994 zend_error_handling zeh;
995 char *channel_str, *message_str;
996 size_t channel_len, message_len;
997 ZEND_RESULT_CODE rv;
998
999 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1000 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &channel_str, &channel_len, &message_str, &message_len);
1001 zend_restore_error_handling(&zeh);
1002
1003 if (SUCCESS == rv) {
1004 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1005
1006 if (!obj->intern) {
1007 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1008 } else {
1009 char *params[2] = {channel_str, message_str};
1010
1011 if (!PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) {
1012 throw_exce(EX_IO, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
1013 } else {
1014 obj->intern->poller = PQconsumeInput;
1015 }
1016
1017 php_pqconn_notify_listeners(obj);
1018 }
1019 }
1020 }
1021
1022 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
1023 ZEND_END_ARG_INFO();
1024 static PHP_METHOD(pqconn, poll) {
1025 zend_error_handling zeh;
1026 ZEND_RESULT_CODE rv;
1027
1028 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1029 rv = zend_parse_parameters_none();
1030 zend_restore_error_handling(&zeh);
1031
1032 if (SUCCESS == rv) {
1033 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1034
1035 if (!obj->intern) {
1036 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1037 } else if (!obj->intern->poller) {
1038 throw_exce(EX_RUNTIME, "No asynchronous operation active");
1039 } else {
1040 if (obj->intern->poller == PQconsumeInput) {
1041 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
1042 } else {
1043 RETVAL_LONG(obj->intern->poller(obj->intern->conn));
1044 }
1045 php_pqconn_notify_listeners(obj);
1046 }
1047 }
1048 }
1049
1050 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
1051 ZEND_ARG_INFO(0, query)
1052 ZEND_END_ARG_INFO();
1053 static PHP_METHOD(pqconn, exec) {
1054 zend_error_handling zeh;
1055 char *query_str;
1056 size_t query_len;
1057 ZEND_RESULT_CODE rv;
1058
1059 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1060 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query_str, &query_len);
1061 zend_restore_error_handling(&zeh);
1062
1063 if (SUCCESS == rv) {
1064 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1065
1066 if (!obj->intern) {
1067 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1068 } else {
1069 PGresult *res = php_pq_exec(obj->intern->conn, query_str);
1070
1071 if (!res) {
1072 throw_exce(EX_RUNTIME, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
1073 } else if (SUCCESS == php_pqres_success(res)) {
1074 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value);
1075 } else {
1076 php_pqres_clear(res);
1077 }
1078
1079 php_pqconn_notify_listeners(obj);
1080 }
1081 }
1082 }
1083
1084 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
1085 ZEND_END_ARG_INFO();
1086 static PHP_METHOD(pqconn, getResult) {
1087 zend_error_handling zeh;
1088 ZEND_RESULT_CODE rv;
1089
1090 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1091 rv = zend_parse_parameters_none();
1092 zend_restore_error_handling(&zeh);
1093
1094 if (SUCCESS == rv) {
1095 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1096
1097 if (!obj->intern) {
1098 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1099 } else {
1100 PGresult *res = PQgetResult(obj->intern->conn);
1101
1102 if (!res) {
1103 RETVAL_NULL();
1104 } else {
1105 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value);
1106 }
1107
1108 php_pqconn_notify_listeners(obj);
1109 }
1110 }
1111 }
1112
1113 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
1114 ZEND_ARG_INFO(0, query)
1115 ZEND_ARG_INFO(0, callable)
1116 ZEND_END_ARG_INFO();
1117 static PHP_METHOD(pqconn, execAsync) {
1118 zend_error_handling zeh;
1119 php_pq_callback_t resolver = {{0}};
1120 char *query_str;
1121 size_t query_len;
1122 ZEND_RESULT_CODE rv;
1123
1124 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1125 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc);
1126 zend_restore_error_handling(&zeh);
1127
1128 if (SUCCESS == rv) {
1129 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1130
1131 if (!obj->intern) {
1132 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1133 } else if (!PQsendQuery(obj->intern->conn, query_str)) {
1134 throw_exce(EX_IO, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
1135 #if HAVE_PQSETSINGLEROWMODE
1136 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1137 throw_exce(EX_RUNTIME, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1138 #endif
1139 } else {
1140 php_pq_callback_recurse(&obj->intern->onevent, &resolver);
1141 obj->intern->poller = PQconsumeInput;
1142 php_pqconn_notify_listeners(obj);
1143 }
1144 }
1145 }
1146
1147 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
1148 ZEND_ARG_INFO(0, query)
1149 ZEND_ARG_ARRAY_INFO(0, params, 0)
1150 ZEND_ARG_ARRAY_INFO(0, types, 1)
1151 ZEND_END_ARG_INFO();
1152 static PHP_METHOD(pqconn, execParams) {
1153 zend_error_handling zeh;
1154 char *query_str;
1155 size_t query_len;
1156 zval *zparams;
1157 zval *ztypes = NULL;
1158 ZEND_RESULT_CODE rv;
1159
1160 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1161 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sa/|a/!", &query_str, &query_len, &zparams, &ztypes);
1162 zend_restore_error_handling(&zeh);
1163
1164 if (SUCCESS == rv) {
1165 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1166
1167 if (!obj->intern) {
1168 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1169 } else {
1170 PGresult *res;
1171 php_pq_params_t *params;
1172
1173 params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams));
1174 res = PQexecParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
1175 php_pq_params_free(&params);
1176
1177 if (!res) {
1178 throw_exce(EX_RUNTIME, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
1179 } else {
1180 if (SUCCESS == php_pqres_success(res)) {
1181 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value);
1182 } else {
1183 php_pqres_clear(res);
1184 }
1185
1186 php_pqconn_notify_listeners(obj);
1187 }
1188 }
1189 }
1190 }
1191
1192 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
1193 ZEND_ARG_INFO(0, query)
1194 ZEND_ARG_ARRAY_INFO(0, params, 0)
1195 ZEND_ARG_ARRAY_INFO(0, types, 1)
1196 ZEND_ARG_INFO(0, callable)
1197 ZEND_END_ARG_INFO();
1198 static PHP_METHOD(pqconn, execParamsAsync) {
1199 zend_error_handling zeh;
1200 php_pq_callback_t resolver = {{0}};
1201 char *query_str;
1202 size_t query_len;
1203 zval *zparams;
1204 zval *ztypes = NULL;
1205 ZEND_RESULT_CODE rv;
1206
1207 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1208 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc);
1209 zend_restore_error_handling(&zeh);
1210
1211 if (SUCCESS == rv) {
1212 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1213
1214 if (!obj->intern) {
1215 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1216 } else {
1217 int rc;
1218 php_pq_params_t *params;
1219
1220 params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams));
1221 rc = PQsendQueryParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
1222 php_pq_params_free(&params);
1223
1224 if (!rc) {
1225 throw_exce(EX_IO, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
1226 #if HAVE_PQSETSINGLEROWMODE
1227 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1228 throw_exce(EX_RUNTIME, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1229 #endif
1230 } else {
1231 php_pq_callback_recurse(&obj->intern->onevent, &resolver);
1232 obj->intern->poller = PQconsumeInput;
1233 php_pqconn_notify_listeners(obj);
1234 }
1235 }
1236 }
1237 zend_restore_error_handling(&zeh);
1238 }
1239
1240 ZEND_RESULT_CODE php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params)
1241 {
1242 PGresult *res;
1243 ZEND_RESULT_CODE rv;
1244
1245 if (!obj) {
1246 obj = PHP_PQ_OBJ(object, NULL);
1247 }
1248
1249 res = php_pq_prepare(obj->intern->conn, name, query, params->type.count, params->type.oids);
1250
1251 if (!res) {
1252 rv = FAILURE;
1253 throw_exce(EX_RUNTIME, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
1254 } else {
1255 rv = php_pqres_success(res);
1256 php_pqres_clear(res);
1257 php_pqconn_notify_listeners(obj);
1258 }
1259
1260 return rv;
1261 }
1262
1263 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
1264 ZEND_ARG_INFO(0, name)
1265 ZEND_ARG_INFO(0, query)
1266 ZEND_ARG_ARRAY_INFO(0, types, 1)
1267 ZEND_END_ARG_INFO();
1268 static PHP_METHOD(pqconn, prepare) {
1269 zend_error_handling zeh;
1270 zval *ztypes = NULL;
1271 char *name_str, *query_str;
1272 size_t name_len, *query_len;
1273 ZEND_RESULT_CODE rv;
1274
1275 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1276 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
1277 zend_restore_error_handling(&zeh);
1278
1279 if (SUCCESS == rv) {
1280 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1281
1282 if (!obj->intern) {
1283 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1284 } else {
1285 php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL);
1286
1287 if (SUCCESS != php_pqconn_prepare(getThis(), obj, name_str, query_str, params)) {
1288 php_pq_params_free(&params);
1289 } else {
1290 php_pqstm_t *stm = php_pqstm_init(obj, name_str, query_str, params);
1291
1292 RETVAL_OBJ(&php_pqstm_create_object_ex(php_pqstm_class_entry, stm)->zo);
1293 }
1294 }
1295 }
1296 }
1297
1298 ZEND_RESULT_CODE php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params)
1299 {
1300 ZEND_RESULT_CODE rv;
1301
1302 if (!obj) {
1303 obj = PHP_PQ_OBJ(object, NULL);
1304 }
1305
1306 if (!PQsendPrepare(obj->intern->conn, name, query, params->type.count, params->type.oids)) {
1307 rv = FAILURE;
1308 throw_exce(EX_IO, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
1309 } else {
1310 rv = SUCCESS;
1311 obj->intern->poller = PQconsumeInput;
1312 php_pqconn_notify_listeners(obj);
1313 }
1314
1315 return rv;
1316 }
1317
1318 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
1319 ZEND_ARG_INFO(0, name)
1320 ZEND_ARG_INFO(0, query)
1321 ZEND_ARG_ARRAY_INFO(0, types, 1)
1322 ZEND_END_ARG_INFO();
1323 static PHP_METHOD(pqconn, prepareAsync) {
1324 zend_error_handling zeh;
1325 zval *ztypes = NULL;
1326 char *name_str, *query_str;
1327 size_t name_len, *query_len;
1328 ZEND_RESULT_CODE rv;
1329
1330 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1331 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
1332 zend_restore_error_handling(&zeh);
1333
1334 if (SUCCESS == rv) {
1335 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1336
1337 if (!obj->intern) {
1338 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1339 } else {
1340 php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL);
1341
1342 if (SUCCESS != php_pqconn_prepare_async(getThis(), obj, name_str, query_str, params)) {
1343 php_pq_params_free(&params);
1344 } else {
1345 php_pqstm_t *stm = php_pqstm_init(obj, name_str, query_str, params);
1346
1347 RETVAL_OBJ(&php_pqstm_create_object_ex(php_pqstm_class_entry, stm)->zo);
1348 }
1349 }
1350 }
1351 }
1352
1353 ZEND_RESULT_CODE php_pqconn_declare(zval *object, php_pqconn_object_t *obj, const char *decl)
1354 {
1355 PGresult *res;
1356 ZEND_RESULT_CODE rv;
1357
1358 if (!obj) {
1359 obj = PHP_PQ_OBJ(object, NULL);
1360 }
1361
1362 res = php_pq_exec(obj->intern->conn, decl);
1363
1364 if (!res) {
1365 rv = FAILURE;
1366 throw_exce(EX_RUNTIME, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn));
1367 } else {
1368 rv = php_pqres_success(res);
1369 php_pqres_clear(res);
1370 php_pqconn_notify_listeners(obj);
1371 }
1372
1373 return rv;
1374 }
1375
1376 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare, 0, 0, 3)
1377 ZEND_ARG_INFO(0, name)
1378 ZEND_ARG_INFO(0, flags)
1379 ZEND_ARG_INFO(0, query)
1380 ZEND_END_ARG_INFO();
1381 static PHP_METHOD(pqconn, declare) {
1382 zend_error_handling zeh;
1383 char *name_str, *query_str;
1384 size_t name_len, query_len;
1385 zend_long flags;
1386 ZEND_RESULT_CODE rv;
1387
1388 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1389 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &name_str, &name_len, &flags, &query_str, &query_len);
1390 zend_restore_error_handling(&zeh);
1391
1392 if (SUCCESS == rv) {
1393 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1394
1395 if (!obj->intern) {
1396 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1397 } else {
1398 int query_offset;
1399 char *decl = php_pqcur_declare_str(name_str, name_len, flags, query_str, query_len, &query_offset);
1400
1401 if (SUCCESS != php_pqconn_declare(getThis(), obj, decl)) {
1402 efree(decl);
1403 } else {
1404 php_pqcur_t *cur = php_pqcur_init(obj, name_str, decl, query_offset, flags);
1405
1406 RETVAL_OBJ(&php_pqcur_create_object_ex(php_pqcur_class_entry, cur)->zo);
1407 }
1408 }
1409 }
1410 }
1411
1412 ZEND_RESULT_CODE php_pqconn_declare_async(zval *object, php_pqconn_object_t *obj, const char *decl)
1413 {
1414 ZEND_RESULT_CODE rv;
1415
1416 if (!obj) {
1417 obj = PHP_PQ_OBJ(object, NULL);
1418 }
1419
1420 if (!PQsendQuery(obj->intern->conn, decl)) {
1421 rv = FAILURE;
1422 throw_exce(EX_IO, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn));
1423 } else {
1424 rv = SUCCESS;
1425 obj->intern->poller = PQconsumeInput;
1426 php_pqconn_notify_listeners(obj);
1427 }
1428
1429 return rv;
1430 }
1431
1432 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare_async, 0, 0, 2)
1433 ZEND_ARG_INFO(0, name)
1434 ZEND_ARG_INFO(0, flags)
1435 ZEND_ARG_INFO(0, query)
1436 ZEND_END_ARG_INFO();
1437 static PHP_METHOD(pqconn, declareAsync) {
1438 zend_error_handling zeh;
1439 char *name_str, *query_str;
1440 size_t name_len, query_len;
1441 zend_long flags;
1442 ZEND_RESULT_CODE rv;
1443
1444 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1445 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &name_str, &name_len, &flags, &query_str, &query_len);
1446 zend_restore_error_handling(&zeh);
1447
1448 if (SUCCESS == rv) {
1449 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1450
1451 if (!obj->intern) {
1452 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1453 } else {
1454 int query_offset;
1455 char *decl = php_pqcur_declare_str(name_str, name_len, flags, query_str, query_len, &query_offset);
1456
1457 if (SUCCESS != php_pqconn_declare_async(getThis(), obj, decl)) {
1458 efree(decl);
1459 } else {
1460 php_pqcur_t *cur = php_pqcur_init(obj, name_str, decl, query_offset, flags);
1461
1462 RETVAL_OBJ(&php_pqcur_create_object_ex(php_pqcur_class_entry, cur)->zo);
1463 }
1464 }
1465 }
1466 }
1467
1468 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
1469 ZEND_ARG_INFO(0, string)
1470 ZEND_END_ARG_INFO();
1471 static PHP_METHOD(pqconn, quote) {
1472 char *str;
1473 size_t len;
1474
1475 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
1476 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1477
1478 if (!obj->intern) {
1479 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1480 } else {
1481 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
1482
1483 if (!quoted) {
1484 php_error_docref(NULL, E_WARNING, "Failed to quote string (%s)", PHP_PQerrorMessage(obj->intern->conn));
1485 RETVAL_FALSE;
1486 } else {
1487 RETVAL_STRING(quoted);
1488 PQfreemem(quoted);
1489 }
1490 }
1491 }
1492 }
1493
1494 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
1495 ZEND_ARG_INFO(0, type)
1496 ZEND_END_ARG_INFO();
1497 static PHP_METHOD(pqconn, quoteName) {
1498 char *str;
1499 size_t len;
1500
1501 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
1502 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1503
1504 if (!obj->intern) {
1505 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1506 } else {
1507 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
1508
1509 if (!quoted) {
1510 php_error_docref(NULL, E_WARNING, "Failed to quote name (%s)", PHP_PQerrorMessage(obj->intern->conn));
1511 RETVAL_FALSE;
1512 } else {
1513 RETVAL_STRING(quoted);
1514 PQfreemem(quoted);
1515 }
1516 }
1517 }
1518 }
1519
1520 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
1521 ZEND_ARG_INFO(0, bytea)
1522 ZEND_END_ARG_INFO();
1523 static PHP_METHOD(pqconn, escapeBytea) {
1524 char *str;
1525 int len;
1526
1527 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
1528 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1529
1530 if (!obj->intern) {
1531 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1532 } else {
1533 size_t escaped_len;
1534 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
1535
1536 if (!escaped_str) {
1537 php_error_docref(NULL, E_WARNING, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
1538 RETVAL_FALSE;
1539 } else {
1540 RETVAL_STRINGL(escaped_str, escaped_len - 1);
1541 PQfreemem(escaped_str);
1542 }
1543 }
1544 }
1545 }
1546
1547 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
1548 ZEND_ARG_INFO(0, bytea)
1549 ZEND_END_ARG_INFO();
1550 static PHP_METHOD(pqconn, unescapeBytea) {
1551 char *str;
1552 size_t len;
1553
1554 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
1555 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1556
1557 if (!obj->intern) {
1558 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1559 } else {
1560 size_t unescaped_len;
1561 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
1562
1563 if (!unescaped_str) {
1564 php_error_docref(NULL, E_WARNING, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
1565 RETVAL_FALSE;
1566 } else {
1567 RETVAL_STRINGL(unescaped_str, unescaped_len);
1568 PQfreemem(unescaped_str);
1569 }
1570 }
1571 }
1572 }
1573
1574 ZEND_RESULT_CODE php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable)
1575 {
1576 ZEND_RESULT_CODE rv = FAILURE;
1577
1578 if (!conn_obj) {
1579 conn_obj = PHP_PQ_OBJ(zconn, NULL);
1580 }
1581
1582 if (!conn_obj->intern) {
1583 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1584 } else {
1585 PGresult *res;
1586 smart_str cmd = {0};
1587 const char *il = php_pq_isolation_level(&isolation);
1588
1589 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
1590 smart_str_appends(&cmd, il);
1591 smart_str_appends(&cmd, ", READ ");
1592 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
1593 smart_str_appends(&cmd, ",");
1594 smart_str_appends(&cmd, deferrable ? "" : " NOT");
1595 smart_str_appends(&cmd, " DEFERRABLE");
1596 smart_str_0(&cmd);
1597
1598 res = php_pq_exec(conn_obj->intern->conn, smart_str_v(&cmd));
1599
1600 if (!res) {
1601 throw_exce(EX_RUNTIME, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
1602 } else {
1603 rv = php_pqres_success(res);
1604 php_pqres_clear(res);
1605 php_pqconn_notify_listeners(conn_obj);
1606 }
1607
1608 smart_str_free(&cmd);
1609 }
1610
1611 return rv;
1612 }
1613
1614 ZEND_RESULT_CODE php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable)
1615 {
1616 ZEND_RESULT_CODE rv = FAILURE;
1617
1618 if (!conn_obj) {
1619 conn_obj = PHP_PQ_OBJ(zconn, NULL);
1620 }
1621
1622 if (!conn_obj->intern) {
1623 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1624 } else {
1625 smart_str cmd = {0};
1626 const char *il = php_pq_isolation_level(&isolation);
1627
1628 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
1629 smart_str_appends(&cmd, il);
1630 smart_str_appends(&cmd, ", READ ");
1631 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
1632 smart_str_appends(&cmd, ",");
1633 smart_str_appends(&cmd, deferrable ? "" : "NOT ");
1634 smart_str_appends(&cmd, " DEFERRABLE");
1635 smart_str_0(&cmd);
1636
1637 if (!PQsendQuery(conn_obj->intern->conn, smart_str_v(&cmd))) {
1638 throw_exce(EX_IO, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
1639 } else {
1640 rv = SUCCESS;
1641 conn_obj->intern->poller = PQconsumeInput;
1642 php_pqconn_notify_listeners(conn_obj);
1643 }
1644
1645 smart_str_free(&cmd);
1646 }
1647
1648 return rv;
1649 }
1650
1651 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
1652 ZEND_ARG_INFO(0, isolation)
1653 ZEND_ARG_INFO(0, readonly)
1654 ZEND_ARG_INFO(0, deferrable)
1655 ZEND_END_ARG_INFO();
1656 static PHP_METHOD(pqconn, startTransaction) {
1657 zend_error_handling zeh;
1658 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1659 zend_long isolation = obj->intern ? obj->intern->default_txn_isolation : PHP_PQTXN_READ_COMMITTED;
1660 zend_bool readonly = obj->intern ? obj->intern->default_txn_readonly : 0;
1661 zend_bool deferrable = obj->intern ? obj->intern->default_txn_deferrable : 0;
1662 ZEND_RESULT_CODE rv;
1663
1664 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1665 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|lbb", &isolation, &readonly, &deferrable);
1666 zend_restore_error_handling(&zeh);
1667
1668 if (SUCCESS == rv) {
1669 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable);
1670
1671 if (SUCCESS == rv) {
1672 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
1673
1674 php_pq_object_addref(obj);
1675 txn->conn = obj;
1676 txn->open = 1;
1677 txn->isolation = isolation;
1678 txn->readonly = readonly;
1679 txn->deferrable = deferrable;
1680
1681 RETVAL_OBJ(&php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn)->zo);
1682 }
1683 }
1684 }
1685
1686 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
1687 ZEND_ARG_INFO(0, isolation)
1688 ZEND_ARG_INFO(0, readonly)
1689 ZEND_ARG_INFO(0, deferrable)
1690 ZEND_END_ARG_INFO();
1691 static PHP_METHOD(pqconn, startTransactionAsync) {
1692 zend_error_handling zeh;
1693 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1694 zend_long isolation = obj->intern ? obj->intern->default_txn_isolation : PHP_PQTXN_READ_COMMITTED;
1695 zend_bool readonly = obj->intern ? obj->intern->default_txn_readonly : 0;
1696 zend_bool deferrable = obj->intern ? obj->intern->default_txn_deferrable : 0;
1697 ZEND_RESULT_CODE rv;
1698
1699 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1700 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|lbb", &isolation, &readonly, &deferrable);
1701 zend_restore_error_handling(&zeh);
1702
1703 if (SUCCESS == rv) {
1704 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable);
1705
1706 if (SUCCESS == rv) {
1707 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
1708
1709 php_pq_object_addref(obj);
1710 txn->conn = obj;
1711 txn->open = 1;
1712 txn->isolation = isolation;
1713 txn->readonly = readonly;
1714 txn->deferrable = deferrable;
1715
1716 RETVAL_OBJ(&php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn)->zo);
1717 }
1718 }
1719 }
1720
1721 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
1722 ZEND_ARG_INFO(0, stdio_stream)
1723 ZEND_END_ARG_INFO();
1724 static PHP_METHOD(pqconn, trace) {
1725 zval *zstream = NULL;
1726
1727 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &zstream)) {
1728 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1729
1730 if (!obj->intern) {
1731 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1732 } else {
1733 if (!zstream) {
1734 PQuntrace(obj->intern->conn);
1735 RETVAL_TRUE;
1736 } else {
1737 FILE *fp;
1738 php_stream *stream = NULL;
1739
1740 php_stream_from_zval(stream, zstream);
1741
1742 if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
1743 RETVAL_FALSE;
1744 } else {
1745 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
1746 PQtrace(obj->intern->conn, fp);
1747 RETVAL_TRUE;
1748 }
1749 }
1750 }
1751 }
1752 }
1753
1754 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_off, 0, 0, 1)
1755 ZEND_ARG_INFO(0, type)
1756 ZEND_END_ARG_INFO();
1757 static PHP_METHOD(pqconn, off) {
1758 zend_error_handling zeh;
1759 zend_string *type;
1760 ZEND_RESULT_CODE rv;
1761
1762 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1763 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "S", &type);
1764 zend_restore_error_handling(&zeh);
1765
1766 if (SUCCESS == rv) {
1767 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1768
1769 if (!obj->intern) {
1770 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1771 } else {
1772 RETURN_BOOL(SUCCESS == zend_hash_del(&obj->intern->eventhandlers, type));
1773 }
1774 }
1775 }
1776
1777 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_on, 0, 0, 2)
1778 ZEND_ARG_INFO(0, type)
1779 ZEND_ARG_INFO(0, callable)
1780 ZEND_END_ARG_INFO();
1781 static PHP_METHOD(pqconn, on) {
1782 zend_error_handling zeh;
1783 char *type_str;
1784 size_t type_len;
1785 php_pq_callback_t cb = {{0}};
1786 ZEND_RESULT_CODE rv;
1787
1788 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1789 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &type_str, &type_len, &cb.fci, &cb.fcc);
1790 zend_restore_error_handling(&zeh);
1791
1792 if (SUCCESS == rv) {
1793 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1794
1795 if (!obj->intern) {
1796 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1797 } else {
1798 RETVAL_LONG(php_pqconn_add_eventhandler(obj, type_str, type_len, &cb));
1799 }
1800 }
1801 }
1802
1803 struct apply_set_converter_arg {
1804 HashTable *ht;
1805 zval *zconv;
1806 unsigned add:1;
1807 };
1808
1809 static int apply_set_converter(zval *zoid, void *a)
1810 {
1811 zend_long oid = zval_get_long(zoid);
1812 struct apply_set_converter_arg *arg = a;
1813
1814 if (arg->add) {
1815 Z_ADDREF_P(arg->zconv);
1816 zend_hash_index_update(arg->ht, oid, arg->zconv);
1817 } else {
1818 zend_hash_index_del(arg->ht, oid);
1819 }
1820
1821 return ZEND_HASH_APPLY_KEEP;
1822 }
1823
1824 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_set_converter, 0, 0, 1)
1825 ZEND_ARG_OBJ_INFO(0, converter, pq\\Converter, 0)
1826 ZEND_END_ARG_INFO();
1827 static PHP_METHOD(pqconn, setConverter) {
1828 ZEND_RESULT_CODE rv;
1829 zend_error_handling zeh;
1830 zval *zcnv;
1831
1832 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1833 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcnv, php_pqconv_class_entry);
1834 zend_restore_error_handling(&zeh);
1835
1836 if (SUCCESS == rv) {
1837 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1838
1839 if (!obj->intern) {
1840 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1841 } else {
1842 zval tmp, zoids;
1843 struct apply_set_converter_arg arg = {NULL};
1844
1845 ZVAL_NULL(&zoids);
1846 zend_call_method_with_0_params(zcnv, NULL, NULL, "converttypes", &zoids);
1847 ZVAL_DUP(&tmp, &zoids);
1848 convert_to_array(&tmp);
1849
1850 arg.ht = &obj->intern->converters;
1851 arg.zconv = zcnv;
1852 arg.add = 1;
1853
1854 zend_hash_apply_with_argument(Z_ARRVAL(tmp), apply_set_converter, &arg);
1855
1856 zval_ptr_dtor(&tmp);
1857 zval_ptr_dtor(&zoids);
1858 }
1859 }
1860 }
1861
1862 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unset_converter, 0, 0, 1)
1863 ZEND_ARG_OBJ_INFO(0, converter, pq\\Converter, 0)
1864 ZEND_END_ARG_INFO();
1865 static PHP_METHOD(pqconn, unsetConverter) {
1866 ZEND_RESULT_CODE rv;
1867 zend_error_handling zeh;
1868 zval *zcnv;
1869
1870 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1871 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcnv, php_pqconv_class_entry);
1872 zend_restore_error_handling(&zeh);
1873
1874 if (SUCCESS == rv) {
1875 php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1876
1877 if (!obj->intern) {
1878 throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized");
1879 } else {
1880 zval tmp, zoids;
1881 struct apply_set_converter_arg arg = {NULL};
1882
1883 ZVAL_NULL(&zoids);
1884 zend_call_method_with_0_params(zcnv, NULL, NULL, "converttypes", &zoids);
1885 ZVAL_DUP(&tmp, &zoids);
1886 convert_to_array(&tmp);
1887
1888 arg.ht = &obj->intern->converters;
1889 arg.zconv = zcnv;
1890 arg.add = 0;
1891
1892 zend_hash_apply_with_argument(Z_ARRVAL(tmp), apply_set_converter, &arg);
1893
1894 zval_ptr_dtor(&tmp);
1895 zval_ptr_dtor(&zoids);
1896 }
1897 }
1898 }
1899
1900 static zend_function_entry php_pqconn_methods[] = {
1901 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1902 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
1903 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
1904 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
1905 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
1906 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
1907 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
1908 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
1909 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
1910 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
1911 PHP_ME(pqconn, declare, ai_pqconn_declare, ZEND_ACC_PUBLIC)
1912 PHP_ME(pqconn, declareAsync, ai_pqconn_declare_async, ZEND_ACC_PUBLIC)
1913 PHP_ME(pqconn, unlisten, ai_pqconn_unlisten, ZEND_ACC_PUBLIC)
1914 PHP_ME(pqconn, unlistenAsync, ai_pqconn_unlisten_async, ZEND_ACC_PUBLIC)
1915 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
1916 PHP_ME(pqconn, listenAsync, ai_pqconn_listen_async, ZEND_ACC_PUBLIC)
1917 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
1918 PHP_ME(pqconn, notifyAsync, ai_pqconn_notify_async, ZEND_ACC_PUBLIC)
1919 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
1920 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
1921 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
1922 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
1923 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
1924 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
1925 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
1926 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
1927 PHP_ME(pqconn, off, ai_pqconn_off, ZEND_ACC_PUBLIC)
1928 PHP_ME(pqconn, on, ai_pqconn_on, ZEND_ACC_PUBLIC)
1929 PHP_ME(pqconn, setConverter, ai_pqconn_set_converter, ZEND_ACC_PUBLIC)
1930 PHP_ME(pqconn, unsetConverter, ai_pqconn_unset_converter, ZEND_ACC_PUBLIC)
1931 {0}
1932 };
1933
1934 PHP_MSHUTDOWN_FUNCTION(pqconn)
1935 {
1936 php_persistent_handle_cleanup(PHP_PQ_G->connection.name, NULL);
1937 zend_string_release(PHP_PQ_G->connection.name);
1938 zend_hash_destroy(&php_pqconn_object_prophandlers);
1939 return SUCCESS;
1940 }
1941
1942 PHP_MINIT_FUNCTION(pqconn)
1943 {
1944 zend_class_entry ce = {0};
1945 php_pq_object_prophandler_t ph = {0};
1946
1947 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
1948 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL);
1949 php_pqconn_class_entry->create_object = php_pqconn_create_object;
1950
1951 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1952 php_pqconn_object_handlers.offset = XtOffsetOf(php_pqconn_object_t, zo);
1953 php_pqconn_object_handlers.free_obj = php_pqconn_object_free;
1954 php_pqconn_object_handlers.read_property = php_pq_object_read_prop;
1955 php_pqconn_object_handlers.write_property = php_pq_object_write_prop;
1956 php_pqconn_object_handlers.clone_obj = NULL;
1957 php_pqconn_object_handlers.get_property_ptr_ptr = NULL;
1958 php_pqconn_object_handlers.get_gc = php_pq_object_get_gc;
1959 php_pqconn_object_handlers.get_properties = php_pq_object_properties;
1960 php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info;
1961
1962 zend_hash_init(&php_pqconn_object_prophandlers, 22, NULL, php_pq_object_prophandler_dtor, 1);
1963
1964 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC);
1965 ph.read = php_pqconn_object_read_status;
1966 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "status", sizeof("status")-1, (void *) &ph, sizeof(ph));
1967
1968 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC);
1969 ph.read = php_pqconn_object_read_transaction_status;
1970 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus")-1, (void *) &ph, sizeof(ph));
1971
1972 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC);
1973 ph.read = NULL; /* forward to std prophandler */
1974 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "socket", sizeof("socket")-1, (void *) &ph, sizeof(ph));
1975
1976 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC);
1977 ph.read = php_pqconn_object_read_error_message;
1978 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage")-1, (void *) &ph, sizeof(ph));
1979
1980 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC);
1981 ph.read = php_pqconn_object_read_busy;
1982 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "busy", sizeof("busy")-1, (void *) &ph, sizeof(ph));
1983
1984 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC);
1985 ph.read = php_pqconn_object_read_encoding;
1986 ph.write = php_pqconn_object_write_encoding;
1987 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding")-1, (void *) &ph, sizeof(ph));
1988 ph.write = NULL;
1989
1990 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC);
1991 ph.read = php_pqconn_object_read_unbuffered;
1992 ph.write = php_pqconn_object_write_unbuffered;
1993 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered")-1, (void *) &ph, sizeof(ph));
1994 ph.write = NULL;
1995
1996 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC);
1997 ph.read = php_pqconn_object_read_db;
1998 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "db", sizeof("db")-1, (void *) &ph, sizeof(ph));
1999
2000 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC);
2001 ph.read = php_pqconn_object_read_user;
2002 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "user", sizeof("user")-1, (void *) &ph, sizeof(ph));
2003
2004 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC);
2005 ph.read = php_pqconn_object_read_pass;
2006 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "pass", sizeof("pass")-1, (void *) &ph, sizeof(ph));
2007
2008 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC);
2009 ph.read = php_pqconn_object_read_host;
2010 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "host", sizeof("host")-1, (void *) &ph, sizeof(ph));
2011
2012 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC);
2013 ph.read = php_pqconn_object_read_port;
2014 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "port", sizeof("port")-1, (void *) &ph, sizeof(ph));
2015
2016 #if HAVE_PQCONNINFO
2017 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC);
2018 ph.read = php_pqconn_object_read_params;
2019 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "params", sizeof("params")-1, (void *) &ph, sizeof(ph));
2020 #endif
2021
2022 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC);
2023 ph.read = php_pqconn_object_read_options;
2024 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "options", sizeof("options")-1, (void *) &ph, sizeof(ph));
2025
2026 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC);
2027 ph.read = php_pqconn_object_read_event_handlers;
2028 ph.gc = php_pqconn_object_gc_event_handlers;
2029 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers")-1, (void *) &ph, sizeof(ph));
2030 ph.gc = NULL;
2031
2032 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("listeners"), ZEND_ACC_PUBLIC);
2033 ph.read = php_pqconn_object_read_listeners;
2034 ph.gc = php_pqconn_object_gc_listeners;
2035 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "listeners", sizeof("listeners")-1, (void *) &ph, sizeof(ph));
2036 ph.gc = NULL;
2037
2038 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("converters"), ZEND_ACC_PUBLIC);
2039 ph.read = php_pqconn_object_read_converters;
2040 ph.gc = php_pqconn_object_gc_converters;
2041 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "converters", sizeof("converters")-1, (void *) &ph, sizeof(ph));
2042 ph.gc = NULL;
2043
2044 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultFetchType"), 0, ZEND_ACC_PUBLIC);
2045 ph.read = php_pqconn_object_read_def_fetch_type;
2046 ph.write = php_pqconn_object_write_def_fetch_type;
2047 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultFetchType", sizeof("defaultFetchType")-1, (void *) &ph, sizeof(ph));
2048 ph.write = NULL;
2049
2050 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultTransactionIsolation"), 0, ZEND_ACC_PUBLIC);
2051 ph.read = php_pqconn_object_read_def_txn_isolation;
2052 ph.write = php_pqconn_object_write_def_txn_isolation;
2053 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionIsolation", sizeof("defaultTransactionIsolation")-1, (void *) &ph, sizeof(ph));
2054 ph.write = NULL;
2055
2056 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("defaultTransactionReadonly"), 0, ZEND_ACC_PUBLIC);
2057 ph.read = php_pqconn_object_read_def_txn_readonly;
2058 ph.write = php_pqconn_object_write_def_txn_readonly;
2059 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionReadonly", sizeof("defaultTransactionReadonly")-1, (void *) &ph, sizeof(ph));
2060 ph.write = NULL;
2061
2062 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("defaultTransactionDeferrable"), 0, ZEND_ACC_PUBLIC);
2063 ph.read = php_pqconn_object_read_def_txn_deferrable;
2064 ph.write = php_pqconn_object_write_def_txn_deferrable;
2065 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionDeferrable", sizeof("defaultTransactionDeferrable")-1, (void *) &ph, sizeof(ph));
2066 ph.write = NULL;
2067
2068 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultAutoConvert"), PHP_PQRES_CONV_ALL, ZEND_ACC_PUBLIC);
2069 ph.read = php_pqconn_object_read_def_auto_conv;
2070 ph.write = php_pqconn_object_write_def_auto_conv;
2071 zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultAutoConvert", sizeof("defaultAutoConvert")-1, (void *) &ph, sizeof(ph));
2072 ph.write = NULL;
2073
2074 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK);
2075 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD);
2076 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED);
2077 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE);
2078 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE);
2079 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK);
2080 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP);
2081 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV);
2082
2083 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE);
2084 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE);
2085 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS);
2086 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR);
2087 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN);
2088
2089 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED);
2090 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING);
2091 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING);
2092 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK);
2093
2094 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_NOTICE"), ZEND_STRL("notice"));
2095 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESULT"), ZEND_STRL("result"));
2096 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESET"), ZEND_STRL("reset"));
2097
2098 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("ASYNC"), 0x1);
2099 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("PERSISTENT"), 0x2);
2100
2101 PHP_PQ_G->connection.name = zend_string_init(ZEND_STRL("pq\\Connection"), 1);
2102
2103 return php_persistent_handle_provide(PHP_PQ_G->connection.name, php_pqconn_get_resource_factory_ops(), NULL, NULL);
2104 }
2105
2106 /*
2107 * Local variables:
2108 * tab-width: 4
2109 * c-basic-offset: 4
2110 * End:
2111 * vim600: noet sw=4 ts=4 fdm=marker
2112 * vim<600: noet sw=4 ts=4
2113 */