1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Andrey Hristov <andrey@php.net> |
14 | Ulf Wendel <uw@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #include "php.h"
19 #include "mysqlnd.h"
20 #include "mysqlnd_vio.h"
21 #include "mysqlnd_protocol_frame_codec.h"
22 #include "mysqlnd_wireprotocol.h"
23 #include "mysqlnd_connection.h"
24 #include "mysqlnd_ps.h"
25 #include "mysqlnd_plugin.h"
26 #include "mysqlnd_priv.h"
27 #include "mysqlnd_statistics.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 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 /* {{{ mysqlnd_object_factory::get_connection */
96 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,get_connection)97 MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory, const zend_bool persistent)
98 {
99 const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
100 const size_t alloc_size_ret_data = sizeof(MYSQLND_CONN_DATA) + mysqlnd_plugin_count() * sizeof(void *);
101 MYSQLND * new_object;
102 MYSQLND_CONN_DATA * data;
103
104 DBG_ENTER("mysqlnd_driver::get_connection");
105 DBG_INF_FMT("persistent=%u", persistent);
106 new_object = mnd_pecalloc(1, alloc_size_ret, persistent);
107 if (!new_object) {
108 DBG_RETURN(NULL);
109 }
110 new_object->data = mnd_pecalloc(1, alloc_size_ret_data, persistent);
111 if (!new_object->data) {
112 mnd_pefree(new_object, persistent);
113 DBG_RETURN(NULL);
114 }
115 new_object->persistent = persistent;
116 new_object->m = mysqlnd_conn_get_methods();
117 data = new_object->data;
118
119 if (FAIL == mysqlnd_error_info_init(&data->error_info_impl, persistent)) {
120 new_object->m->dtor(new_object);
121 DBG_RETURN(NULL);
122 }
123 data->error_info = &data->error_info_impl;
124
125 data->options = &(data->options_impl);
126
127 mysqlnd_upsert_status_init(&data->upsert_status_impl);
128 data->upsert_status = &(data->upsert_status_impl);
129 UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(data->upsert_status);
130
131 data->persistent = persistent;
132 data->m = mysqlnd_conn_data_get_methods();
133 data->object_factory = *factory;
134
135 mysqlnd_connection_state_init(&data->state);
136
137 data->m->get_reference(data);
138
139 mysqlnd_stats_init(&data->stats, STAT_LAST, persistent);
140
141 data->protocol_frame_codec = mysqlnd_pfc_init(persistent, factory, data->stats, data->error_info);
142 data->vio = mysqlnd_vio_init(persistent, factory, data->stats, data->error_info);
143 data->payload_decoder_factory = mysqlnd_protocol_payload_decoder_factory_init(data, persistent);
144 data->command = mysqlnd_command_get_methods();
145
146 if (!data->protocol_frame_codec || !data->vio || !data->payload_decoder_factory || !data->command) {
147 new_object->m->dtor(new_object);
148 DBG_RETURN(NULL);
149 }
150
151 DBG_RETURN(new_object);
152 }
153 /* }}} */
154
155
156 /* {{{ mysqlnd_object_factory::clone_connection_object */
157 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,clone_connection_object)158 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object)(MYSQLND * to_be_cloned)
159 {
160 const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
161 MYSQLND * new_object;
162
163 DBG_ENTER("mysqlnd_driver::clone_connection_object");
164 DBG_INF_FMT("persistent=%u", to_be_cloned->persistent);
165 if (!to_be_cloned || !to_be_cloned->data) {
166 DBG_RETURN(NULL);
167 }
168 new_object = mnd_pecalloc(1, alloc_size_ret, to_be_cloned->persistent);
169 if (!new_object) {
170 DBG_RETURN(NULL);
171 }
172 new_object->persistent = to_be_cloned->persistent;
173 new_object->m = to_be_cloned->m;
174
175 new_object->data = to_be_cloned->data->m->get_reference(to_be_cloned->data);
176 if (!new_object->data) {
177 new_object->m->dtor(new_object);
178 new_object = NULL;
179 }
180 DBG_RETURN(new_object);
181 }
182 /* }}} */
183
184
185 /* {{{ mysqlnd_object_factory::get_prepared_statement */
186 static MYSQLND_STMT *
MYSQLND_METHOD(mysqlnd_object_factory,get_prepared_statement)187 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA * const conn)
188 {
189 const size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
190 MYSQLND_STMT * ret = mnd_ecalloc(1, alloc_size);
191 MYSQLND_STMT_DATA * stmt = NULL;
192
193 DBG_ENTER("mysqlnd_object_factory::get_prepared_statement");
194 do {
195 if (!ret) {
196 break;
197 }
198 ret->m = mysqlnd_stmt_get_methods();
199
200 stmt = ret->data = mnd_ecalloc(1, sizeof(MYSQLND_STMT_DATA));
201 DBG_INF_FMT("stmt=%p", stmt);
202 if (!stmt) {
203 break;
204 }
205
206 if (FAIL == mysqlnd_error_info_init(&stmt->error_info_impl, 0)) {
207 break;
208 }
209 stmt->error_info = &stmt->error_info_impl;
210
211 mysqlnd_upsert_status_init(&stmt->upsert_status_impl);
212 stmt->upsert_status = &(stmt->upsert_status_impl);
213 stmt->state = MYSQLND_STMT_INITTED;
214 stmt->execute_cmd_buffer.length = 4096;
215 stmt->execute_cmd_buffer.buffer = mnd_emalloc(stmt->execute_cmd_buffer.length);
216 if (!stmt->execute_cmd_buffer.buffer) {
217 break;
218 }
219
220 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
221
222 /*
223 Mark that we reference the connection, thus it won't be
224 be destructed till there is open statements. The last statement
225 or normal query result will close it then.
226 */
227 stmt->conn = conn->m->get_reference(conn);
228
229 DBG_RETURN(ret);
230 } while (0);
231
232 SET_OOM_ERROR(conn->error_info);
233 if (ret) {
234 ret->m->dtor(ret, TRUE);
235 ret = NULL;
236 }
237 DBG_RETURN(NULL);
238 }
239 /* }}} */
240
241
242 /* {{{ mysqlnd_object_factory::get_pfc */
243 static MYSQLND_PFC *
MYSQLND_METHOD(mysqlnd_object_factory,get_pfc)244 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc)(const zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
245 {
246 const size_t pfc_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_PFC) + mysqlnd_plugin_count() * sizeof(void *));
247 const size_t pfc_data_alloc_size = sizeof(MYSQLND_PFC_DATA) + mysqlnd_plugin_count() * sizeof(void *);
248 MYSQLND_PFC * pfc = mnd_pecalloc(1, pfc_alloc_size + pfc_data_alloc_size, persistent);
249
250 DBG_ENTER("mysqlnd_object_factory::get_pfc");
251 DBG_INF_FMT("persistent=%u", persistent);
252 if (pfc) {
253 pfc->data = (MYSQLND_PFC_DATA*)((char*)pfc + pfc_alloc_size);
254 pfc->persistent = pfc->data->persistent = persistent;
255 pfc->data->m = *mysqlnd_pfc_get_methods();
256
257 if (PASS != pfc->data->m.init(pfc, stats, error_info)) {
258 pfc->data->m.dtor(pfc, stats, error_info);
259 pfc = NULL;
260 }
261 }
262 DBG_RETURN(pfc);
263 }
264 /* }}} */
265
266
267 /* {{{ mysqlnd_object_factory::get_vio */
268 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)269 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
270 {
271 const size_t vio_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *));
272 const size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
273 MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size + vio_data_alloc_size, persistent);
274
275 DBG_ENTER("mysqlnd_object_factory::get_vio");
276 DBG_INF_FMT("persistent=%u", persistent);
277 if (vio) {
278 vio->data = (MYSQLND_VIO_DATA*)((char*)vio + vio_alloc_size);
279 vio->persistent = vio->data->persistent = persistent;
280 vio->data->m = *mysqlnd_vio_get_methods();
281
282 if (PASS != vio->data->m.init(vio, stats, error_info)) {
283 vio->data->m.dtor(vio, stats, error_info);
284 vio = NULL;
285 }
286 }
287 DBG_RETURN(vio);
288 }
289 /* }}} */
290
291
292 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
293 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)294 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const zend_bool persistent)
295 {
296 const size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
297 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
298
299 DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
300 DBG_INF_FMT("persistent=%u", persistent);
301 if (ret) {
302 ret->persistent = persistent;
303 ret->conn = conn;
304 ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
305 }
306
307 DBG_RETURN(ret);
308 }
309 /* }}} */
310
311
312 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
313 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
314 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
315 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
316 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
317 MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
318 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
319 MYSQLND_CLASS_METHODS_END;
320