64d94b74f830877163af835c87a3dd0b436e62b8
[m6w6/ext-pq] / src / php_pqconn_event.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
24 #include "php_pq.h"
25 #include "php_pq_misc.h"
26 #include "php_pq_object.h"
27 #include "php_pqconn_event.h"
28 #include "php_pqstm.h"
29 #include "php_pqres.h"
30
31 static int apply_event(void *p, void *a TSRMLS_DC)
32 {
33 php_pq_callback_t *cb = p;
34 zval *args = a;
35 zval *retval = NULL;
36
37 zend_fcall_info_args(&cb->fci, args TSRMLS_CC);
38 zend_fcall_info_call(&cb->fci, &cb->fcc, &retval, NULL TSRMLS_CC);
39 if (retval) {
40 zval_ptr_dtor(&retval);
41 }
42
43 return ZEND_HASH_APPLY_KEEP;
44 }
45
46
47 static inline PGresult *relisten(PGconn *conn, const char *channel_str, size_t channel_len TSRMLS_DC)
48 {
49 char *quoted_channel = PQescapeIdentifier(conn, channel_str, channel_len);
50 PGresult *res = NULL;
51
52 if (quoted_channel) {
53 smart_str cmd = {0};
54
55 smart_str_appends(&cmd, "LISTEN ");
56 smart_str_appends(&cmd, quoted_channel);
57 smart_str_0(&cmd);
58
59 res = PQexec(conn, cmd.c);
60
61 smart_str_free(&cmd);
62 PQfreemem(quoted_channel);
63 }
64
65 return res;
66 }
67
68 static int apply_relisten(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
69 {
70 php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
71 PGresult *res = relisten(obj->intern->conn, key->arKey, key->nKeyLength - 1 TSRMLS_CC);
72
73 if (res) {
74 php_pqres_clear(res);
75 }
76
77 return ZEND_HASH_APPLY_KEEP;
78 }
79
80 static int apply_reprepare(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
81 {
82 php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
83 php_pqstm_t *stm = *(php_pqstm_object_t **) p;
84
85 php_pqconn_prepare(NULL, obj, stm->name, stm->query, stm->params TSRMLS_CC);
86
87 return ZEND_HASH_APPLY_KEEP;
88 }
89
90 static void php_pqconn_event_connreset(PGEventConnReset *event)
91 {
92 php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event);
93
94 if (data) {
95 HashTable *evhs;
96 TSRMLS_DF(data);
97
98 /* restore listeners */
99 zend_hash_apply_with_arguments(&data->obj->intern->listeners TSRMLS_CC, apply_relisten, 1, data->obj);
100
101 /* restore statements */
102 zend_hash_apply_with_arguments(&data->obj->intern->statements TSRMLS_CC, apply_reprepare, 1, data->obj);
103
104 /* eventhandler */
105 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("reset"), (void *) &evhs)) {
106 zval *args, *connection = NULL;
107
108 MAKE_STD_ZVAL(args);
109 array_init(args);
110 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
111 add_next_index_zval(args, connection);
112 zend_hash_apply_with_argument(evhs, apply_event, args TSRMLS_CC);
113 zval_ptr_dtor(&args);
114 }
115 }
116 }
117
118 static void php_pqconn_event_resultcreate(PGEventResultCreate *event)
119 {
120 php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event);
121
122 if (data) {
123 php_pqres_object_t *obj;
124 HashTable *evhs;
125 TSRMLS_DF(data);
126
127 php_pqres_init_instance_data(event->result, data->obj, &obj TSRMLS_CC);
128
129 /* event listener */
130 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) {
131 zval *args, *connection = NULL, *res = NULL;
132
133 MAKE_STD_ZVAL(args);
134 array_init(args);
135 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
136 add_next_index_zval(args, connection);
137 php_pq_object_to_zval(obj, &res TSRMLS_CC);
138 add_next_index_zval(args, res);
139 zend_hash_apply_with_argument(evhs, apply_event, args TSRMLS_CC);
140 zval_ptr_dtor(&args);
141 }
142
143 /* async callback */
144 if (php_pq_callback_is_enabled(&data->obj->intern->onevent)) {
145 zval *res = NULL;
146
147 php_pq_object_to_zval(obj, &res TSRMLS_CC);
148 zend_fcall_info_argn(&data->obj->intern->onevent.fci TSRMLS_CC, 1, &res);
149 zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL TSRMLS_CC);
150 zval_ptr_dtor(&res);
151 }
152
153 }
154 }
155
156 static void php_pqconn_event_resultdestroy(PGEventResultDestroy *event)
157 {
158 php_pqres_object_t *obj = PQresultInstanceData(event->result, php_pqconn_event);
159
160 if (obj) {
161 obj->intern->res = NULL;
162 }
163 }
164
165 int php_pqconn_event(PGEventId id, void *e, void *data)
166 {
167 switch (id) {
168 case PGEVT_CONNRESET:
169 php_pqconn_event_connreset(e);
170 break;
171 case PGEVT_RESULTCREATE:
172 php_pqconn_event_resultcreate(e);
173 break;
174 case PGEVT_RESULTDESTROY:
175 php_pqconn_event_resultdestroy(e);
176 break;
177 default:
178 break;
179 }
180
181 return 1;
182 }
183
184 php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj TSRMLS_DC)
185 {
186 php_pqconn_event_data_t *data = emalloc(sizeof(*data));
187
188 data->obj = obj;
189 TSRMLS_CF(data);
190
191 return data;
192 }
193
194 void php_pqconn_notice_recv(void *p, const PGresult *res)
195 {
196 php_pqconn_event_data_t *data = p;
197
198 if (data) {
199 HashTable *evhs;
200 TSRMLS_DF(data);
201
202 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("notice"), (void *) &evhs)) {
203 zval *args, *connection = NULL;
204
205 MAKE_STD_ZVAL(args);
206 array_init(args);
207 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
208 add_next_index_zval(args, connection);
209 add_next_index_string(args, PHP_PQresultErrorMessage(res), 1);
210 zend_hash_apply_with_argument(evhs, apply_event, args TSRMLS_CC);
211 zval_ptr_dtor(&args);
212 }
213 }
214 }
215
216 void php_pqconn_notice_ignore(void *p, const PGresult *res)
217 {
218 }
219
220 /*
221 * Local variables:
222 * tab-width: 4
223 * c-basic-offset: 4
224 * End:
225 * vim600: noet sw=4 ts=4 fdm=marker
226 * vim<600: noet sw=4 ts=4
227 */