xref: /PHP-5.4/ext/mysqlnd/mysqlnd_driver.c (revision c0d060f5)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2006-2014 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 		mysqlnd_example_plugin_register(TSRMLS_C);
85 		mysqlnd_debug_trace_plugin_register(TSRMLS_C);
86 		mysqlnd_register_builtin_authentication_plugins(TSRMLS_C);
87 
88 		mysqlnd_reverse_api_init(TSRMLS_C);
89 	}
90 }
91 /* }}} */
92 
93 
94 /* {{{ mysqlnd_error_list_pdtor */
95 static void
mysqlnd_error_list_pdtor(void * pDest)96 mysqlnd_error_list_pdtor(void * pDest)
97 {
98 	MYSQLND_ERROR_LIST_ELEMENT * element = (MYSQLND_ERROR_LIST_ELEMENT *) pDest;
99 #ifdef ZTS
100 	TSRMLS_FETCH();
101 #endif
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 TSRMLS_DC)
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 TSRMLS_CC);
143 
144 	if (PASS != data->m->init(data TSRMLS_CC)) {
145 		new_object->m->dtor(new_object TSRMLS_CC);
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 TSRMLS_CC);
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 TSRMLS_DC)
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 TSRMLS_CC);
182 	if (!new_object->data) {
183 		new_object->m->dtor(new_object TSRMLS_CC);
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 TSRMLS_DC)
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 TSRMLS_CC);
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 TSRMLS_CC);
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 TSRMLS_DC)
252 {
253 	size_t alloc_size = sizeof(MYSQLND_NET) + mysqlnd_plugin_count() * sizeof(void *);
254 	MYSQLND_NET * net = mnd_pecalloc(1, alloc_size, persistent);
255 
256 	DBG_ENTER("mysqlnd_object_factory::get_io_channel");
257 	DBG_INF_FMT("persistent=%u", persistent);
258 	if (net) {
259 		net->persistent = persistent;
260 		net->m = *mysqlnd_net_get_methods();
261 
262 		if (PASS != net->m.init(net, stats, error_info TSRMLS_CC)) {
263 			net->m.dtor(net, stats, error_info TSRMLS_CC);
264 			net = NULL;
265 		}
266 	}
267 	DBG_RETURN(net);
268 }
269 /* }}} */
270 
271 
272 /* {{{ mysqlnd_object_factory::get_protocol_decoder */
273 PHPAPI MYSQLND_PROTOCOL *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_decoder)274 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_decoder)(zend_bool persistent TSRMLS_DC)
275 {
276 	size_t alloc_size = sizeof(MYSQLND_PROTOCOL) + mysqlnd_plugin_count() * sizeof(void *);
277 	MYSQLND_PROTOCOL *ret = mnd_pecalloc(1, alloc_size, persistent);
278 
279 	DBG_ENTER("mysqlnd_object_factory::get_protocol_decoder");
280 	DBG_INF_FMT("persistent=%u", persistent);
281 	if (ret) {
282 		ret->persistent = persistent;
283 		ret->m = mysqlnd_mysqlnd_protocol_methods;
284 	}
285 
286 	DBG_RETURN(ret);
287 }
288 /* }}} */
289 
290 
291 MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
292 	MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
293 	MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
294 	MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
295 	MYSQLND_METHOD(mysqlnd_object_factory, get_io_channel),
296 	MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_decoder)
297 MYSQLND_CLASS_METHODS_END;
298 
299 /*
300  * Local variables:
301  * tab-width: 4
302  * c-basic-offset: 4
303  * End:
304  * vim600: noet sw=4 ts=4 fdm=marker
305  * vim<600: noet sw=4 ts=4
306  */
307