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