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 | http://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 | Author: Georg Richter <georg@php.net> |
14 | Andrey Hristov <andrey@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <signal.h>
23
24 #include "php.h"
25 #include "php_ini.h"
26 #include "ext/standard/info.h"
27 #include "php_mysqli_structs.h"
28 #include "mysqli_priv.h"
29
30 #define CHECK_STATUS(value, quiet) \
31 if (!obj->ptr || ((MYSQLI_RESOURCE *)obj->ptr)->status < value ) { \
32 if (!quiet) { \
33 zend_throw_error(NULL, "Property access is not allowed yet"); \
34 } \
35 return FAILURE; \
36 } \
37
38 #define MYSQLI_GET_MYSQL(statusval) \
39 MYSQL *p; \
40 if (!obj->ptr || !(MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr) { \
41 if (!quiet) { \
42 zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(obj->zo.ce->name)); \
43 } \
44 return FAILURE; \
45 } else { \
46 CHECK_STATUS(statusval, quiet);\
47 p = (MYSQL *)((MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr)->mysql;\
48 }
49
50 #define MYSQLI_GET_RESULT(statusval) \
51 MYSQL_RES *p; \
52 if (!obj->ptr) { \
53 if (!quiet) { \
54 zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(obj->zo.ce->name)); \
55 } \
56 return FAILURE; \
57 } else { \
58 CHECK_STATUS(statusval, quiet);\
59 p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr; \
60 }
61
62 #define MYSQLI_GET_STMT(statusval) \
63 MYSQL_STMT *p; \
64 if (!obj->ptr) { \
65 if (!quiet) { \
66 zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(obj->zo.ce->name)); \
67 } \
68 return FAILURE; \
69 } else { \
70 CHECK_STATUS(statusval, quiet); \
71 p = (MYSQL_STMT *)((MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr)->stmt; \
72 }
73
74 #define MYSQLI_MAP_PROPERTY_FUNC_LONG( __func, __int_func, __get_type, __ret_type, __ret_type_sprint_mod)\
75 static int __func(mysqli_object *obj, zval *retval, zend_bool quiet) \
76 {\
77 __ret_type l;\
78 __get_type;\
79 if (!p) {\
80 ZVAL_NULL(retval);\
81 } else {\
82 l = (__ret_type)__int_func(p);\
83 if (l < ZEND_LONG_MAX) {\
84 ZVAL_LONG(retval, (zend_long) l);\
85 } else { \
86 ZVAL_NEW_STR(retval, strpprintf(0, __ret_type_sprint_mod, l)); \
87 } \
88 } \
89 return SUCCESS; \
90 }
91
92 #define MYSQLI_MAP_PROPERTY_FUNC_STRING(__func, __int_func, __get_type)\
93 static int __func(mysqli_object *obj, zval *retval, zend_bool quiet)\
94 {\
95 char *c;\
96 __get_type;\
97 if (!p) {\
98 ZVAL_NULL(retval);\
99 } else {\
100 c = (char *)__int_func(p);\
101 if (!c) {\
102 ZVAL_NULL(retval);\
103 } else {\
104 ZVAL_STRING(retval, c);\
105 }\
106 }\
107 return SUCCESS; \
108 }
109
110 /* {{{ property link_client_version_read */
link_client_version_read(mysqli_object * obj,zval * retval,zend_bool quiet)111 static int link_client_version_read(mysqli_object *obj, zval *retval, zend_bool quiet)
112 {
113 ZVAL_LONG(retval, MYSQL_VERSION_ID);
114
115 return SUCCESS;
116 }
117 /* }}} */
118
119 /* {{{ property link_client_info_read */
link_client_info_read(mysqli_object * obj,zval * retval,zend_bool quiet)120 static int link_client_info_read(mysqli_object *obj, zval *retval, zend_bool quiet)
121 {
122 CHECK_STATUS(MYSQLI_STATUS_INITIALIZED, quiet);
123 ZVAL_STRING(retval, MYSQL_SERVER_VERSION);
124
125 return SUCCESS;
126 }
127 /* }}} */
128
129 /* {{{ property link_connect_errno_read */
link_connect_errno_read(mysqli_object * obj,zval * retval,zend_bool quiet)130 static int link_connect_errno_read(mysqli_object *obj, zval *retval, zend_bool quiet)
131 {
132 ZVAL_LONG(retval, (zend_long)MyG(error_no));
133
134 return SUCCESS;
135 }
136 /* }}} */
137
138 /* {{{ property link_connect_error_read */
link_connect_error_read(mysqli_object * obj,zval * retval,zend_bool quiet)139 static int link_connect_error_read(mysqli_object *obj, zval *retval, zend_bool quiet)
140 {
141 if (MyG(error_msg)) {
142 ZVAL_STRING(retval, MyG(error_msg));
143 } else {
144 ZVAL_NULL(retval);
145 }
146
147 return SUCCESS;
148 }
149 /* }}} */
150
151 /* {{{ property link_affected_rows_read */
link_affected_rows_read(mysqli_object * obj,zval * retval,zend_bool quiet)152 static int link_affected_rows_read(mysqli_object *obj, zval *retval, zend_bool quiet)
153 {
154 MY_MYSQL *mysql;
155 my_ulonglong rc;
156
157 CHECK_STATUS(MYSQLI_STATUS_INITIALIZED, quiet);
158
159 mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
160
161 if (!mysql) {
162 ZVAL_NULL(retval);
163 } else {
164 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
165
166 rc = mysql_affected_rows(mysql->mysql);
167
168 if (rc == (my_ulonglong) -1) {
169 ZVAL_LONG(retval, -1);
170 return SUCCESS;
171 }
172
173 if (rc < ZEND_LONG_MAX) {
174 ZVAL_LONG(retval, (zend_long) rc);
175 } else {
176 ZVAL_NEW_STR(retval, strpprintf(0, MYSQLI_LLU_SPEC, rc));
177 }
178 }
179
180 return SUCCESS;
181 }
182 /* }}} */
183
184 /* {{{ property link_error_list_read */
link_error_list_read(mysqli_object * obj,zval * retval,zend_bool quiet)185 static int link_error_list_read(mysqli_object *obj, zval *retval, zend_bool quiet)
186 {
187 MY_MYSQL *mysql;
188
189 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
190
191 mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
192
193 if (mysql) {
194 array_init(retval);
195 #ifdef MYSQLI_USE_MYSQLND
196 if (1) {
197 MYSQLND_ERROR_LIST_ELEMENT * message;
198 zend_llist_position pos;
199 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&mysql->mysql->data->error_info->error_list, &pos);
200 message;
201 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&mysql->mysql->data->error_info->error_list, &pos))
202 {
203 zval single_error;
204 array_init(&single_error);
205 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
206 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
207 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
208 add_next_index_zval(retval, &single_error);
209 }
210 }
211 #else
212 if (mysql_errno(mysql->mysql)) {
213 zval single_error;
214 array_init(&single_error);
215 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_errno(mysql->mysql));
216 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_sqlstate(mysql->mysql));
217 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_error(mysql->mysql));
218 add_next_index_zval(retval, &single_error);
219 }
220 #endif
221 } else {
222 ZVAL_EMPTY_ARRAY(retval);
223 }
224
225 return SUCCESS;
226 }
227 /* }}} */
228
229 /* link properties */
MYSQLI_MAP_PROPERTY_FUNC_LONG(link_errno_read,mysql_errno,MYSQLI_GET_MYSQL (MYSQLI_STATUS_INITIALIZED),zend_ulong,ZEND_ULONG_FMT)230 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_errno_read, mysql_errno, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED), zend_ulong, ZEND_ULONG_FMT)
231 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_error_read, mysql_error, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED))
232 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_field_count_read, mysql_field_count, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
233 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_host_info_read, mysql_get_host_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
234 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_info_read, mysql_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
235 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_insert_id_read, mysql_insert_id, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
236 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_protocol_version_read, mysql_get_proto_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
237 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_server_info_read, mysql_get_server_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
238 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_server_version_read, mysql_get_server_version, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
239 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_sqlstate_read, mysql_sqlstate, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
240 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_thread_id_read, mysql_thread_id, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
241 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_warning_count_read, mysql_warning_count, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
242
243 /* result properties */
244
245 /* {{{ property result_type_read */
246 static int result_type_read(mysqli_object *obj, zval *retval, zend_bool quiet)
247 {
248 MYSQL_RES *p;
249
250 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
251 p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
252
253 if (!p) {
254 ZVAL_NULL(retval);
255 } else {
256 ZVAL_LONG(retval, mysqli_result_is_unbuffered(p) ? MYSQLI_USE_RESULT:MYSQLI_STORE_RESULT);
257 }
258
259 return SUCCESS;
260 }
261 /* }}} */
262
263 /* {{{ property result_lengths_read */
result_lengths_read(mysqli_object * obj,zval * retval,zend_bool quiet)264 static int result_lengths_read(mysqli_object *obj, zval *retval, zend_bool quiet)
265 {
266 MYSQL_RES *p;
267 #ifdef MYSQLI_USE_MYSQLND
268 const size_t *ret;
269 #else
270 const zend_ulong *ret;
271 #endif
272 uint32_t field_count;
273
274 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
275 p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
276 field_count = mysql_num_fields(p);
277 if (!p || !field_count || !(ret = mysql_fetch_lengths(p))) {
278 ZVAL_NULL(retval);
279 } else {
280 zend_ulong i;
281
282 array_init(retval);
283
284 for (i = 0; i < field_count; i++) {
285 add_index_long(retval, i, ret[i]);
286 }
287 }
288
289 return SUCCESS;
290 }
291 /* }}} */
292
MYSQLI_MAP_PROPERTY_FUNC_LONG(result_current_field_read,mysql_field_tell,MYSQLI_GET_RESULT (MYSQLI_STATUS_VALID),zend_ulong,ZEND_ULONG_FMT)293 MYSQLI_MAP_PROPERTY_FUNC_LONG(result_current_field_read, mysql_field_tell, MYSQLI_GET_RESULT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
294 MYSQLI_MAP_PROPERTY_FUNC_LONG(result_field_count_read, mysql_num_fields, MYSQLI_GET_RESULT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
295 MYSQLI_MAP_PROPERTY_FUNC_LONG(result_num_rows_read, mysql_num_rows, MYSQLI_GET_RESULT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
296
297 /* statement properties */
298
299 /* {{{ property stmt_id_read */
300 static int stmt_id_read(mysqli_object *obj, zval *retval, zend_bool quiet)
301 {
302 MY_STMT *p;
303
304 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
305
306 p = (MY_STMT*)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
307
308 if (!p) {
309 ZVAL_NULL(retval);
310 } else {
311 ZVAL_LONG(retval, mysqli_stmt_get_id(p->stmt));
312 }
313
314 return SUCCESS;
315 }
316 /* }}} */
317
318 /* {{{ property stmt_affected_rows_read */
stmt_affected_rows_read(mysqli_object * obj,zval * retval,zend_bool quiet)319 static int stmt_affected_rows_read(mysqli_object *obj, zval *retval, zend_bool quiet)
320 {
321 MY_STMT *p;
322 my_ulonglong rc;
323
324 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
325
326 p = (MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
327
328 if (!p) {
329 ZVAL_NULL(retval);
330 } else {
331 rc = mysql_stmt_affected_rows(p->stmt);
332
333 if (rc == (my_ulonglong) -1) {
334 ZVAL_LONG(retval, -1);
335 return SUCCESS;
336 }
337
338 if (rc < ZEND_LONG_MAX) {
339 ZVAL_LONG(retval, (zend_long) rc);
340 } else {
341 ZVAL_NEW_STR(retval, strpprintf(0, MYSQLI_LLU_SPEC, rc));
342 }
343 }
344
345 return SUCCESS;
346 }
347 /* }}} */
348
349 /* {{{ property stmt_error_list_read */
stmt_error_list_read(mysqli_object * obj,zval * retval,zend_bool quiet)350 static int stmt_error_list_read(mysqli_object *obj, zval *retval, zend_bool quiet)
351 {
352 MY_STMT * stmt;
353
354 CHECK_STATUS(MYSQLI_STATUS_INITIALIZED, quiet);
355
356 stmt = (MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
357 if (stmt && stmt->stmt) {
358 array_init(retval);
359 #ifdef MYSQLI_USE_MYSQLND
360 if (stmt->stmt->data && stmt->stmt->data->error_info) {
361 MYSQLND_ERROR_LIST_ELEMENT * message;
362 zend_llist_position pos;
363 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&stmt->stmt->data->error_info->error_list, &pos);
364 message;
365 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&stmt->stmt->data->error_info->error_list, &pos))
366 {
367 zval single_error;
368 array_init(&single_error);
369 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
370 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
371 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
372 add_next_index_zval(retval, &single_error);
373 }
374 }
375 #else
376 if (mysql_stmt_errno(stmt->stmt)) {
377 zval single_error;
378 array_init(&single_error);
379 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_stmt_errno(stmt->stmt));
380 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_stmt_sqlstate(stmt->stmt));
381 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_stmt_error(stmt->stmt));
382 add_next_index_zval(retval, &single_error);
383 }
384 #endif
385 } else {
386 ZVAL_EMPTY_ARRAY(retval);
387 }
388
389 return SUCCESS;
390 }
391 /* }}} */
392
393 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_insert_id_read, mysql_stmt_insert_id, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
394 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_num_rows_read, mysql_stmt_num_rows, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
395 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_param_count_read, mysql_stmt_param_count, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
396 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_field_count_read, mysql_stmt_field_count, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
397 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_errno_read, mysql_stmt_errno, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED), zend_ulong, ZEND_ULONG_FMT)
398 MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_error_read, mysql_stmt_error, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED))
399 MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_sqlstate_read, mysql_stmt_sqlstate, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED))
400
401 /* }}} */
402 const mysqli_property_entry mysqli_link_property_entries[] = {
403 {"affected_rows", sizeof("affected_rows") - 1, link_affected_rows_read, NULL},
404 {"client_info", sizeof("client_info") - 1, link_client_info_read, NULL},
405 {"client_version", sizeof("client_version") - 1, link_client_version_read, NULL},
406 {"connect_errno", sizeof("connect_errno") - 1, link_connect_errno_read, NULL},
407 {"connect_error", sizeof("connect_error") - 1, link_connect_error_read, NULL},
408 {"errno", sizeof("errno") - 1, link_errno_read, NULL},
409 {"error", sizeof("error") - 1, link_error_read, NULL},
410 {"error_list", sizeof("error_list") - 1, link_error_list_read, NULL},
411 {"field_count", sizeof("field_count") - 1, link_field_count_read, NULL},
412 {"host_info", sizeof("host_info") - 1, link_host_info_read, NULL},
413 {"info", sizeof("info") - 1, link_info_read, NULL},
414 {"insert_id", sizeof("insert_id") - 1, link_insert_id_read, NULL},
415 {"server_info", sizeof("server_info") - 1, link_server_info_read, NULL},
416 {"server_version", sizeof("server_version") - 1, link_server_version_read, NULL},
417 {"sqlstate", sizeof("sqlstate") - 1, link_sqlstate_read, NULL},
418 {"protocol_version",sizeof("protocol_version") - 1, link_protocol_version_read, NULL},
419 {"thread_id", sizeof("thread_id") - 1, link_thread_id_read, NULL},
420 {"warning_count", sizeof("warning_count") - 1, link_warning_count_read, NULL},
421 {NULL, 0, NULL, NULL}
422 };
423
424
425 const mysqli_property_entry mysqli_result_property_entries[] = {
426 {"current_field",sizeof("current_field")-1, result_current_field_read, NULL},
427 {"field_count", sizeof("field_count") - 1, result_field_count_read, NULL},
428 {"lengths", sizeof("lengths") - 1, result_lengths_read, NULL},
429 {"num_rows", sizeof("num_rows") - 1, result_num_rows_read, NULL},
430 {"type", sizeof("type") - 1, result_type_read, NULL},
431 {NULL, 0, NULL, NULL}
432 };
433
434 const mysqli_property_entry mysqli_stmt_property_entries[] = {
435 {"affected_rows", sizeof("affected_rows")-1,stmt_affected_rows_read, NULL},
436 {"insert_id", sizeof("insert_id") - 1, stmt_insert_id_read, NULL},
437 {"num_rows", sizeof("num_rows") - 1, stmt_num_rows_read, NULL},
438 {"param_count", sizeof("param_count") - 1, stmt_param_count_read, NULL},
439 {"field_count", sizeof("field_count") - 1, stmt_field_count_read, NULL},
440 {"errno", sizeof("errno") - 1, stmt_errno_read, NULL},
441 {"error", sizeof("error") - 1, stmt_error_read, NULL},
442 {"error_list", sizeof("error_list") - 1, stmt_error_list_read, NULL},
443 {"sqlstate", sizeof("sqlstate") - 1, stmt_sqlstate_read, NULL},
444 {"id", sizeof("id") - 1, stmt_id_read, NULL},
445 {NULL, 0, NULL, NULL}
446 };
447