1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
102 const 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 = mysqlnd_command_get_methods();
147
148 if (!data->protocol_frame_codec || !data->vio || !data->payload_decoder_factory || !data->command) {
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 const 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)
190 {
191 const size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
192 MYSQLND_STMT * ret = mnd_ecalloc(1, alloc_size);
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
202 stmt = ret->data = mnd_ecalloc(1, sizeof(MYSQLND_STMT_DATA));
203 DBG_INF_FMT("stmt=%p", stmt);
204 if (!stmt) {
205 break;
206 }
207
208 if (FAIL == mysqlnd_error_info_init(&stmt->error_info_impl, 0)) {
209 break;
210 }
211 stmt->error_info = &stmt->error_info_impl;
212
213 mysqlnd_upsert_status_init(&stmt->upsert_status_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_emalloc(stmt->execute_cmd_buffer.length);
218 if (!stmt->execute_cmd_buffer.buffer) {
219 break;
220 }
221
222 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
223
224 /*
225 Mark that we reference the connection, thus it won't be
226 be destructed till there is open statements. The last statement
227 or normal query result will close it then.
228 */
229 stmt->conn = conn->m->get_reference(conn);
230
231 DBG_RETURN(ret);
232 } while (0);
233
234 SET_OOM_ERROR(conn->error_info);
235 if (ret) {
236 ret->m->dtor(ret, TRUE);
237 ret = NULL;
238 }
239 DBG_RETURN(NULL);
240 }
241 /* }}} */
242
243
244 /* {{{ mysqlnd_object_factory::get_pfc */
245 static MYSQLND_PFC *
MYSQLND_METHOD(mysqlnd_object_factory,get_pfc)246 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc)(const zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
247 {
248 const size_t pfc_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_PFC) + mysqlnd_plugin_count() * sizeof(void *));
249 const size_t pfc_data_alloc_size = sizeof(MYSQLND_PFC_DATA) + mysqlnd_plugin_count() * sizeof(void *);
250 MYSQLND_PFC * pfc = mnd_pecalloc(1, pfc_alloc_size + pfc_data_alloc_size, persistent);
251
252 DBG_ENTER("mysqlnd_object_factory::get_pfc");
253 DBG_INF_FMT("persistent=%u", persistent);
254 if (pfc) {
255 pfc->data = (MYSQLND_PFC_DATA*)((char*)pfc + pfc_alloc_size);
256 pfc->persistent = pfc->data->persistent = persistent;
257 pfc->data->m = *mysqlnd_pfc_get_methods();
258
259 if (PASS != pfc->data->m.init(pfc, stats, error_info)) {
260 pfc->data->m.dtor(pfc, stats, error_info);
261 pfc = NULL;
262 }
263 }
264 DBG_RETURN(pfc);
265 }
266 /* }}} */
267
268
269 /* {{{ mysqlnd_object_factory::get_vio */
270 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)271 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
272 {
273 const size_t vio_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *));
274 const size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
275 MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size + vio_data_alloc_size, persistent);
276
277 DBG_ENTER("mysqlnd_object_factory::get_vio");
278 DBG_INF_FMT("persistent=%u", persistent);
279 if (vio) {
280 vio->data = (MYSQLND_VIO_DATA*)((char*)vio + vio_alloc_size);
281 vio->persistent = vio->data->persistent = persistent;
282 vio->data->m = *mysqlnd_vio_get_methods();
283
284 if (PASS != vio->data->m.init(vio, stats, error_info)) {
285 vio->data->m.dtor(vio, stats, error_info);
286 vio = NULL;
287 }
288 }
289 DBG_RETURN(vio);
290 }
291 /* }}} */
292
293
294 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
295 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)296 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const zend_bool persistent)
297 {
298 const size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
299 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
300
301 DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
302 DBG_INF_FMT("persistent=%u", persistent);
303 if (ret) {
304 ret->persistent = persistent;
305 ret->conn = conn;
306 ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
307 }
308
309 DBG_RETURN(ret);
310 }
311 /* }}} */
312
313
314 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
315 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
316 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
317 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
318 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
319 MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
320 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
321 MYSQLND_CLASS_METHODS_END;
322