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 pfc->data->m.init(pfc, stats, error_info);
234 }
235 DBG_RETURN(pfc);
236 }
237 /* }}} */
238
239
240 /* {{{ mysqlnd_object_factory::get_vio */
241 static MYSQLND_VIO *
MYSQLND_METHOD(mysqlnd_object_factory,get_vio)242 MYSQLND_METHOD(mysqlnd_object_factory, get_vio)(const bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
243 {
244 const size_t vio_alloc_size = ZEND_MM_ALIGNED_SIZE(sizeof(MYSQLND_VIO) + mysqlnd_plugin_count() * sizeof(void *));
245 const size_t vio_data_alloc_size = sizeof(MYSQLND_VIO_DATA) + mysqlnd_plugin_count() * sizeof(void *);
246 MYSQLND_VIO * vio = mnd_pecalloc(1, vio_alloc_size + vio_data_alloc_size, persistent);
247
248 DBG_ENTER("mysqlnd_object_factory::get_vio");
249 DBG_INF_FMT("persistent=%u", persistent);
250 if (vio) {
251 vio->data = (MYSQLND_VIO_DATA*)((char*)vio + vio_alloc_size);
252 vio->persistent = vio->data->persistent = persistent;
253 vio->data->m = *mysqlnd_vio_get_methods();
254
255 vio->data->m.init(vio, stats, error_info);
256 }
257 DBG_RETURN(vio);
258 }
259 /* }}} */
260
261
262 /* {{{ mysqlnd_object_factory::get_protocol_payload_decoder_factory */
263 static MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
MYSQLND_METHOD(mysqlnd_object_factory,get_protocol_payload_decoder_factory)264 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)(MYSQLND_CONN_DATA * conn, const bool persistent)
265 {
266 const size_t alloc_size = sizeof(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY) + mysqlnd_plugin_count() * sizeof(void *);
267 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *ret = mnd_pecalloc(1, alloc_size, persistent);
268
269 DBG_ENTER("mysqlnd_object_factory::get_protocol_payload_decoder_factory");
270 DBG_INF_FMT("persistent=%u", persistent);
271 if (ret) {
272 ret->persistent = persistent;
273 ret->conn = conn;
274 ret->m = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_protocol_payload_decoder_factory);
275 }
276
277 DBG_RETURN(ret);
278 }
279 /* }}} */
280
281
282 PHPAPI MYSQLND_CLASS_METHODS_START(mysqlnd_object_factory)
283 MYSQLND_METHOD(mysqlnd_object_factory, get_connection),
284 MYSQLND_METHOD(mysqlnd_object_factory, clone_connection_object),
285 MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement),
286 MYSQLND_METHOD(mysqlnd_object_factory, get_pfc),
287 MYSQLND_METHOD(mysqlnd_object_factory, get_vio),
288 MYSQLND_METHOD(mysqlnd_object_factory, get_protocol_payload_decoder_factory)
289 MYSQLND_CLASS_METHODS_END;
290