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: George Schlossnagle <george@omniti.com> |
14 | Wez Furlong <wez@php.net> |
15 | Johannes Schlueter <johannes@mysql.com> |
16 +----------------------------------------------------------------------+
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "php.h"
24 #include "php_ini.h"
25 #include "ext/standard/info.h"
26 #include "pdo/php_pdo.h"
27 #include "pdo/php_pdo_driver.h"
28 #include "php_pdo_mysql.h"
29 #include "php_pdo_mysql_int.h"
30
31 #ifdef PDO_USE_MYSQLND
32 # define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt)
33 #else
34 # define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
35 #endif
36
37
pdo_mysql_free_result(pdo_mysql_stmt * S)38 static void pdo_mysql_free_result(pdo_mysql_stmt *S)
39 {
40 if (S->result) {
41 #ifndef PDO_USE_MYSQLND
42 if (S->bound_result) {
43 /* We can't use stmt->column_count here, because it gets reset before the
44 * next_rowset handler is called. */
45 unsigned column_count = mysql_num_fields(S->result);
46 for (unsigned i = 0; i < column_count; i++) {
47 efree(S->bound_result[i].buffer);
48 }
49
50 efree(S->bound_result);
51 efree(S->out_null);
52 efree(S->out_length);
53 S->bound_result = NULL;
54 }
55 #endif
56
57 mysql_free_result(S->result);
58 S->result = NULL;
59 }
60 }
61
pdo_mysql_stmt_dtor(pdo_stmt_t * stmt)62 static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
63 {
64 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
65
66 PDO_DBG_ENTER("pdo_mysql_stmt_dtor");
67 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
68
69 pdo_mysql_free_result(S);
70 if (S->einfo.errmsg) {
71 pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
72 S->einfo.errmsg = NULL;
73 }
74 if (S->stmt) {
75 mysql_stmt_close(S->stmt);
76 S->stmt = NULL;
77 }
78
79 #ifndef PDO_USE_MYSQLND
80 if (S->params) {
81 efree(S->params);
82 }
83 if (S->in_null) {
84 efree(S->in_null);
85 }
86 if (S->in_length) {
87 efree(S->in_length);
88 }
89 #endif
90
91 if (!S->done && !Z_ISUNDEF(stmt->database_object_handle)
92 && IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE(stmt->database_object_handle)])
93 && (!(OBJ_FLAGS(Z_OBJ(stmt->database_object_handle)) & IS_OBJ_FREE_CALLED))) {
94 while (mysql_more_results(S->H->server)) {
95 MYSQL_RES *res;
96 if (mysql_next_result(S->H->server) != 0) {
97 break;
98 }
99
100 res = mysql_store_result(S->H->server);
101 if (res) {
102 mysql_free_result(res);
103 }
104 }
105 }
106
107 #ifdef PDO_USE_MYSQLND
108 if (!S->stmt && S->current_data) {
109 mnd_free(S->current_data);
110 }
111 #endif /* PDO_USE_MYSQLND */
112
113 efree(S);
114 PDO_DBG_RETURN(1);
115 }
116 /* }}} */
117
pdo_mysql_stmt_set_row_count(pdo_stmt_t * stmt)118 static void pdo_mysql_stmt_set_row_count(pdo_stmt_t *stmt) /* {{{ */
119 {
120 pdo_mysql_stmt *S = stmt->driver_data;
121 zend_long row_count = (zend_long) mysql_stmt_affected_rows(S->stmt);
122 if (row_count != (zend_long)-1) {
123 stmt->row_count = row_count;
124 }
125 }
126 /* }}} */
127
pdo_mysql_fill_stmt_from_result(pdo_stmt_t * stmt)128 static int pdo_mysql_fill_stmt_from_result(pdo_stmt_t *stmt) /* {{{ */
129 {
130 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
131 pdo_mysql_db_handle *H = S->H;
132 my_ulonglong row_count;
133 PDO_DBG_ENTER("pdo_mysql_fill_stmt_from_result");
134
135 row_count = mysql_affected_rows(H->server);
136 if (row_count == (my_ulonglong)-1) {
137 /* we either have a query that returned a result set or an error occurred
138 lets see if we have access to a result set */
139 if (!H->buffered) {
140 S->result = mysql_use_result(H->server);
141 } else {
142 S->result = mysql_store_result(H->server);
143 }
144 if (NULL == S->result) {
145 pdo_mysql_error_stmt(stmt);
146 PDO_DBG_RETURN(0);
147 }
148
149 stmt->row_count = (zend_long) mysql_num_rows(S->result);
150 php_pdo_stmt_set_column_count(stmt, (int) mysql_num_fields(S->result));
151 S->fields = mysql_fetch_fields(S->result);
152 } else {
153 /* this was a DML or DDL query (INSERT, UPDATE, DELETE, ... */
154 stmt->row_count = (zend_long) row_count;
155 }
156
157 PDO_DBG_RETURN(1);
158 }
159 /* }}} */
160
pdo_mysql_stmt_after_execute_prepared(pdo_stmt_t * stmt)161 static bool pdo_mysql_stmt_after_execute_prepared(pdo_stmt_t *stmt) {
162 pdo_mysql_stmt *S = stmt->driver_data;
163 pdo_mysql_db_handle *H = S->H;
164
165 #ifdef PDO_USE_MYSQLND
166 /* For SHOW/DESCRIBE and others the column/field count is not available before execute. */
167 php_pdo_stmt_set_column_count(stmt, mysql_stmt_field_count(S->stmt));
168 for (int i = 0; i < stmt->column_count; i++) {
169 mysqlnd_stmt_bind_one_result(S->stmt, i);
170 }
171
172 S->result = mysqlnd_stmt_result_metadata(S->stmt);
173 if (S->result) {
174 S->fields = mysql_fetch_fields(S->result);
175 /* If buffered, pre-fetch all the data */
176 if (H->buffered) {
177 if (mysql_stmt_store_result(S->stmt)) {
178 pdo_mysql_error_stmt(stmt);
179 return false;
180 }
181 }
182 }
183 #else
184 /* figure out the result set format, if any */
185 S->result = mysql_stmt_result_metadata(S->stmt);
186 if (S->result) {
187 int calc_max_length = H->buffered && S->max_length == 1;
188 S->fields = mysql_fetch_fields(S->result);
189
190 php_pdo_stmt_set_column_count(stmt, (int)mysql_num_fields(S->result));
191 S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
192 S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
193 S->out_length = ecalloc(stmt->column_count, sizeof(zend_ulong));
194
195 /* summon memory to hold the row */
196 for (int i = 0; i < stmt->column_count; i++) {
197 if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
198 my_bool on = 1;
199 mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
200 calc_max_length = 0;
201 }
202 switch (S->fields[i].type) {
203 case FIELD_TYPE_INT24:
204 S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH + 1;
205 break;
206 case FIELD_TYPE_LONG:
207 S->bound_result[i].buffer_length = MAX_INT_WIDTH + 1;
208 break;
209 case FIELD_TYPE_LONGLONG:
210 S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH + 1;
211 break;
212 case FIELD_TYPE_TINY:
213 S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH + 1;
214 break;
215 case FIELD_TYPE_SHORT:
216 S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH + 1;
217 break;
218 default:
219 S->bound_result[i].buffer_length =
220 S->fields[i].max_length? S->fields[i].max_length:
221 S->fields[i].length;
222 /* work-around for longtext and alike */
223 if (S->bound_result[i].buffer_length > H->max_buffer_size) {
224 S->bound_result[i].buffer_length = H->max_buffer_size;
225 }
226 }
227
228 /* there are cases where the length reported by mysql is too short.
229 * eg: when describing a table that contains an enum column. Since
230 * we have no way of knowing the true length either, we'll bump up
231 * our buffer size to a reasonable size, just in case */
232 if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
233 S->bound_result[i].buffer_length = 128;
234 }
235
236 S->out_length[i] = 0;
237
238 S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
239 S->bound_result[i].is_null = &S->out_null[i];
240 S->bound_result[i].length = &S->out_length[i];
241 S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
242 }
243
244 if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
245 pdo_mysql_error_stmt(stmt);
246 PDO_DBG_RETURN(0);
247 }
248
249 /* if buffered, pre-fetch all the data */
250 if (H->buffered) {
251 if (mysql_stmt_store_result(S->stmt)) {
252 pdo_mysql_error_stmt(stmt);
253 PDO_DBG_RETURN(0);
254 }
255 }
256 }
257 #endif
258
259 pdo_mysql_stmt_set_row_count(stmt);
260 return true;
261 }
262
263 #ifndef PDO_USE_MYSQLND
pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t * stmt)264 static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt) /* {{{ */
265 {
266 pdo_mysql_stmt *S = stmt->driver_data;
267
268 PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_libmysql");
269
270 /* (re)bind the parameters */
271 if (mysql_stmt_bind_param(S->stmt, S->params) || mysql_stmt_execute(S->stmt)) {
272 if (S->params) {
273 memset(S->params, 0, S->num_params * sizeof(MYSQL_BIND));
274 }
275 pdo_mysql_error_stmt(stmt);
276 if (mysql_stmt_errno(S->stmt) == 2057) {
277 /* CR_NEW_STMT_METADATA makes the statement unusable */
278 S->stmt = NULL;
279 }
280 PDO_DBG_RETURN(0);
281 }
282
283 PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
284 }
285 /* }}} */
286 #endif
287
288 #ifdef PDO_USE_MYSQLND
pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t * stmt)289 static int pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t *stmt) /* {{{ */
290 {
291 pdo_mysql_stmt *S = stmt->driver_data;
292
293 PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_mysqlnd");
294
295 if (mysql_stmt_execute(S->stmt)) {
296 pdo_mysql_error_stmt(stmt);
297 PDO_DBG_RETURN(0);
298 }
299
300 PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
301 }
302 /* }}} */
303 #endif
304
pdo_mysql_stmt_execute(pdo_stmt_t * stmt)305 static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
306 {
307 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
308 pdo_mysql_db_handle *H = S->H;
309 PDO_DBG_ENTER("pdo_mysql_stmt_execute");
310 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
311
312 /* ensure that we free any previous unfetched results */
313 pdo_mysql_free_result(S);
314 S->done = 0;
315
316 if (S->stmt) {
317 PDO_DBG_RETURN(pdo_mysql_stmt_execute_prepared(stmt));
318 }
319
320 if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
321 pdo_mysql_error_stmt(stmt);
322 PDO_DBG_RETURN(0);
323 }
324
325 PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt));
326 }
327 /* }}} */
328
pdo_mysql_stmt_next_rowset(pdo_stmt_t * stmt)329 static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
330 {
331 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
332 pdo_mysql_db_handle *H = S->H;
333 PDO_DBG_ENTER("pdo_mysql_stmt_next_rowset");
334 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
335
336 /* ensure that we free any previous unfetched results */
337 pdo_mysql_free_result(S);
338
339 if (S->stmt) {
340 mysql_stmt_free_result(S->stmt);
341 if (mysql_stmt_next_result(S->stmt)) {
342 pdo_mysql_error_stmt(stmt);
343 S->done = 1;
344 PDO_DBG_RETURN(0);
345 }
346 PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
347 } else {
348 if (mysql_next_result(H->server)) {
349 pdo_mysql_error_stmt(stmt);
350 S->done = 1;
351 PDO_DBG_RETURN(0);
352 }
353 PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt));
354 }
355 }
356 /* }}} */
357
358
359 static const char * const pdo_param_event_names[] =
360 {
361 "PDO_PARAM_EVT_ALLOC",
362 "PDO_PARAM_EVT_FREE",
363 "PDO_PARAM_EVT_EXEC_PRE",
364 "PDO_PARAM_EVT_EXEC_POST",
365 "PDO_PARAM_EVT_FETCH_PRE",
366 "PDO_PARAM_EVT_FETCH_POST",
367 "PDO_PARAM_EVT_NORMALIZE",
368 };
369
370 #ifndef PDO_USE_MYSQLND
371 static unsigned char libmysql_false_buffer = 0;
372 static unsigned char libmysql_true_buffer = 1;
373 #endif
374
pdo_mysql_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type)375 static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) /* {{{ */
376 {
377 zval *parameter;
378 #ifndef PDO_USE_MYSQLND
379 PDO_MYSQL_PARAM_BIND *b;
380 #endif
381 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
382
383 PDO_DBG_ENTER("pdo_mysql_stmt_param_hook");
384 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
385 PDO_DBG_INF_FMT("event = %s", pdo_param_event_names[event_type]);
386 if (S->stmt && param->is_param) {
387 switch (event_type) {
388 case PDO_PARAM_EVT_ALLOC:
389 /* sanity check parameter number range */
390 if (param->paramno < 0 || param->paramno >= S->num_params) {
391 strcpy(stmt->error_code, "HY093");
392 PDO_DBG_RETURN(0);
393 }
394
395 #ifndef PDO_USE_MYSQLND
396 b = &S->params[param->paramno];
397 param->driver_data = b;
398 b->is_null = &S->in_null[param->paramno];
399 b->length = &S->in_length[param->paramno];
400 /* recall how many parameters have been provided */
401 #endif
402 PDO_DBG_RETURN(1);
403
404 case PDO_PARAM_EVT_EXEC_PRE:
405 if (zend_hash_num_elements(stmt->bound_params) < (unsigned int) S->num_params) {
406 /* too few parameter bound */
407 PDO_DBG_ERR("too few parameters bound");
408 strcpy(stmt->error_code, "HY093");
409 PDO_DBG_RETURN(0);
410 }
411
412 if (!Z_ISREF(param->parameter)) {
413 parameter = ¶m->parameter;
414 } else {
415 parameter = Z_REFVAL(param->parameter);
416 }
417
418 #ifdef PDO_USE_MYSQLND
419 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL || (Z_TYPE_P(parameter) == IS_NULL)) {
420 mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_NULL);
421 PDO_DBG_RETURN(1);
422 }
423 #else
424 b = (PDO_MYSQL_PARAM_BIND*)param->driver_data;
425 *b->is_null = 0;
426 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL || Z_TYPE_P(parameter) == IS_NULL) {
427 *b->is_null = 1;
428 b->buffer_type = MYSQL_TYPE_STRING;
429 b->buffer = NULL;
430 b->buffer_length = 0;
431 *b->length = 0;
432 PDO_DBG_RETURN(1);
433 }
434 #endif /* PDO_USE_MYSQLND */
435
436 switch (PDO_PARAM_TYPE(param->param_type)) {
437 case PDO_PARAM_STMT:
438 PDO_DBG_RETURN(0);
439 case PDO_PARAM_LOB:
440 PDO_DBG_INF("PDO_PARAM_LOB");
441 if (!Z_ISREF(param->parameter)) {
442 parameter = ¶m->parameter;
443 } else {
444 parameter = Z_REFVAL(param->parameter);
445 }
446 if (Z_TYPE_P(parameter) == IS_RESOURCE) {
447 php_stream *stm = NULL;
448 php_stream_from_zval_no_verify(stm, parameter);
449 if (stm) {
450 zend_string *mem = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
451 zval_ptr_dtor(parameter);
452 ZVAL_STR(parameter, mem ? mem : ZSTR_EMPTY_ALLOC());
453 } else {
454 pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource");
455 return 0;
456 }
457 }
458 /* fall through */
459
460 default:
461 ;
462 }
463
464 #ifdef PDO_USE_MYSQLND
465 /* Is it really correct to check the zval's type? - But well, that's what the old code below does, too */
466 PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE(param->parameter));
467 if (!Z_ISREF(param->parameter)) {
468 parameter = ¶m->parameter;
469 } else {
470 parameter = Z_REFVAL(param->parameter);
471 }
472 switch (Z_TYPE_P(parameter)) {
473 case IS_STRING:
474 mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_VAR_STRING);
475 break;
476 case IS_LONG:
477 #if SIZEOF_ZEND_LONG==8
478 mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_LONGLONG);
479 #elif SIZEOF_ZEND_LONG==4
480 mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_LONG);
481 #endif /* SIZEOF_LONG */
482 break;
483 case IS_TRUE:
484 case IS_FALSE:
485 mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_TINY);
486 break;
487 case IS_DOUBLE:
488 mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, parameter, MYSQL_TYPE_DOUBLE);
489 break;
490 default:
491 PDO_DBG_RETURN(0);
492 }
493
494 PDO_DBG_RETURN(1);
495 #else
496 PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE(param->parameter));
497 if (!Z_ISREF(param->parameter)) {
498 parameter = ¶m->parameter;
499 } else {
500 parameter = Z_REFVAL(param->parameter);
501 }
502 switch (Z_TYPE_P(parameter)) {
503 case IS_STRING:
504 b->buffer_type = MYSQL_TYPE_STRING;
505 b->buffer = Z_STRVAL_P(parameter);
506 b->buffer_length = Z_STRLEN_P(parameter);
507 *b->length = Z_STRLEN_P(parameter);
508 PDO_DBG_RETURN(1);
509
510 case IS_FALSE:
511 b->buffer_type = MYSQL_TYPE_TINY;
512 b->buffer = &libmysql_false_buffer;
513 PDO_DBG_RETURN(1);
514
515 case IS_TRUE:
516 b->buffer_type = MYSQL_TYPE_TINY;
517 b->buffer = &libmysql_true_buffer;
518 PDO_DBG_RETURN(1);
519
520 case IS_LONG:
521 b->buffer_type = MYSQL_TYPE_LONG;
522 b->buffer = &Z_LVAL_P(parameter);
523 PDO_DBG_RETURN(1);
524
525 case IS_DOUBLE:
526 b->buffer_type = MYSQL_TYPE_DOUBLE;
527 b->buffer = &Z_DVAL_P(parameter);
528 PDO_DBG_RETURN(1);
529
530 default:
531 PDO_DBG_RETURN(0);
532 }
533 #endif /* PDO_USE_MYSQLND */
534 case PDO_PARAM_EVT_FREE:
535 case PDO_PARAM_EVT_EXEC_POST:
536 case PDO_PARAM_EVT_FETCH_PRE:
537 case PDO_PARAM_EVT_FETCH_POST:
538 case PDO_PARAM_EVT_NORMALIZE:
539 /* do nothing */
540 break;
541 }
542 }
543
544 PDO_DBG_RETURN(1);
545 }
546 /* }}} */
547
pdo_mysql_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,zend_long offset)548 static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset) /* {{{ */
549 {
550 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
551
552 if (!S->result) {
553 PDO_DBG_RETURN(0);
554 }
555
556 #ifdef PDO_USE_MYSQLND
557 zend_bool fetched_anything;
558
559 PDO_DBG_ENTER("pdo_mysql_stmt_fetch");
560 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
561 if (S->stmt) {
562 if (FAIL == mysqlnd_stmt_fetch(S->stmt, &fetched_anything) || fetched_anything == FALSE) {
563 pdo_mysql_error_stmt(stmt);
564 PDO_DBG_RETURN(0);
565 }
566
567 PDO_DBG_RETURN(1);
568 }
569
570 if (!S->stmt && S->current_data) {
571 mnd_free(S->current_data);
572 }
573 #else
574 int ret;
575
576 if (S->stmt) {
577 ret = mysql_stmt_fetch(S->stmt);
578
579 # ifdef MYSQL_DATA_TRUNCATED
580 if (ret == MYSQL_DATA_TRUNCATED) {
581 ret = 0;
582 }
583 # endif
584
585 if (ret) {
586 if (ret != MYSQL_NO_DATA) {
587 pdo_mysql_error_stmt(stmt);
588 }
589 PDO_DBG_RETURN(0);
590 }
591
592 PDO_DBG_RETURN(1);
593 }
594 #endif /* PDO_USE_MYSQLND */
595
596 if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
597 if (!S->H->buffered && mysql_errno(S->H->server)) {
598 pdo_mysql_error_stmt(stmt);
599 }
600 PDO_DBG_RETURN(0);
601 }
602
603 S->current_lengths = mysql_fetch_lengths(S->result);
604 PDO_DBG_RETURN(1);
605 }
606 /* }}} */
607
pdo_mysql_stmt_describe(pdo_stmt_t * stmt,int colno)608 static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
609 {
610 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
611 struct pdo_column_data *cols = stmt->columns;
612 int i;
613
614 PDO_DBG_ENTER("pdo_mysql_stmt_describe");
615 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
616 if (!S->result) {
617 PDO_DBG_RETURN(0);
618 }
619
620 if (colno >= stmt->column_count) {
621 /* error invalid column */
622 PDO_DBG_RETURN(0);
623 }
624
625 /* fetch all on demand, this seems easiest
626 ** if we've been here before bail out
627 */
628 if (cols[0].name) {
629 PDO_DBG_RETURN(1);
630 }
631 for (i = 0; i < stmt->column_count; i++) {
632
633 if (S->H->fetch_table_names) {
634 cols[i].name = strpprintf(0, "%s.%s", S->fields[i].table, S->fields[i].name);
635 } else {
636 #ifdef PDO_USE_MYSQLND
637 cols[i].name = zend_string_copy(S->fields[i].sname);
638 #else
639 cols[i].name = zend_string_init(S->fields[i].name, S->fields[i].name_length, 0);
640 #endif
641 }
642
643 cols[i].precision = S->fields[i].decimals;
644 cols[i].maxlen = S->fields[i].length;
645
646 #ifdef PDO_USE_MYSQLND
647 if (S->stmt) {
648 cols[i].param_type = PDO_PARAM_ZVAL;
649 } else
650 #endif
651 {
652 cols[i].param_type = PDO_PARAM_STR;
653 }
654 }
655 PDO_DBG_RETURN(1);
656 }
657 /* }}} */
658
pdo_mysql_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,size_t * len,int * caller_frees)659 static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees) /* {{{ */
660 {
661 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
662
663 PDO_DBG_ENTER("pdo_mysql_stmt_get_col");
664 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
665 if (!S->result) {
666 PDO_DBG_RETURN(0);
667 }
668
669 /* With mysqlnd data is stored inside mysqlnd, not S->current_data */
670 if (!S->stmt) {
671 if (S->current_data == NULL || !S->result) {
672 PDO_DBG_RETURN(0);
673 }
674 }
675
676 if (colno >= stmt->column_count) {
677 /* error invalid column */
678 PDO_DBG_RETURN(0);
679 }
680 #ifdef PDO_USE_MYSQLND
681 if (S->stmt) {
682 Z_TRY_ADDREF(S->stmt->data->result_bind[colno].zv);
683 *ptr = (char*)&S->stmt->data->result_bind[colno].zv;
684 *len = sizeof(zval);
685 PDO_DBG_RETURN(1);
686 }
687 #else
688 if (S->stmt) {
689 if (S->out_null[colno]) {
690 *ptr = NULL;
691 *len = 0;
692 PDO_DBG_RETURN(1);
693 }
694 *ptr = S->bound_result[colno].buffer;
695 if (S->out_length[colno] > S->bound_result[colno].buffer_length) {
696 /* mysql lied about the column width */
697 strcpy(stmt->error_code, "01004"); /* truncated */
698 S->out_length[colno] = S->bound_result[colno].buffer_length;
699 *len = S->out_length[colno];
700 PDO_DBG_RETURN(0);
701 }
702 *len = S->out_length[colno];
703 PDO_DBG_RETURN(1);
704 }
705 #endif
706 *ptr = S->current_data[colno];
707 *len = S->current_lengths[colno];
708 PDO_DBG_RETURN(1);
709 } /* }}} */
710
type_to_name_native(int type)711 static char *type_to_name_native(int type) /* {{{ */
712 {
713 #define PDO_MYSQL_NATIVE_TYPE_NAME(x) case FIELD_TYPE_##x: return #x;
714
715 switch (type) {
716 PDO_MYSQL_NATIVE_TYPE_NAME(STRING)
717 PDO_MYSQL_NATIVE_TYPE_NAME(VAR_STRING)
718 #ifdef FIELD_TYPE_TINY
719 PDO_MYSQL_NATIVE_TYPE_NAME(TINY)
720 #endif
721 #ifdef FIELD_TYPE_BIT
722 PDO_MYSQL_NATIVE_TYPE_NAME(BIT)
723 #endif
724 PDO_MYSQL_NATIVE_TYPE_NAME(SHORT)
725 PDO_MYSQL_NATIVE_TYPE_NAME(LONG)
726 PDO_MYSQL_NATIVE_TYPE_NAME(LONGLONG)
727 PDO_MYSQL_NATIVE_TYPE_NAME(INT24)
728 PDO_MYSQL_NATIVE_TYPE_NAME(FLOAT)
729 PDO_MYSQL_NATIVE_TYPE_NAME(DOUBLE)
730 PDO_MYSQL_NATIVE_TYPE_NAME(DECIMAL)
731 #ifdef FIELD_TYPE_NEWDECIMAL
732 PDO_MYSQL_NATIVE_TYPE_NAME(NEWDECIMAL)
733 #endif
734 #ifdef FIELD_TYPE_GEOMETRY
735 PDO_MYSQL_NATIVE_TYPE_NAME(GEOMETRY)
736 #endif
737 PDO_MYSQL_NATIVE_TYPE_NAME(TIMESTAMP)
738 #ifdef FIELD_TYPE_YEAR
739 PDO_MYSQL_NATIVE_TYPE_NAME(YEAR)
740 #endif
741 PDO_MYSQL_NATIVE_TYPE_NAME(SET)
742 PDO_MYSQL_NATIVE_TYPE_NAME(ENUM)
743 PDO_MYSQL_NATIVE_TYPE_NAME(DATE)
744 #ifdef FIELD_TYPE_NEWDATE
745 PDO_MYSQL_NATIVE_TYPE_NAME(NEWDATE)
746 #endif
747 PDO_MYSQL_NATIVE_TYPE_NAME(TIME)
748 PDO_MYSQL_NATIVE_TYPE_NAME(DATETIME)
749 PDO_MYSQL_NATIVE_TYPE_NAME(TINY_BLOB)
750 PDO_MYSQL_NATIVE_TYPE_NAME(MEDIUM_BLOB)
751 PDO_MYSQL_NATIVE_TYPE_NAME(LONG_BLOB)
752 PDO_MYSQL_NATIVE_TYPE_NAME(BLOB)
753 PDO_MYSQL_NATIVE_TYPE_NAME(NULL)
754 default:
755 return NULL;
756 }
757 #undef PDO_MYSQL_NATIVE_TYPE_NAME
758 } /* }}} */
759
pdo_mysql_stmt_col_meta(pdo_stmt_t * stmt,zend_long colno,zval * return_value)760 static int pdo_mysql_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) /* {{{ */
761 {
762 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
763 const MYSQL_FIELD *F;
764 zval flags;
765 char *str;
766
767 PDO_DBG_ENTER("pdo_mysql_stmt_col_meta");
768 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
769 if (!S->result) {
770 PDO_DBG_RETURN(FAILURE);
771 }
772 if (colno >= stmt->column_count) {
773 /* error invalid column */
774 PDO_DBG_RETURN(FAILURE);
775 }
776
777 array_init(return_value);
778 array_init(&flags);
779
780 F = S->fields + colno;
781
782 if (F->def) {
783 add_assoc_string(return_value, "mysql:def", F->def);
784 }
785 if (IS_NOT_NULL(F->flags)) {
786 add_next_index_string(&flags, "not_null");
787 }
788 if (IS_PRI_KEY(F->flags)) {
789 add_next_index_string(&flags, "primary_key");
790 }
791 if (F->flags & MULTIPLE_KEY_FLAG) {
792 add_next_index_string(&flags, "multiple_key");
793 }
794 if (F->flags & UNIQUE_KEY_FLAG) {
795 add_next_index_string(&flags, "unique_key");
796 }
797 if (IS_BLOB(F->flags)) {
798 add_next_index_string(&flags, "blob");
799 }
800 str = type_to_name_native(F->type);
801 if (str) {
802 add_assoc_string(return_value, "native_type", str);
803 }
804
805 #ifdef PDO_USE_MYSQLND
806 switch (F->type) {
807 case MYSQL_TYPE_BIT:
808 case MYSQL_TYPE_YEAR:
809 case MYSQL_TYPE_TINY:
810 case MYSQL_TYPE_SHORT:
811 case MYSQL_TYPE_INT24:
812 case MYSQL_TYPE_LONG:
813 #if SIZEOF_ZEND_LONG==8
814 case MYSQL_TYPE_LONGLONG:
815 #endif
816 add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
817 break;
818 default:
819 add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
820 break;
821 }
822 #endif
823
824 add_assoc_zval(return_value, "flags", &flags);
825 add_assoc_string(return_value, "table", (char *) (F->table?F->table : ""));
826
827 PDO_DBG_RETURN(SUCCESS);
828 } /* }}} */
829
pdo_mysql_stmt_cursor_closer(pdo_stmt_t * stmt)830 static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt) /* {{{ */
831 {
832 pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
833
834 PDO_DBG_ENTER("pdo_mysql_stmt_cursor_closer");
835 PDO_DBG_INF_FMT("stmt=%p", S->stmt);
836
837 S->done = 1;
838 pdo_mysql_free_result(S);
839 if (S->stmt) {
840 mysql_stmt_free_result(S->stmt);
841 }
842
843 while (mysql_more_results(S->H->server)) {
844 MYSQL_RES *res;
845 if (mysql_next_result(S->H->server) != 0) {
846 pdo_mysql_error_stmt(stmt);
847 PDO_DBG_RETURN(0);
848 }
849 res = mysql_store_result(S->H->server);
850 if (res) {
851 mysql_free_result(res);
852 }
853 }
854 PDO_DBG_RETURN(1);
855 }
856 /* }}} */
857
858 const struct pdo_stmt_methods mysql_stmt_methods = {
859 pdo_mysql_stmt_dtor,
860 pdo_mysql_stmt_execute,
861 pdo_mysql_stmt_fetch,
862 pdo_mysql_stmt_describe,
863 pdo_mysql_stmt_get_col,
864 pdo_mysql_stmt_param_hook,
865 NULL, /* set_attr */
866 NULL, /* get_attr */
867 pdo_mysql_stmt_col_meta,
868 pdo_mysql_stmt_next_rowset,
869 pdo_mysql_stmt_cursor_closer
870 };
871