xref: /PHP-5.6/ext/mysqlnd/mysqlnd_driver.c (revision 49493a2d)
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