1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2017 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andrey Hristov <andrey@php.net> |
16 | Ulf Wendel <uw@php.net> |
17 | Georg Richter <georg@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include "php.h"
22 #include "mysqlnd.h"
23 #include "mysqlnd_wireprotocol.h"
24 #include "mysqlnd_priv.h"
25 #include "mysqlnd_result.h"
26 #include "mysqlnd_statistics.h"
27 #include "mysqlnd_charset.h"
28 #include "mysqlnd_debug.h"
29 #include "mysqlnd_reverse_api.h"
30 #include "mysqlnd_ext_plugin.h"
31
32 static zend_bool mysqlnd_library_initted = FALSE;
33
34 static struct st_mysqlnd_plugin_core mysqlnd_plugin_core =
35 {
36 {
37 MYSQLND_PLUGIN_API_VERSION,
38 "mysqlnd",
39 MYSQLND_VERSION_ID,
40 PHP_MYSQLND_VERSION,
41 "PHP License 3.01",
42 "Andrey Hristov <andrey@php.net>, Ulf Wendel <uw@php.net>, Georg Richter <georg@php.net>",
43 {
44 NULL, /* will be filled later */
45 mysqlnd_stats_values_names,
46 },
47 {
48 NULL /* plugin shutdown */
49 }
50 }
51 };
52
53
54 /* {{{ mysqlnd_library_end */
mysqlnd_library_end(void)55 PHPAPI void mysqlnd_library_end(void)
56 {
57 if (mysqlnd_library_initted == TRUE) {
58 mysqlnd_plugin_subsystem_end();
59 mysqlnd_stats_end(mysqlnd_global_stats, 1);
60 mysqlnd_global_stats = NULL;
61 mysqlnd_library_initted = FALSE;
62 mysqlnd_reverse_api_end();
63 }
64 }
65 /* }}} */
66
67
68 /* {{{ mysqlnd_library_init */
mysqlnd_library_init(void)69 PHPAPI void mysqlnd_library_init(void)
70 {
71 if (mysqlnd_library_initted == FALSE) {
72 mysqlnd_library_initted = TRUE;
73 mysqlnd_conn_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_conn));
74 mysqlnd_conn_data_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_conn_data));
75 _mysqlnd_init_ps_subsystem();
76 /* Should be calloc, as mnd_calloc will reference LOCK_access*/
77 mysqlnd_stats_init(&mysqlnd_global_stats, STAT_LAST, 1);
78 mysqlnd_plugin_subsystem_init();
79 {
80 mysqlnd_plugin_core.plugin_header.plugin_stats.values = mysqlnd_global_stats;
81 mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_plugin_core);
82 }
83 #if defined(MYSQLND_DBG_ENABLED) && MYSQLND_DBG_ENABLED == 1
84 mysqlnd_example_plugin_register();
85 #endif
86 mysqlnd_debug_trace_plugin_register();
87 mysqlnd_register_builtin_authentication_plugins();
88
89 mysqlnd_reverse_api_init();
90 }
91 }
92 /* }}} */
93
94
95
96 /* {{{ mysqlnd_error_list_pdtor */
97 static void
mysqlnd_error_list_pdtor(void * pDest)98 mysqlnd_error_list_pdtor(void * pDest)
99 {
100 MYSQLND_ERROR_LIST_ELEMENT * element = (MYSQLND_ERROR_LIST_ELEMENT *) pDest;
101
102 DBG_ENTER("mysqlnd_error_list_pdtor");
103 if (element->error) {
104 mnd_pefree(element->error, TRUE);
105 }
106 DBG_VOID_RETURN;
107 }
108 /* }}} */
109
110
111 /* {{{ mysqlnd_object_factory::get_connection */
112 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,get_connection)113 MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(zend_bool persistent)
114 {
115 size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
116 size_t alloc_size_ret_data = sizeof(MYSQLND_CONN_DATA) + mysqlnd_plugin_count() * sizeof(void *);
117 MYSQLND * new_object;
118 MYSQLND_CONN_DATA * data;
119
120 DBG_ENTER("mysqlnd_driver::get_connection");
121 DBG_INF_FMT("persistent=%u", persistent);
122 new_object = mnd_pecalloc(1, alloc_size_ret, persistent);
123 if (!new_object) {
124 DBG_RETURN(NULL);
125 }
126 new_object->data = mnd_pecalloc(1, alloc_size_ret_data, persistent);
127 if (!new_object->data) {
128 mnd_pefree(new_object, persistent);
129 DBG_RETURN(NULL);
130 }
131 new_object->persistent = persistent;
132 new_object->m = mysqlnd_conn_get_methods();
133 data = new_object->data;
134
135 data->error_info = &(data->error_info_impl);
136 data->options = &(data->options_impl);
137 data->upsert_status = &(data->upsert_status_impl);
138
139 data->persistent = persistent;
140 data->m = mysqlnd_conn_data_get_methods();
141 CONN_SET_STATE(data, CONN_ALLOCED);
142 data->m->get_reference(data);
143
144 if (PASS != data->m->init(data)) {
145 new_object->m->dtor(new_object);
146 DBG_RETURN(NULL);
147 }
148
149 data->error_info->error_list = mnd_pecalloc(1, sizeof(zend_llist), persistent);
150 if (!data->error_info->error_list) {
151 new_object->m->dtor(new_object);
152 DBG_RETURN(NULL);
153 } else {
154 zend_llist_init(data->error_info->error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t)mysqlnd_error_list_pdtor, persistent);
155 }
156
157 DBG_RETURN(new_object);
158 }
159 /* }}} */
160
161
162 /* {{{ mysqlnd_object_factory::clone_connection_object */
163 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,clone_connection_object)164 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object)(MYSQLND * to_be_cloned)
165 {
166 size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
167 MYSQLND * new_object;
168
169 DBG_ENTER("mysqlnd_driver::clone_connection_object");
170 DBG_INF_FMT("persistent=%u", to_be_cloned->persistent);
171 if (!to_be_cloned || !to_be_cloned->data) {
172 DBG_RETURN(NULL);
173 }
174 new_object = mnd_pecalloc(1, alloc_size_ret, to_be_cloned->persistent);
175 if (!new_object) {
176 DBG_RETURN(NULL);
177 }
178 new_object->persistent = to_be_cloned->persistent;
179 new_object->m = to_be_cloned->m;
180
181 new_object->data = to_be_cloned->data->m->get_reference(to_be_cloned->data);
182 if (!new_object->data) {
183 new_object->m->dtor(new_object);
184 new_object = NULL;
185 }
186 DBG_RETURN(new_object);
187 }
188 /* }}} */
189
190
191 /* {{{ mysqlnd_object_factory::get_prepared_statement */
192 static MYSQLND_STMT *
MYSQLND_METHOD(mysqlnd_object_factory,get_prepared_statement)193 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA * const conn)
194 {
195 size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
196 MYSQLND_STMT * ret = mnd_pecalloc(1, alloc_size, conn->persistent);
197 MYSQLND_STMT_DATA * stmt = NULL;
198
199 DBG_ENTER("mysqlnd_object_factory::get_prepared_statement");
200 do {
201 if (!ret) {
202 break;
203 }
204 ret->m = mysqlnd_stmt_get_methods();
205 ret->persistent = conn->persistent;
206
207 stmt = ret->data = mnd_pecalloc(1, sizeof(MYSQLND_STMT_DATA), conn->persistent);
208 DBG_INF_FMT("stmt=%p", stmt);
209 if (!stmt) {
210 break;
211 }
212 stmt->persistent = conn->persistent;
213 stmt->error_info = &(stmt->error_info_impl);
214 stmt->upsert_status = &(stmt->upsert_status_impl);
215 stmt->state = MYSQLND_STMT_INITTED;
216 stmt->execute_cmd_buffer.length = 4096;
217 stmt->execute_cmd_buffer.buffer = mnd_pemalloc(stmt->execute_cmd_buffer.length, stmt->persistent);
218 if (!stmt->execute_cmd_buffer.buffer) {
219 break;
220 }
221
222 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
223 /*
224 Mark that we reference the connection, thus it won't be
225 be destructed till there is open statements. The last statement
226 or normal query result will close it then.
227 */
228 stmt->conn = conn->m->get_reference(conn);
229 stmt->error_info->error_list = mnd_pecalloc(1, sizeof(zend_llist), ret->persistent);
230 if (!stmt->error_info->error_list) {
231 break;
232 }
233
234 zend_llist_init(stmt->error_info->error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t) mysqlnd_error_list_pdtor, conn->persistent);
235
236 DBG_RETURN(ret);
237 } while (0);
238
239 SET_OOM_ERROR(*conn->error_info);
240 if (ret) {
241 ret->m->dtor(ret, TRUE);
242 ret = NULL;
243 }
244 DBG_RETURN(NULL);
245 }
246 /* }}} */
247
248
249 /* {{{ mysqlnd_object_factory::get_io_channel */
250 PHPAPI MYSQLND_NET *
MYSQLND_METHOD(mysqlnd_object_factory,get_io_channel)251 MYSQLND_METHOD(mysqlnd_object_factory, get_io_channel)(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
252 {
253 size_t net_alloc_size = sizeof(MYSQLND_NET) + mysqlnd_plugin_count() * sizeof(void *);
254 size_t net_data_alloc_size = sizeof(MYSQLND_NET_DATA) + mysqlnd_plugin_count() * sizeof(void *);
255 MYSQLND_NET * net = mnd_pecalloc(1, net_alloc_size, persistent);
256 MYSQLND_NET_DATA * net_data = mnd_pecalloc(1, net_data_alloc_size, persistent);
257
258 DBG_ENTER("mysqlnd_object_factory::get_io_channel");
259 DBG_INF_FMT("persistent=%u", persistent);
260 if (net && net_data) {
261 net->data = net_data;
262 net->persistent = net->data->persistent = persistent;
263 net->data->m = *mysqlnd_net_get_methods();
264
265 if (PASS != net->data->m.init(net, stats, error_info)) {
266 net->data->m.dtor(net, stats, error_info);
267 net = NULL;
268 }
269 } else {
270 if (net_data) {
271 mnd_pefree(net_data, persistent);
272 net_data = NULL;
273 }
274 if (net) {
275 mnd_pefree(net, persistent);
276 net = NULL;
277 }
278 }
279 DBG_RETURN(net);
280 }
281 /* }}} */
282
283
284 /* {{{ mysqlnd_object_factory::get_protocol_decoder */
285 static MYSQLND_PROTOCOL *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_decoder)286 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_decoder)(zend_bool persistent)
287 {
288 size_t alloc_size = sizeof(MYSQLND_PROTOCOL) + mysqlnd_plugin_count() * sizeof(void *);
289 MYSQLND_PROTOCOL *ret = mnd_pecalloc(1, alloc_size, persistent);
290
291 DBG_ENTER("mysqlnd_object_factory::get_protocol_decoder");
292 DBG_INF_FMT("persistent=%u", persistent);
293 if (ret) {
294 ret->persistent = persistent;
295 ret->m = mysqlnd_mysqlnd_protocol_methods;
296 }
297
298 DBG_RETURN(ret);
299 }
300 /* }}} */
301
302
303 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
304 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
305 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
306 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
307 MYSQLND_METHOD(mysqlnd_object_factory, get_io_channel),
308 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_decoder)
309 MYSQLND_CLASS_METHODS_END;
310
311 /*
312 * Local variables:
313 * tab-width: 4
314 * c-basic-offset: 4
315 * End:
316 * vim600: noet sw=4 ts=4 fdm=marker
317 * vim<600: noet sw=4 ts=4
318 */
319