Annotation of embedaddon/php/ext/pdo_mysql/mysql_statement.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>