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