xref: /PHP-7.0/ext/mysqlnd/mysqlnd_driver.c (revision 478f119a)
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