1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2018 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 +----------------------------------------------------------------------+
18 */
19
20 #include "php.h"
21 #include "mysqlnd.h"
22 #include "mysqlnd_vio.h"
23 #include "mysqlnd_protocol_frame_codec.h"
24 #include "mysqlnd_wireprotocol.h"
25 #include "mysqlnd_connection.h"
26 #include "mysqlnd_ps.h"
27 #include "mysqlnd_plugin.h"
28 #include "mysqlnd_priv.h"
29 #include "mysqlnd_statistics.h"
30 #include "mysqlnd_debug.h"
31 #include "mysqlnd_reverse_api.h"
32 #include "mysqlnd_ext_plugin.h"
33
34 static zend_bool mysqlnd_library_initted = FALSE;
35
36 static struct st_mysqlnd_plugin_core mysqlnd_plugin_core =
37 {
38 {
39 MYSQLND_PLUGIN_API_VERSION,
40 "mysqlnd",
41 MYSQLND_VERSION_ID,
42 PHP_MYSQLND_VERSION,
43 "PHP License 3.01",
44 "Andrey Hristov <andrey@php.net>, Ulf Wendel <uw@php.net>, Georg Richter <georg@php.net>",
45 {
46 NULL, /* will be filled later */
47 mysqlnd_stats_values_names,
48 },
49 {
50 NULL /* plugin shutdown */
51 }
52 }
53 };
54
55
56 /* {{{ mysqlnd_library_end */
mysqlnd_library_end(void)57 PHPAPI void mysqlnd_library_end(void)
58 {
59 if (mysqlnd_library_initted == TRUE) {
60 mysqlnd_plugin_subsystem_end();
61 mysqlnd_stats_end(mysqlnd_global_stats, 1);
62 mysqlnd_global_stats = NULL;
63 mysqlnd_library_initted = FALSE;
64 mysqlnd_reverse_api_end();
65 }
66 }
67 /* }}} */
68
69
70 /* {{{ mysqlnd_library_init */
mysqlnd_library_init(void)71 PHPAPI void mysqlnd_library_init(void)
72 {
73 if (mysqlnd_library_initted == FALSE) {
74 mysqlnd_library_initted = TRUE;
75 mysqlnd_conn_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_conn));
76 mysqlnd_conn_data_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_conn_data));
77 _mysqlnd_init_ps_subsystem();
78 /* Should be calloc, as mnd_calloc will reference LOCK_access*/
79 mysqlnd_stats_init(&mysqlnd_global_stats, STAT_LAST, 1);
80 mysqlnd_plugin_subsystem_init();
81 {
82 mysqlnd_plugin_core.plugin_header.plugin_stats.values = mysqlnd_global_stats;
83 mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_plugin_core);
84 }
85 #if defined(MYSQLND_DBG_ENABLED) && MYSQLND_DBG_ENABLED == 1
86 mysqlnd_example_plugin_register();
87 #endif
88 mysqlnd_debug_trace_plugin_register();
89 mysqlnd_register_builtin_authentication_plugins();
90
91 mysqlnd_reverse_api_init();
92 }
93 }
94 /* }}} */
95
96
97 /* {{{ mysqlnd_object_factory::get_connection */
98 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,get_connection)99 MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory, const zend_bool persistent)
100 {
101 size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
102 size_t alloc_size_ret_data = sizeof(MYSQLND_CONN_DATA) + mysqlnd_plugin_count() * sizeof(void *);
103 MYSQLND * new_object;
104 MYSQLND_CONN_DATA * data;
105
106 DBG_ENTER("mysqlnd_driver::get_connection");
107 DBG_INF_FMT("persistent=%u", persistent);
108 new_object = mnd_pecalloc(1, alloc_size_ret, persistent);
109 if (!new_object) {
110 DBG_RETURN(NULL);
111 }
112 new_object->data = mnd_pecalloc(1, alloc_size_ret_data, persistent);
113 if (!new_object->data) {
114 mnd_pefree(new_object, persistent);
115 DBG_RETURN(NULL);
116 }
117 new_object->persistent = persistent;
118 new_object->m = mysqlnd_conn_get_methods();
119 data = new_object->data;
120
121 if (FAIL == mysqlnd_error_info_init(&data->error_info_impl, persistent)) {
122 new_object->m->dtor(new_object);
123 DBG_RETURN(NULL);
124 }
125 data->error_info = &data->error_info_impl;
126
127 data->options = &(data->options_impl);
128
129 mysqlnd_upsert_status_init(&data->upsert_status_impl);
130 data->upsert_status = &(data->upsert_status_impl);
131 UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(data->upsert_status);
132
133 data->persistent = persistent;
134 data->m = mysqlnd_conn_data_get_methods();
135 data->object_factory = *factory;
136
137 mysqlnd_connection_state_init(&data->state);
138
139 data->m->get_reference(data);
140
141 mysqlnd_stats_init(&data->stats, STAT_LAST, persistent);
142
143 data->protocol_frame_codec = mysqlnd_pfc_init(persistent, factory, data->stats, data->error_info);
144 data->vio = mysqlnd_vio_init(persistent, factory, data->stats, data->error_info);
145 data->payload_decoder_factory = mysqlnd_protocol_payload_decoder_factory_init(data, persistent);
146 data->command_factory = mysqlnd_command_factory_get();
147
148 if (!data->protocol_frame_codec || !data->vio || !data->payload_decoder_factory || !data->command_factory) {
149 new_object->m->dtor(new_object);
150 DBG_RETURN(NULL);
151 }
152
153 DBG_RETURN(new_object);
154 }
155 /* }}} */
156
157
158 /* {{{ mysqlnd_object_factory::clone_connection_object */
159 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,clone_connection_object)160 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object)(MYSQLND * to_be_cloned)
161 {
162 size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
163 MYSQLND * new_object;
164
165 DBG_ENTER("mysqlnd_driver::clone_connection_object");
166 DBG_INF_FMT("persistent=%u", to_be_cloned->persistent);
167 if (!to_be_cloned || !to_be_cloned->data) {
168 DBG_RETURN(NULL);
169 }
170 new_object = mnd_pecalloc(1, alloc_size_ret, to_be_cloned->persistent);
171 if (!new_object) {
172 DBG_RETURN(NULL);
173 }
174 new_object->persistent = to_be_cloned->persistent;
175 new_object->m = to_be_cloned->m;
176
177 new_object->data = to_be_cloned->data->m->get_reference(to_be_cloned->data);
178 if (!new_object->data) {
179 new_object->m->dtor(new_object);
180 new_object = NULL;
181 }
182 DBG_RETURN(new_object);
183 }
184 /* }}} */
185
186
187 /* {{{ mysqlnd_object_factory::get_prepared_statement */
188 static MYSQLND_STMT *
MYSQLND_METHOD(mysqlnd_object_factory,get_prepared_statement)189 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA * const conn, const zend_bool persistent)
190 {
191 size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
192 MYSQLND_STMT * ret = mnd_pecalloc(1, alloc_size, conn->persistent);
193 MYSQLND_STMT_DATA * stmt = NULL;
194
195 DBG_ENTER("mysqlnd_object_factory::get_prepared_statement");
196 do {
197 if (!ret) {
198 break;
199 }
200 ret->m = mysqlnd_stmt_get_methods();
201 ret->persistent = conn->persistent;
202
203 stmt = ret->data = mnd_pecalloc(1, sizeof(MYSQLND_STMT_DATA), persistent);
204 DBG_INF_FMT("stmt=%p", stmt);
205 if (!stmt) {
206 break;
207 }
208 stmt->persistent = persistent;
209
210 if (FAIL == mysqlnd_error_info_init(&stmt->error_info_impl, persistent)) {
211 break;
212 }
213 stmt->error_info = &stmt->error_info_impl;
214
215 mysqlnd_upsert_status_init(&stmt->upsert_status_impl);
216 stmt->upsert_status = &(stmt->upsert_status_impl);
217 stmt->state = MYSQLND_STMT_INITTED;
218 stmt->execute_cmd_buffer.length = 4096;
219 stmt->execute_cmd_buffer.buffer = mnd_pemalloc(stmt->execute_cmd_buffer.length, stmt->persistent);
220 if (!stmt->execute_cmd_buffer.buffer) {
221 break;
222 }
223
224 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
225
226 /*
227 Mark that we reference the connection, thus it won't be
228 be destructed till there is open statements. The last statement
229 or normal query result will close it then.
230 */
231 stmt->conn = conn->m->get_reference(conn);
232
233 DBG_RETURN(ret);
234 } while (0);
235
236 SET_OOM_ERROR(conn->error_info);
237 if (ret) {
238 ret->m->dtor(ret, TRUE);
239 ret = NULL;
240 }
241 DBG_RETURN(NULL);
242 }
243 /* }}} */
244
245
246 /* {{{ mysqlnd_object_factory::get_pfc */
247 static MYSQLND_PFC *
MYSQLND_METHOD(mysqlnd_object_factory,get_pfc)248 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc)(const zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
249 {
250 size_t pfc_alloc_size = sizeof(MYSQLND_PFC) + mysqlnd_plugin_count() * sizeof(void *);
251 size_t pfc_data_alloc_size = sizeof(MYSQLND_PFC_DATA) + mysqlnd_plugin_count() * sizeof(void *);
252 MYSQLND_PFC * pfc = mnd_pecalloc(1, pfc_alloc_size, persistent);
253 MYSQLND_PFC_DATA * pfc_data = mnd_pecalloc(1, pfc_data_alloc_size, persistent);
254
255 DBG_ENTER("mysqlnd_object_factory::get_pfc");
256 DBG_INF_FMT("persistent=%u", persistent);
257 if (pfc && pfc_data) {
258 pfc->data = pfc_data;
259 pfc->persistent = pfc->data->persistent = persistent;
260 pfc->data->m = *mysqlnd_pfc_get_methods();
261
262 if (PASS != pfc->data->m.init(pfc, stats, error_info)) {
263 pfc->data->m.dtor(pfc, stats, error_info);
264 pfc = NULL;
265 }
266 } else {
267 if (pfc_data) {
268 mnd_pefree(pfc_data, persistent);
269 pfc_data = NULL;
270 }
271 if (pfc) {
272 mnd_pefree(pfc, persistent);
273 pfc = NULL;
274 }
275 }
276 DBG_RETURN(pfc);
277 }
278 /* }}} */
279
280
281 /* {{{ mysqlnd_object_factory::get_vio */
282 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)283 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
284 {
285 size_t vio_alloc_size = sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *);
286 size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
287 MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size, persistent);
288 MYSQLND_VIO_DATA * vio_data = mnd_pecalloc(1, vio_data_alloc_size, persistent);
289
290 DBG_ENTER("mysqlnd_object_factory::get_vio");
291 DBG_INF_FMT("persistent=%u", persistent);
292 if (vio && vio_data) {
293 vio->data = vio_data;
294 vio->persistent = vio->data->persistent = persistent;
295 vio->data->m = *mysqlnd_vio_get_methods();
296
297 if (PASS != vio->data->m.init(vio, stats, error_info)) {
298 vio->data->m.dtor(vio, stats, error_info);
299 vio = NULL;
300 }
301 } else {
302 if (vio_data) {
303 mnd_pefree(vio_data, persistent);
304 vio_data = NULL;
305 }
306 if (vio) {
307 mnd_pefree(vio, persistent);
308 vio = NULL;
309 }
310 }
311 DBG_RETURN(vio);
312 }
313 /* }}} */
314
315
316 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
317 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)318 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const zend_bool persistent)
319 {
320 size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
321 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
322
323 DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
324 DBG_INF_FMT("persistent=%u", persistent);
325 if (ret) {
326 ret->persistent = persistent;
327 ret->conn = conn;
328 ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
329 }
330
331 DBG_RETURN(ret);
332 }
333 /* }}} */
334
335
336 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
337 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
338 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
339 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
340 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
341 MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
342 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
343 MYSQLND_CLASS_METHODS_END;
344
345 /*
346 * Local variables:
347 * tab-width: 4
348 * c-basic-offset: 4
349 * End:
350 * vim600: noet sw=4 ts=4 fdm=marker
351 * vim<600: noet sw=4 ts=4
352 */
353