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 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
210
211 /*
212 Mark that we reference the connection, thus it won't be
213 be destructed till there is open statements. The last statement
214 or normal query result will close it then.
215 */
216 stmt->conn = conn->m->get_reference(conn);
217
218 DBG_RETURN(ret);
219 }
220 /* }}} */
221
222
223 /* {{{ mysqlnd_object_factory::get_pfc */
224 static MYSQLND_PFC *
MYSQLND_METHOD(mysqlnd_object_factory,get_pfc)225 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
226 {
227 const size_t pfc_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_PFC) + mysqlnd_plugin_count() * sizeof(void *));
228 const size_t pfc_data_alloc_size = sizeof(MYSQLND_PFC_DATA) + mysqlnd_plugin_count() * sizeof(void *);
229 MYSQLND_PFC * pfc = mnd_pecalloc(1, pfc_alloc_size + pfc_data_alloc_size, persistent);
230
231 DBG_ENTER("mysqlnd_object_factory::get_pfc");
232 DBG_INF_FMT("persistent=%u", persistent);
233 if (pfc) {
234 pfc->data = (MYSQLND_PFC_DATA*)((char*)pfc + pfc_alloc_size);
235 pfc->persistent = pfc->data->persistent = persistent;
236 pfc->data->m = *mysqlnd_pfc_get_methods();
237
238 pfc->data->m.init(pfc, stats, error_info);
239 }
240 DBG_RETURN(pfc);
241 }
242 /* }}} */
243
244
245 /* {{{ mysqlnd_object_factory::get_vio */
246 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)247 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
248 {
249 const size_t vio_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *));
250 const size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
251 MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size + vio_data_alloc_size, persistent);
252
253 DBG_ENTER("mysqlnd_object_factory::get_vio");
254 DBG_INF_FMT("persistent=%u", persistent);
255 if (vio) {
256 vio->data = (MYSQLND_VIO_DATA*)((char*)vio + vio_alloc_size);
257 vio->persistent = vio->data->persistent = persistent;
258 vio->data->m = *mysqlnd_vio_get_methods();
259
260 vio->data->m.init(vio, stats, error_info);
261 }
262 DBG_RETURN(vio);
263 }
264 /* }}} */
265
266
267 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
268 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)269 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const bool persistent)
270 {
271 const size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
272 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
273
274 DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
275 DBG_INF_FMT("persistent=%u", persistent);
276 if (ret) {
277 ret->persistent = persistent;
278 ret->conn = conn;
279 ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
280 }
281
282 DBG_RETURN(ret);
283 }
284 /* }}} */
285
286
287 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
288 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
289 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
290 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
291 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
292 MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
293 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
294 MYSQLND_CLASS_METHODS_END;
295