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 }
92 /* }}} */
93
94
95 /* {{{ mysqlnd_object_factory::get_connection */
96 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,get_connection)97 MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory, const bool persistent)
98 {
99 const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
100 const size_t alloc_size_ret_data = sizeof(MYSQLND_CONN_DATA) + mysqlnd_plugin_count() * sizeof(void *);
101 MYSQLND * new_object;
102 MYSQLND_CONN_DATA * data;
103
104 DBG_ENTER("mysqlnd_driver::get_connection");
105 DBG_INF_FMT("persistent=%u", persistent);
106 new_object = mnd_pecalloc(1, alloc_size_ret, persistent);
107 if (!new_object) {
108 DBG_RETURN(NULL);
109 }
110 new_object->data = mnd_pecalloc(1, alloc_size_ret_data, persistent);
111 if (!new_object->data) {
112 mnd_pefree(new_object, persistent);
113 DBG_RETURN(NULL);
114 }
115 new_object->persistent = persistent;
116 new_object->m = mysqlnd_conn_get_methods();
117 data = new_object->data;
118
119 mysqlnd_error_info_init(&data->error_info_impl, persistent);
120 data->error_info = &data->error_info_impl;
121
122 data->options = &(data->options_impl);
123
124 mysqlnd_upsert_status_init(&data->upsert_status_impl);
125 data->upsert_status = &(data->upsert_status_impl);
126 UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(data->upsert_status);
127
128 data->persistent = persistent;
129 data->m = mysqlnd_conn_data_get_methods();
130 data->object_factory = *factory;
131
132 mysqlnd_connection_state_init(&data->state);
133
134 data->m->get_reference(data);
135
136 mysqlnd_stats_init(&data->stats, STAT_LAST, persistent);
137
138 data->protocol_frame_codec = mysqlnd_pfc_init(persistent, factory, data->stats, data->error_info);
139 data->vio = mysqlnd_vio_init(persistent, factory, data->stats, data->error_info);
140 data->payload_decoder_factory = mysqlnd_protocol_payload_decoder_factory_init(data, persistent);
141 data->command = mysqlnd_command_get_methods();
142
143 if (!data->protocol_frame_codec || !data->vio || !data->payload_decoder_factory || !data->command) {
144 new_object->m->dtor(new_object);
145 DBG_RETURN(NULL);
146 }
147
148 DBG_RETURN(new_object);
149 }
150 /* }}} */
151
152
153 /* {{{ mysqlnd_object_factory::clone_connection_object */
154 static MYSQLND *
MYSQLND_METHOD(mysqlnd_object_factory,clone_connection_object)155 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object)(MYSQLND * to_be_cloned)
156 {
157 const size_t alloc_size_ret = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
158 MYSQLND * new_object;
159
160 DBG_ENTER("mysqlnd_driver::clone_connection_object");
161 DBG_INF_FMT("persistent=%u", to_be_cloned->persistent);
162 if (!to_be_cloned || !to_be_cloned->data) {
163 DBG_RETURN(NULL);
164 }
165 new_object = mnd_pecalloc(1, alloc_size_ret, to_be_cloned->persistent);
166 if (!new_object) {
167 DBG_RETURN(NULL);
168 }
169 new_object->persistent = to_be_cloned->persistent;
170 new_object->m = to_be_cloned->m;
171
172 new_object->data = to_be_cloned->data->m->get_reference(to_be_cloned->data);
173 if (!new_object->data) {
174 new_object->m->dtor(new_object);
175 new_object = NULL;
176 }
177 DBG_RETURN(new_object);
178 }
179 /* }}} */
180
181
182 /* {{{ mysqlnd_object_factory::get_prepared_statement */
183 static MYSQLND_STMT *
MYSQLND_METHOD(mysqlnd_object_factory,get_prepared_statement)184 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA * const conn)
185 {
186 const size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
187 MYSQLND_STMT * ret = mnd_ecalloc(1, alloc_size);
188 MYSQLND_STMT_DATA * stmt = NULL;
189
190 DBG_ENTER("mysqlnd_object_factory::get_prepared_statement");
191 ret->m = mysqlnd_stmt_get_methods();
192
193 stmt = ret->data = mnd_ecalloc(1, sizeof(MYSQLND_STMT_DATA));
194 DBG_INF_FMT("stmt=%p", stmt);
195
196 mysqlnd_error_info_init(&stmt->error_info_impl, 0);
197 stmt->error_info = &stmt->error_info_impl;
198
199 mysqlnd_upsert_status_init(&stmt->upsert_status_impl);
200 stmt->upsert_status = &(stmt->upsert_status_impl);
201 stmt->state = MYSQLND_STMT_INITTED;
202 stmt->execute_cmd_buffer.length = 4096;
203 stmt->execute_cmd_buffer.buffer = mnd_emalloc(stmt->execute_cmd_buffer.length);
204 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
205
206 /*
207 Mark that we reference the connection, thus it won't be
208 be destructed till there is open statements. The last statement
209 or normal query result will close it then.
210 */
211 stmt->conn = conn->m->get_reference(conn);
212
213 DBG_RETURN(ret);
214 }
215 /* }}} */
216
217
218 /* {{{ mysqlnd_object_factory::get_pfc */
219 static MYSQLND_PFC *
MYSQLND_METHOD(mysqlnd_object_factory,get_pfc)220 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
221 {
222 const size_t pfc_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_PFC) + mysqlnd_plugin_count() * sizeof(void *));
223 const size_t pfc_data_alloc_size = sizeof(MYSQLND_PFC_DATA) + mysqlnd_plugin_count() * sizeof(void *);
224 MYSQLND_PFC * pfc = mnd_pecalloc(1, pfc_alloc_size + pfc_data_alloc_size, persistent);
225
226 DBG_ENTER("mysqlnd_object_factory::get_pfc");
227 DBG_INF_FMT("persistent=%u", persistent);
228 if (pfc) {
229 pfc->data = (MYSQLND_PFC_DATA*)((char*)pfc + pfc_alloc_size);
230 pfc->persistent = pfc->data->persistent = persistent;
231 pfc->data->m = *mysqlnd_pfc_get_methods();
232
233 if (PASS != pfc->data->m.init(pfc, stats, error_info)) {
234 pfc->data->m.dtor(pfc, stats, error_info);
235 pfc = NULL;
236 }
237 }
238 DBG_RETURN(pfc);
239 }
240 /* }}} */
241
242
243 /* {{{ mysqlnd_object_factory::get_vio */
244 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)245 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
246 {
247 const size_t vio_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *));
248 const size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
249 MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size + vio_data_alloc_size, persistent);
250
251 DBG_ENTER("mysqlnd_object_factory::get_vio");
252 DBG_INF_FMT("persistent=%u", persistent);
253 if (vio) {
254 vio->data = (MYSQLND_VIO_DATA*)((char*)vio + vio_alloc_size);
255 vio->persistent = vio->data->persistent = persistent;
256 vio->data->m = *mysqlnd_vio_get_methods();
257
258 if (PASS != vio->data->m.init(vio, stats, error_info)) {
259 vio->data->m.dtor(vio, stats, error_info);
260 vio = NULL;
261 }
262 }
263 DBG_RETURN(vio);
264 }
265 /* }}} */
266
267
268 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
269 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)270 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const bool persistent)
271 {
272 const size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
273 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
274
275 DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
276 DBG_INF_FMT("persistent=%u", persistent);
277 if (ret) {
278 ret->persistent = persistent;
279 ret->conn = conn;
280 ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
281 }
282
283 DBG_RETURN(ret);
284 }
285 /* }}} */
286
287
288 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
289 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
290 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
291 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
292 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
293 MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
294 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
295 MYSQLND_CLASS_METHODS_END;
296