xref: /php-src/ext/mysqlnd/mysqlnd_driver.c (revision c316382a)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Authors: Andrey Hristov <andrey@php.net>                             |
14   |          Ulf Wendel <uw@php.net>                                     |
15   +----------------------------------------------------------------------+
16 */
17 
18 #include "php.h"
19 #include "mysqlnd.h"
20 #include "mysqlnd_vio.h"
21 #include "mysqlnd_protocol_frame_codec.h"
22 #include "mysqlnd_wireprotocol.h"
23 #include "mysqlnd_connection.h"
24 #include "mysqlnd_ps.h"
25 #include "mysqlnd_plugin.h"
26 #include "mysqlnd_priv.h"
27 #include "mysqlnd_statistics.h"
28 #include "mysqlnd_debug.h"
29 #include "mysqlnd_reverse_api.h"
30 #include "mysqlnd_ext_plugin.h"
31 
32 static 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 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 #if MYSQLND_CHARSETS_SANITY_CHECK == 1
92 		void mysqlnd_charsets_sanity_check(void);
93 		mysqlnd_charsets_sanity_check();
94 #endif
95 	}
96 }
97 /* }}} */
98 
99 
100 /* {{{ mysqlnd_object_factory::get_connection */
101 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,get_connection)102 MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory, const bool persistent)
103 {
104 	const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
105 	const size_t alloc_size_ret_data = sizeof(MYSQLND_CONN_DATA) + mysqlnd_plugin_count() * sizeof(void *);
106 	MYSQLND * new_object;
107 	MYSQLND_CONN_DATA * data;
108 
109 	DBG_ENTER("mysqlnd_driver::get_connection");
110 	DBG_INF_FMT("persistent=%u", persistent);
111 	new_object = mnd_pecalloc(1, alloc_size_ret, persistent);
112 	if (!new_object) {
113 		DBG_RETURN(NULL);
114 	}
115 	new_object->data = mnd_pecalloc(1, alloc_size_ret_data, persistent);
116 	if (!new_object->data) {
117 		mnd_pefree(new_object, persistent);
118 		DBG_RETURN(NULL);
119 	}
120 	new_object->persistent = persistent;
121 	new_object->m = mysqlnd_conn_get_methods();
122 	data = new_object->data;
123 
124 	mysqlnd_error_info_init(&data->error_info_impl, persistent);
125 	data->error_info = &data->error_info_impl;
126 
127 	data->options = &(data->options_impl);
128 
129 	mysqlnd_upsert_status_init(&data->upsert_status_impl);
130 	data->upsert_status = &(data->upsert_status_impl);
131 	UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(data->upsert_status);
132 
133 	data->persistent = persistent;
134 	data->m = mysqlnd_conn_data_get_methods();
135 	data->object_factory = *factory;
136 
137 	mysqlnd_connection_state_init(&data->state);
138 
139 	data->m->get_reference(data);
140 
141 	mysqlnd_stats_init(&data->stats, STAT_LAST, persistent);
142 
143 	data->protocol_frame_codec = mysqlnd_pfc_init(persistent, factory, data->stats, data->error_info);
144 	data->vio = mysqlnd_vio_init(persistent, factory, data->stats, data->error_info);
145 	data->payload_decoder_factory = mysqlnd_protocol_payload_decoder_factory_init(data, persistent);
146 	data->command = mysqlnd_command_get_methods();
147 
148 	if (!data->protocol_frame_codec || !data->vio || !data->payload_decoder_factory || !data->command) {
149 		new_object->m->dtor(new_object);
150 		DBG_RETURN(NULL);
151 	}
152 
153 	DBG_RETURN(new_object);
154 }
155 /* }}} */
156 
157 
158 /* {{{ mysqlnd_object_factory::clone_connection_object */
159 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,clone_connection_object)160 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object)(MYSQLND * to_be_cloned)
161 {
162 	const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
163 	MYSQLND * new_object;
164 
165 	DBG_ENTER("mysqlnd_driver::clone_connection_object");
166 	DBG_INF_FMT("persistent=%u", to_be_cloned->persistent);
167 	if (!to_be_cloned || !to_be_cloned->data) {
168 		DBG_RETURN(NULL);
169 	}
170 	new_object = mnd_pecalloc(1, alloc_size_ret, to_be_cloned->persistent);
171 	if (!new_object) {
172 		DBG_RETURN(NULL);
173 	}
174 	new_object->persistent = to_be_cloned->persistent;
175 	new_object->m = to_be_cloned->m;
176 
177 	new_object->data = to_be_cloned->data->m->get_reference(to_be_cloned->data);
178 	if (!new_object->data) {
179 		new_object->m->dtor(new_object);
180 		new_object = NULL;
181 	}
182 	DBG_RETURN(new_object);
183 }
184 /* }}} */
185 
186 
187 /* {{{ mysqlnd_object_factory::get_prepared_statement */
188 static MYSQLND_STMT *
MYSQLND_METHOD(mysqlnd_object_factory,get_prepared_statement)189 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA * const conn)
190 {
191 	const size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
192 	MYSQLND_STMT * ret = mnd_ecalloc(1, alloc_size);
193 	MYSQLND_STMT_DATA * stmt = NULL;
194 
195 	DBG_ENTER("mysqlnd_object_factory::get_prepared_statement");
196 	ret->m = mysqlnd_stmt_get_methods();
197 
198 	stmt = ret->data = mnd_ecalloc(1, sizeof(MYSQLND_STMT_DATA));
199 	DBG_INF_FMT("stmt=%p", stmt);
200 
201 	mysqlnd_error_info_init(&stmt->error_info_impl, 0);
202 	stmt->error_info = &stmt->error_info_impl;
203 
204 	mysqlnd_upsert_status_init(&stmt->upsert_status_impl);
205 	stmt->upsert_status = &(stmt->upsert_status_impl);
206 	stmt->state = MYSQLND_STMT_INITTED;
207 	stmt->execute_cmd_buffer.length = MYSQLND_NET_CMD_BUFFER_MIN_SIZE;
208 	stmt->execute_cmd_buffer.buffer = mnd_emalloc(stmt->execute_cmd_buffer.length);
209 
210 	/*
211 	  Mark that we reference the connection, thus it won't be
212 	  be destructed till there is open statements. The last statement
213 	  or normal query result will close it then.
214 	*/
215 	stmt->conn = conn->m->get_reference(conn);
216 
217 	DBG_RETURN(ret);
218 }
219 /* }}} */
220 
221 
222 /* {{{ mysqlnd_object_factory::get_pfc */
223 static MYSQLND_PFC *
MYSQLND_METHOD(mysqlnd_object_factory,get_pfc)224 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
225 {
226 	const size_t pfc_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_PFC) + mysqlnd_plugin_count() * sizeof(void *));
227 	const size_t pfc_data_alloc_size = sizeof(MYSQLND_PFC_DATA) + mysqlnd_plugin_count() * sizeof(void *);
228 	MYSQLND_PFC * pfc = mnd_pecalloc(1, pfc_alloc_size + pfc_data_alloc_size, persistent);
229 
230 	DBG_ENTER("mysqlnd_object_factory::get_pfc");
231 	DBG_INF_FMT("persistent=%u", persistent);
232 	if (pfc) {
233 		pfc->data = (MYSQLND_PFC_DATA*)((char*)pfc + pfc_alloc_size);
234 		pfc->persistent = pfc->data->persistent = persistent;
235 		pfc->data->m = *mysqlnd_pfc_get_methods();
236 
237 		pfc->data->m.init(pfc, stats, error_info);
238 	}
239 	DBG_RETURN(pfc);
240 }
241 /* }}} */
242 
243 
244 /* {{{ mysqlnd_object_factory::get_vio */
245 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)246 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
247 {
248 	const size_t vio_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *));
249 	const size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
250 	MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size + vio_data_alloc_size, persistent);
251 
252 	DBG_ENTER("mysqlnd_object_factory::get_vio");
253 	DBG_INF_FMT("persistent=%u", persistent);
254 	if (vio) {
255 		vio->data = (MYSQLND_VIO_DATA*)((char*)vio + vio_alloc_size);
256 		vio->persistent = vio->data->persistent = persistent;
257 		vio->data->m = *mysqlnd_vio_get_methods();
258 
259 		vio->data->m.init(vio, stats, error_info);
260 	}
261 	DBG_RETURN(vio);
262 }
263 /* }}} */
264 
265 
266 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
267 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)268 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const bool persistent)
269 {
270 	const size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
271 	MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
272 
273 	DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
274 	DBG_INF_FMT("persistent=%u", persistent);
275 	if (ret) {
276 		ret->persistent = persistent;
277 		ret->conn = conn;
278 		ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
279 	}
280 
281 	DBG_RETURN(ret);
282 }
283 /* }}} */
284 
285 
286 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
287 	MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
288 	MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
289 	MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
290 	MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
291 	MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
292 	MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
293 MYSQLND_CLASS_METHODS_END;
294