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