Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_ps.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
                      5:   | Copyright (c) 2006-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:   +----------------------------------------------------------------------+
1.1.1.2 ! misho      15:   | Authors: Andrey Hristov <andrey@mysql.com>                           |
1.1       misho      16:   |          Ulf Wendel <uwendel@mysql.com>                              |
1.1.1.2 ! misho      17:   |          Georg Richter <georg@mysql.com>                             |
1.1       misho      18:   +----------------------------------------------------------------------+
                     19: */
                     20: 
1.1.1.2 ! misho      21: /* $Id$ */
1.1       misho      22: #include "php.h"
                     23: #include "mysqlnd.h"
                     24: #include "mysqlnd_wireprotocol.h"
                     25: #include "mysqlnd_priv.h"
                     26: #include "mysqlnd_result.h"
                     27: #include "mysqlnd_result_meta.h"
                     28: #include "mysqlnd_statistics.h"
                     29: #include "mysqlnd_debug.h"
                     30: #include "mysqlnd_block_alloc.h"
1.1.1.2 ! misho      31: #include "mysqlnd_ext_plugin.h"
1.1       misho      32: 
                     33: #define MYSQLND_SILENT
                     34: 
                     35: 
                     36: const char * const mysqlnd_not_bound_as_blob = "Can't send long data for non-string/non-binary data types";
                     37: const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
                     38: 
                     39: /* Exported by mysqlnd_ps_codec.c */
                     40: enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC);
                     41: 
                     42: enum_func_status mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param,
                     43:                                                                                                unsigned int flags,
                     44:                                                                                                zend_bool *fetched_anything TSRMLS_DC);
                     45: 
                     46: enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param,
                     47:                                                                                           unsigned int flags,
                     48:                                                                                           zend_bool *fetched_anything TSRMLS_DC);
                     49: 
                     50: static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
                     51: static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC);
                     52: 
1.1.1.2 ! misho      53: 
1.1       misho      54: /* {{{ mysqlnd_stmt::store_result */
                     55: static MYSQLND_RES *
                     56: MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
                     57: {
                     58:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                     59:        enum_func_status ret;
1.1.1.2 ! misho      60:        MYSQLND_CONN_DATA * conn;
1.1       misho      61:        MYSQLND_RES * result;
                     62: 
                     63:        DBG_ENTER("mysqlnd_stmt::store_result");
                     64:        if (!stmt || !stmt->conn || !stmt->result) {
                     65:                DBG_RETURN(NULL);
                     66:        }
                     67:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                     68: 
                     69:        conn = stmt->conn;
                     70: 
                     71:        /* be compliant with libmysql - NULL will turn */
                     72:        if (!stmt->field_count) {
                     73:                DBG_RETURN(NULL);
                     74:        }
                     75: 
                     76:        if (stmt->cursor_exists) {
                     77:                /* Silently convert buffered to unbuffered, for now */
                     78:                DBG_RETURN(s->m->use_result(s TSRMLS_CC));
                     79:        }
                     80: 
                     81:        /* Nothing to store for UPSERT/LOAD DATA*/
                     82:        if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA ||
                     83:                stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
                     84:        {
1.1.1.2 ! misho      85:                SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
1.1       misho      86:                                                 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                     87:                DBG_RETURN(NULL);
                     88:        }
                     89: 
                     90:        stmt->default_rset_handler = s->m->store_result;
                     91: 
1.1.1.2 ! misho      92:        SET_EMPTY_ERROR(*stmt->error_info);
        !            93:        SET_EMPTY_ERROR(*conn->error_info);
1.1       misho      94:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
                     95: 
                     96:        result = stmt->result;
                     97:        result->type                    = MYSQLND_RES_PS_BUF;
                     98:        result->m.fetch_row             = mysqlnd_stmt_fetch_row_buffered;
                     99:        result->m.fetch_lengths = NULL;/* makes no sense */
1.1.1.2 ! misho     100:        result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
1.1       misho     101: 
                    102:        result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
                    103: 
1.1.1.2 ! misho     104:        ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC);
1.1       misho     105: 
                    106:        if (PASS == ret) {
                    107:                /* libmysql API docs say it should be so for SELECT statements */
1.1.1.2 ! misho     108:                stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count;
1.1       misho     109: 
                    110:                stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
                    111:        } else {
1.1.1.2 ! misho     112:                COPY_CLIENT_ERROR(*conn->error_info, result->stored_data->error_info);
1.1       misho     113:                stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
                    114:                mnd_efree(stmt->result);
                    115:                stmt->result = NULL;
                    116:                stmt->state = MYSQLND_STMT_PREPARED;
                    117:        }
                    118: 
                    119:        DBG_RETURN(result);
                    120: }
                    121: /* }}} */
                    122: 
                    123: 
                    124: /* {{{ mysqlnd_stmt::get_result */
                    125: static MYSQLND_RES *
                    126: MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
                    127: {
                    128:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho     129:        MYSQLND_CONN_DATA * conn;
1.1       misho     130:        MYSQLND_RES *result;
                    131: 
                    132:        DBG_ENTER("mysqlnd_stmt::get_result");
                    133:        if (!stmt || !stmt->conn || !stmt->result) {
                    134:                DBG_RETURN(NULL);
                    135:        }
                    136:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    137: 
                    138:        conn = stmt->conn;
                    139: 
                    140:        /* be compliant with libmysql - NULL will turn */
                    141:        if (!stmt->field_count) {
                    142:                DBG_RETURN(NULL);
                    143:        }
                    144: 
                    145:        if (stmt->cursor_exists) {
                    146:                /* Silently convert buffered to unbuffered, for now */
                    147:                DBG_RETURN(s->m->use_result(s TSRMLS_CC));
                    148:        }
                    149: 
                    150:        /* Nothing to store for UPSERT/LOAD DATA*/
                    151:        if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
1.1.1.2 ! misho     152:                SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
1.1       misho     153:                                                 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                    154:                DBG_RETURN(NULL);
                    155:        }
                    156: 
1.1.1.2 ! misho     157:        SET_EMPTY_ERROR(*stmt->error_info);
        !           158:        SET_EMPTY_ERROR(*conn->error_info);
1.1       misho     159:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
                    160: 
                    161:        do {
                    162:                result = conn->m->result_init(stmt->result->field_count, stmt->persistent TSRMLS_CC);
                    163:                if (!result) {
1.1.1.2 ! misho     164:                        SET_OOM_ERROR(*conn->error_info);
1.1       misho     165:                        break;
                    166:                }
                    167: 
                    168:                result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
                    169:                if (!result->meta) {
1.1.1.2 ! misho     170:                        SET_OOM_ERROR(*conn->error_info);
1.1       misho     171:                        break;
                    172:                }
                    173: 
                    174:                if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) {
1.1.1.2 ! misho     175:                        stmt->upsert_status->affected_rows = result->stored_data->row_count;
1.1       misho     176:                        stmt->state = MYSQLND_STMT_PREPARED;
                    177:                        result->type = MYSQLND_RES_PS_BUF;
                    178:                } else {
1.1.1.2 ! misho     179:                        COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
1.1       misho     180:                        stmt->state = MYSQLND_STMT_PREPARED;
                    181:                        break;
                    182:                }
                    183:                DBG_RETURN(result);
                    184:        } while (0);
                    185: 
                    186:        if (result) {
                    187:                result->m.free_result(result, TRUE TSRMLS_CC);
                    188:        }
                    189:        DBG_RETURN(NULL);
                    190: }
                    191: /* }}} */
                    192: 
                    193: 
                    194: /* {{{ mysqlnd_stmt::more_results */
                    195: static zend_bool
                    196: MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * s TSRMLS_DC)
                    197: {
                    198:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    199:        DBG_ENTER("mysqlnd_stmt::more_results");
                    200:        /* (conn->state == CONN_NEXT_RESULT_PENDING) too */
1.1.1.2 ! misho     201:        DBG_RETURN((stmt && stmt->conn && (stmt->conn->m->get_server_status(stmt->conn TSRMLS_CC) & SERVER_MORE_RESULTS_EXISTS))?
1.1       misho     202:                                                                        TRUE:
                    203:                                                                        FALSE);
                    204: }
                    205: /* }}} */
                    206: 
                    207: 
                    208: /* {{{ mysqlnd_stmt::next_result */
                    209: static enum_func_status
                    210: MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC)
                    211: {
                    212:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho     213:        MYSQLND_CONN_DATA * conn;
1.1       misho     214: 
                    215:        DBG_ENTER("mysqlnd_stmt::next_result");
                    216:        if (!stmt || !stmt->conn || !stmt->result) {
                    217:                DBG_RETURN(FAIL);
                    218:        }
                    219:        conn = stmt->conn;
                    220:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    221: 
1.1.1.2 ! misho     222:        if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS)) {
1.1       misho     223:                DBG_RETURN(FAIL);
                    224:        }
                    225: 
1.1.1.2 ! misho     226:        DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
1.1       misho     227: 
                    228:        /* Free space for next result */
                    229:        s->m->free_stmt_content(s TSRMLS_CC);
                    230:        {
                    231:                enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC);
                    232:                DBG_RETURN(ret);
                    233:        }
                    234: }
                    235: /* }}} */
                    236: 
                    237: 
                    238: /* {{{ mysqlnd_stmt_skip_metadata */
                    239: static enum_func_status
                    240: mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC)
                    241: {
                    242:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    243:        /* Follows parameter metadata, we have just to skip it, as libmysql does */
                    244:        unsigned int i = 0;
                    245:        enum_func_status ret = FAIL;
                    246:        MYSQLND_PACKET_RES_FIELD * field_packet;
                    247: 
                    248:        DBG_ENTER("mysqlnd_stmt_skip_metadata");
                    249:        if (!stmt || !stmt->conn || !stmt->conn->protocol) {
                    250:                DBG_RETURN(FAIL);
                    251:        }
                    252:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    253: 
                    254:        field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
                    255:        if (!field_packet) {
1.1.1.2 ! misho     256:                SET_OOM_ERROR(*stmt->error_info);
        !           257:                SET_OOM_ERROR(*stmt->conn->error_info);
1.1       misho     258:        } else {
                    259:                ret = PASS;
                    260:                field_packet->skip_parsing = TRUE;
                    261:                for (;i < stmt->param_count; i++) {
                    262:                        if (FAIL == PACKET_READ(field_packet, stmt->conn)) {
                    263:                                ret = FAIL;
                    264:                                break;
                    265:                        }
                    266:                }
                    267:                PACKET_FREE(field_packet);
                    268:        }
                    269: 
                    270:        DBG_RETURN(ret);
                    271: }
                    272: /* }}} */
                    273: 
                    274: 
                    275: /* {{{ mysqlnd_stmt_read_prepare_response */
                    276: static enum_func_status
                    277: mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
                    278: {
                    279:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    280:        MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp;
                    281:        enum_func_status ret = FAIL;
                    282: 
                    283:        DBG_ENTER("mysqlnd_stmt_read_prepare_response");
                    284:        if (!stmt || !stmt->conn || !stmt->conn->protocol) {
                    285:                DBG_RETURN(FAIL);
                    286:        }
                    287:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    288: 
                    289:        prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
                    290:        if (!prepare_resp) {
1.1.1.2 ! misho     291:                SET_OOM_ERROR(*stmt->error_info);
        !           292:                SET_OOM_ERROR(*stmt->conn->error_info);
1.1       misho     293:                goto done;
                    294:        }
                    295: 
                    296:        if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) {
                    297:                goto done;
                    298:        }
                    299: 
                    300:        if (0xFF == prepare_resp->error_code) {
1.1.1.2 ! misho     301:                COPY_CLIENT_ERROR(*stmt->error_info, prepare_resp->error_info);
        !           302:                COPY_CLIENT_ERROR(*stmt->conn->error_info, prepare_resp->error_info);
1.1       misho     303:                goto done;
                    304:        }
                    305:        ret = PASS;
                    306:        stmt->stmt_id = prepare_resp->stmt_id;
1.1.1.2 ! misho     307:        stmt->warning_count = stmt->conn->upsert_status->warning_count = prepare_resp->warning_count;
1.1       misho     308:        stmt->field_count = stmt->conn->field_count = prepare_resp->field_count;
                    309:        stmt->param_count = prepare_resp->param_count;
                    310: done:
                    311:        PACKET_FREE(prepare_resp);
                    312: 
                    313:        DBG_RETURN(ret);
                    314: }
                    315: /* }}} */
                    316: 
                    317: 
                    318: /* {{{ mysqlnd_stmt_prepare_read_eof */
                    319: static enum_func_status
                    320: mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC)
                    321: {
                    322:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    323:        MYSQLND_PACKET_EOF * fields_eof;
                    324:        enum_func_status ret = FAIL;
                    325: 
                    326:        DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
                    327:        if (!stmt || !stmt->conn || !stmt->conn->protocol) {
                    328:                DBG_RETURN(FAIL);
                    329:        }
                    330:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    331: 
                    332:        fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
                    333:        if (!fields_eof) {
1.1.1.2 ! misho     334:                SET_OOM_ERROR(*stmt->error_info);
        !           335:                SET_OOM_ERROR(*stmt->conn->error_info);
1.1       misho     336:        } else {
                    337:                if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
                    338:                        if (stmt->result) {
                    339:                                stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
                    340:                                mnd_efree(stmt->result);
                    341:                                memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
                    342:                                stmt->state = MYSQLND_STMT_INITTED;
                    343:                        }
                    344:                } else {
1.1.1.2 ! misho     345:                        stmt->upsert_status->server_status = fields_eof->server_status;
        !           346:                        stmt->upsert_status->warning_count = fields_eof->warning_count;
1.1       misho     347:                        stmt->state = MYSQLND_STMT_PREPARED;
                    348:                }
                    349:                PACKET_FREE(fields_eof);
                    350:        }
                    351: 
                    352:        DBG_RETURN(ret);
                    353: }
                    354: /* }}} */
                    355: 
                    356: 
                    357: /* {{{ mysqlnd_stmt::prepare */
                    358: static enum_func_status
                    359: MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const query, unsigned int query_len TSRMLS_DC)
                    360: {
                    361:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    362:        MYSQLND_STMT * s_to_prepare = s;
                    363:        MYSQLND_STMT_DATA * stmt_to_prepare = stmt;
                    364: 
                    365:        DBG_ENTER("mysqlnd_stmt::prepare");
                    366:        if (!stmt || !stmt->conn) {
                    367:                DBG_RETURN(FAIL);
                    368:        }
                    369:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
1.1.1.2 ! misho     370:        DBG_INF_FMT("query=%s", query);
1.1       misho     371: 
                    372:        SET_ERROR_AFF_ROWS(stmt);
                    373:        SET_ERROR_AFF_ROWS(stmt->conn);
                    374: 
1.1.1.2 ! misho     375:        SET_EMPTY_ERROR(*stmt->error_info);
        !           376:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho     377: 
                    378:        if (stmt->state > MYSQLND_STMT_INITTED) {
                    379:                /* See if we have to clean the wire */
                    380:                if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
                    381:                        /* Do implicit use_result and then flush the result */
                    382:                        stmt->default_rset_handler = s->m->use_result;
                    383:                        stmt->default_rset_handler(s TSRMLS_CC);
                    384:                }
                    385:                /* No 'else' here please :) */
                    386:                if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE && stmt->result) {
                    387:                        stmt->result->m.skip_result(stmt->result TSRMLS_CC);
                    388:                }
                    389:                /*
                    390:                  Create a new test statement, which we will prepare, but if anything
                    391:                  fails, we will scrap it.
                    392:                */
                    393:                s_to_prepare = stmt->conn->m->stmt_init(stmt->conn TSRMLS_CC);
                    394:                if (!s_to_prepare) {
                    395:                        goto fail;
                    396:                }
                    397:                stmt_to_prepare = s_to_prepare->data;
                    398:        }
                    399: 
1.1.1.2 ! misho     400:        if (FAIL == stmt_to_prepare->conn->m->simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, (const zend_uchar *) query, query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) ||
1.1       misho     401:                FAIL == mysqlnd_stmt_read_prepare_response(s_to_prepare TSRMLS_CC))
                    402:        {
                    403:                goto fail;
                    404:        }
                    405: 
                    406:        if (stmt_to_prepare->param_count) {
                    407:                if (FAIL == mysqlnd_stmt_skip_metadata(s_to_prepare TSRMLS_CC) ||
                    408:                        FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
                    409:                {
                    410:                        goto fail;
                    411:                }
                    412:        }
                    413: 
                    414:        /*
                    415:          Read metadata only if there is actual result set.
                    416:          Beware that SHOW statements bypass the PS framework and thus they send
                    417:          no metadata at prepare.
                    418:        */
                    419:        if (stmt_to_prepare->field_count) {
                    420:                MYSQLND_RES * result = stmt->conn->m->result_init(stmt_to_prepare->field_count, stmt_to_prepare->persistent TSRMLS_CC);
                    421:                if (!result) {
1.1.1.2 ! misho     422:                        SET_OOM_ERROR(*stmt->conn->error_info);
1.1       misho     423:                        goto fail;
                    424:                }
                    425:                /* Allocate the result now as it is needed for the reading of metadata */
                    426:                stmt_to_prepare->result = result; 
                    427: 
                    428:                result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn TSRMLS_CC);
                    429: 
                    430:                result->type = MYSQLND_RES_PS_BUF;
                    431: 
                    432:                if (FAIL == result->m.read_result_metadata(result, stmt_to_prepare->conn TSRMLS_CC) ||
                    433:                        FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
                    434:                {
                    435:                        goto fail;
                    436:                }
                    437:        }
                    438: 
                    439:        if (stmt_to_prepare != stmt) {
                    440:                /* swap */
                    441:                size_t real_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
                    442:                char * tmp_swap = mnd_malloc(real_size);
                    443:                memcpy(tmp_swap, s, real_size);
                    444:                memcpy(s, s_to_prepare, real_size);
                    445:                memcpy(s_to_prepare, tmp_swap, real_size);
                    446:                mnd_free(tmp_swap);
                    447:                {
                    448:                        MYSQLND_STMT_DATA * tmp_swap_data = stmt_to_prepare;
                    449:                        stmt_to_prepare = stmt;
                    450:                        stmt = tmp_swap_data;
                    451:                }
                    452:                s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
                    453:        }
                    454:        stmt->state = MYSQLND_STMT_PREPARED;
                    455:        DBG_INF("PASS");
                    456:        DBG_RETURN(PASS);
                    457: 
                    458: fail:
                    459:        if (stmt_to_prepare != stmt && s_to_prepare) {
                    460:                s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
                    461:        }
                    462:        stmt->state = MYSQLND_STMT_INITTED;
                    463: 
                    464:        DBG_INF("FAIL");
                    465:        DBG_RETURN(FAIL);
                    466: }
                    467: /* }}} */
                    468: 
                    469: 
                    470: /* {{{ mysqlnd_stmt_execute_parse_response */
                    471: static enum_func_status
                    472: mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC)
                    473: {
                    474:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    475:        enum_func_status ret;
1.1.1.2 ! misho     476:        MYSQLND_CONN_DATA * conn;
1.1       misho     477: 
                    478:        DBG_ENTER("mysqlnd_stmt_execute_parse_response");
                    479:        if (!stmt || !stmt->conn) {
                    480:                DBG_RETURN(FAIL);
                    481:        }
                    482:        conn = stmt->conn;
                    483:        CONN_SET_STATE(conn, CONN_QUERY_SENT);
                    484: 
                    485:        ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC);
                    486:        if (ret == FAIL) {
1.1.1.2 ! misho     487:                COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
        !           488:                stmt->upsert_status->affected_rows = conn->upsert_status->affected_rows;
1.1       misho     489:                if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
                    490:                        /* close the statement here, the connection has been closed */
                    491:                }
                    492:                stmt->state = MYSQLND_STMT_PREPARED;
                    493:                stmt->send_types_to_server = 1;
                    494:        } else {
                    495:                /*
                    496:                  stmt->send_types_to_server has already been set to 0 in
                    497:                  mysqlnd_stmt_execute_generate_request / mysqlnd_stmt_execute_store_params
                    498:                  In case there is a situation in which binding was done for integer and the
                    499:                  value is > LONG_MAX or < LONG_MIN, there is string conversion and we have
                    500:                  to resend the types. Next execution will also need to resend the type.
                    501:                */
1.1.1.2 ! misho     502:                SET_EMPTY_ERROR(*stmt->error_info);
        !           503:                SET_EMPTY_ERROR(*stmt->conn->error_info);
        !           504:                *stmt->upsert_status = *conn->upsert_status; /* copy status */
1.1       misho     505:                stmt->state = MYSQLND_STMT_EXECUTED;
                    506:                if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type == QUERY_LOAD_LOCAL) {
                    507:                        DBG_INF("PASS");
                    508:                        DBG_RETURN(PASS);
                    509:                }
                    510: 
                    511:                stmt->result->type = MYSQLND_RES_PS_BUF;
                    512:                if (!stmt->result->conn) {
                    513:                        /*
                    514:                          For SHOW we don't create (bypasses PS in server)
                    515:                          a result set at prepare and thus a connection was missing
                    516:                        */
                    517:                        stmt->result->conn = stmt->conn->m->get_reference(stmt->conn TSRMLS_CC);
                    518:                }
                    519: 
                    520:                /* Update stmt->field_count as SHOW sets it to 0 at prepare */
                    521:                stmt->field_count = stmt->result->field_count = conn->field_count;
                    522:                stmt->result->lengths = NULL;
                    523:                if (stmt->field_count) {
                    524:                        stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
                    525:                        /*
                    526:                          We need to set this because the user might not call
                    527:                          use_result() or store_result() and we should be able to scrap the
                    528:                          data on the line, if he just decides to close the statement.
                    529:                        */
1.1.1.2 ! misho     530:                        DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status,
        !           531:                                                stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
1.1       misho     532: 
1.1.1.2 ! misho     533:                        if (stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS) {
1.1       misho     534:                                DBG_INF("cursor exists");
                    535:                                stmt->cursor_exists = TRUE;
                    536:                                CONN_SET_STATE(conn, CONN_READY);
                    537:                                /* Only cursor read */
                    538:                                stmt->default_rset_handler = s->m->use_result;
                    539:                                DBG_INF("use_result");
                    540:                        } else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
                    541:                                DBG_INF("asked for cursor but got none");
                    542:                                /*
                    543:                                  We have asked for CURSOR but got no cursor, because the condition
                    544:                                  above is not fulfilled. Then...
                    545: 
                    546:                                  This is a single-row result set, a result set with no rows, EXPLAIN,
                    547:                                  SHOW VARIABLES, or some other command which either a) bypasses the
                    548:                                  cursors framework in the server and writes rows directly to the
                    549:                                  network or b) is more efficient if all (few) result set rows are
                    550:                                  precached on client and server's resources are freed.
                    551:                                */
                    552:                                /* preferred is buffered read */
                    553:                                stmt->default_rset_handler = s->m->store_result;
                    554:                                DBG_INF("store_result");
                    555:                        } else {
                    556:                                DBG_INF("no cursor");
                    557:                                /* preferred is unbuffered read */
                    558:                                stmt->default_rset_handler = s->m->use_result;
                    559:                                DBG_INF("use_result");
                    560:                        }
                    561:                }
                    562:        }
                    563: #ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET
1.1.1.2 ! misho     564:        if (stmt->upsert_status->server_status & SERVER_PS_OUT_PARAMS) {
1.1       misho     565:                s->m->free_stmt_content(s TSRMLS_CC);
                    566:                DBG_INF("PS OUT Variable RSet, skipping");
                    567:                /* OUT params result set. Skip for now to retain compatibility */
                    568:                ret = mysqlnd_stmt_execute_parse_response(s TSRMLS_CC);
                    569:        }
                    570: #endif
                    571: 
                    572:        DBG_INF(ret == PASS? "PASS":"FAIL");
                    573:        DBG_RETURN(ret);
                    574: }
                    575: /* }}} */
                    576: 
                    577: 
                    578: /* {{{ mysqlnd_stmt::execute */
                    579: static enum_func_status
                    580: MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
                    581: {
                    582:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    583:        enum_func_status ret;
1.1.1.2 ! misho     584:        MYSQLND_CONN_DATA * conn;
1.1       misho     585:        zend_uchar *request = NULL;
                    586:        size_t          request_len;
                    587:        zend_bool       free_request;
                    588: 
                    589:        DBG_ENTER("mysqlnd_stmt::execute");
                    590:        if (!stmt || !stmt->conn) {
                    591:                DBG_RETURN(FAIL);
                    592:        }
                    593:        conn = stmt->conn;
                    594:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    595: 
                    596:        SET_ERROR_AFF_ROWS(stmt);
                    597:        SET_ERROR_AFF_ROWS(stmt->conn);
                    598: 
                    599:        if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) {
                    600:                /*
                    601:                  We don need to copy the data from the buffers which we will clean.
                    602:                  Because it has already been copied. See
                    603:                  #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                    604:                */
                    605: #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                    606:                if (stmt->result_bind &&
                    607:                        stmt->result_zvals_separated_once == TRUE && 
                    608:                        stmt->state >= MYSQLND_STMT_USER_FETCHING)
                    609:                {
                    610:                        /*
                    611:                          We need to copy the data from the buffers which we will clean.
                    612:                          The bound variables point to them only if the user has started
                    613:                          to fetch data (MYSQLND_STMT_USER_FETCHING).
                    614:                          We need to check 'result_zvals_separated_once' or we will leak
                    615:                          in the following scenario
                    616:                          prepare("select 1 from dual");
                    617:                          execute();
                    618:                          fetch(); <-- no binding, but that's not a problem
                    619:                          bind_result();
                    620:                          execute(); <-- here we will leak because we separate without need
                    621:                        */
                    622:                        unsigned int i;
                    623:                        for (i = 0; i < stmt->field_count; i++) {
                    624:                                if (stmt->result_bind[i].bound == TRUE) {
                    625:                                        zval_copy_ctor(stmt->result_bind[i].zv);
                    626:                                }
                    627:                        }
                    628:                }
                    629: #endif
                    630: 
1.1.1.2 ! misho     631:                s->m->flush(s TSRMLS_CC);
1.1       misho     632: 
                    633:                /*
                    634:                  Executed, but the user hasn't started to fetch
                    635:                  This will clean also the metadata, but after the EXECUTE call we will
                    636:                  have it again.
                    637:                */
                    638:                stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
                    639:        } else if (stmt->state < MYSQLND_STMT_PREPARED) {
                    640:                /* Only initted - error */
1.1.1.2 ! misho     641:                SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
1.1       misho     642:                                                 mysqlnd_out_of_sync);
                    643:                SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                    644:                DBG_INF("FAIL");
                    645:                DBG_RETURN(FAIL);
                    646:        }
                    647: 
                    648:        if (stmt->param_count) {
                    649:                unsigned int i, not_bound = 0;
                    650:                if (!stmt->param_bind) {
                    651:                        SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
                    652:                                                         "No data supplied for parameters in prepared statement");
                    653:                        DBG_INF("FAIL");
                    654:                        DBG_RETURN(FAIL);
                    655:                }
                    656:                for (i = 0; i < stmt->param_count; i++) {
                    657:                        if (stmt->param_bind[i].zv == NULL) {
                    658:                                not_bound++;
                    659:                        }
                    660:                }
                    661:                if (not_bound) {
                    662:                        char * msg;
1.1.1.2 ! misho     663:                        mnd_sprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement",
        !           664:                                                not_bound, not_bound>1 ?"s":"");
1.1       misho     665:                        SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, msg);
                    666:                        if (msg) {
1.1.1.2 ! misho     667:                                mnd_sprintf_free(msg);
1.1       misho     668:                        }
                    669:                        DBG_INF("FAIL");
                    670:                        DBG_RETURN(FAIL);
                    671:                }
                    672:        }
                    673:        ret = s->m->generate_execute_request(s, &request, &request_len, &free_request TSRMLS_CC);
                    674:        if (ret == PASS) {
                    675:                /* support for buffer types should be added here ! */
1.1.1.2 ! misho     676:                ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, request, request_len,
1.1       misho     677:                                                                                        PROT_LAST /* we will handle the response packet*/,
                    678:                                                                                        FALSE, FALSE TSRMLS_CC);
                    679:        } else {
                    680:                SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM.");
                    681:        }
                    682: 
                    683:        if (free_request) {
                    684:                mnd_efree(request);
                    685:        }
                    686: 
                    687:        if (ret == FAIL) {
1.1.1.2 ! misho     688:                COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
1.1       misho     689:                DBG_INF("FAIL");
                    690:                DBG_RETURN(FAIL);
                    691:        }
                    692:        stmt->execute_count++;
                    693: 
                    694:        ret = s->m->parse_execute_response(s TSRMLS_CC);
                    695: 
1.1.1.2 ! misho     696:        DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
1.1       misho     697: 
1.1.1.2 ! misho     698:        if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status->affected_rows) {
        !           699:                MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status->affected_rows);
1.1       misho     700:        }
                    701:        DBG_RETURN(ret);
                    702: }
                    703: /* }}} */
                    704: 
                    705: 
                    706: /* {{{ mysqlnd_stmt_fetch_row_buffered */
                    707: enum_func_status
                    708: mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
                    709: {
                    710:        MYSQLND_STMT * s = (MYSQLND_STMT *) param;
                    711:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    712:        MYSQLND_RES_BUFFERED *set = result->stored_data;
                    713:        unsigned int field_count = result->meta->field_count;
                    714: 
                    715:        DBG_ENTER("mysqlnd_stmt_fetch_row_buffered");
                    716:        *fetched_anything = FALSE;
                    717:        DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L);
                    718: 
                    719:        /* If we haven't read everything */
                    720:        if (set->data_cursor &&
                    721:                (set->data_cursor - set->data) < (set->row_count * field_count))
                    722:        {
                    723:                /* The user could have skipped binding - don't crash*/
                    724:                if (stmt->result_bind) {
                    725:                        unsigned int i;
                    726:                        MYSQLND_RES_METADATA * meta = result->meta;
                    727:                        zval **current_row = set->data_cursor;
                    728: 
                    729:                        if (NULL == current_row[0]) {
                    730:                                uint64_t row_num = (set->data_cursor - set->data) / field_count;
                    731:                                enum_func_status rc = result->m.row_decoder(set->row_buffers[row_num],
                    732:                                                                                                current_row,
                    733:                                                                                                meta->field_count,
                    734:                                                                                                meta->fields,
1.1.1.2 ! misho     735:                                                                                                result->conn->options->numeric_and_datetime_as_unicode,
        !           736:                                                                                                result->conn->options->int_and_float_native,
1.1       misho     737:                                                                                                result->conn->stats TSRMLS_CC);
                    738:                                if (PASS != rc) {
                    739:                                        DBG_RETURN(FAIL);
                    740:                                }
                    741:                                set->initialized_rows++;
                    742:                                if (stmt->update_max_length) {
                    743:                                        for (i = 0; i < result->field_count; i++) {
                    744:                                                /*
                    745:                                                  NULL fields are 0 length, 0 is not more than 0
                    746:                                                  String of zero size, definitely can't be the next max_length.
                    747:                                                  Thus for NULL and zero-length we are quite efficient.
                    748:                                                */
                    749:                                                if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
                    750:                                                        unsigned long len = Z_STRLEN_P(current_row[i]);
                    751:                                                        if (meta->fields[i].max_length < len) {
                    752:                                                                meta->fields[i].max_length = len;
                    753:                                                        }
                    754:                                                }
                    755:                                        }
                    756:                                }
                    757:                        }
                    758: 
                    759:                        for (i = 0; i < result->field_count; i++) {
                    760:                                /* Clean what we copied last time */
                    761: #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                    762:                                if (stmt->result_bind[i].zv) {
                    763:                                        zval_dtor(stmt->result_bind[i].zv);
                    764:                                }
                    765: #endif
                    766:                                /* copy the type */
                    767:                                if (stmt->result_bind[i].bound == TRUE) {
                    768:                                        DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
                    769:                                        if (Z_TYPE_P(current_row[i]) != IS_NULL) {
                    770:                                                /*
                    771:                                                  Copy the value.
                    772:                                                  Pre-condition is that the zvals in the result_bind buffer
                    773:                                                  have been  ZVAL_NULL()-ed or to another simple type
                    774:                                                  (int, double, bool but not string). Because of the reference
                    775:                                                  counting the user can't delete the strings the variables point to.
                    776:                                                */
                    777: 
                    778:                                                Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
                    779:                                                stmt->result_bind[i].zv->value = current_row[i]->value;
                    780: #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                    781:                                                zval_copy_ctor(stmt->result_bind[i].zv);
                    782: #endif
                    783:                                        } else {
                    784:                                                ZVAL_NULL(stmt->result_bind[i].zv);
                    785:                                        }
                    786:                                }
                    787:                        }
                    788:                }
                    789:                set->data_cursor += field_count;
                    790:                *fetched_anything = TRUE;
                    791:                /* buffered result sets don't have a connection */
                    792:                MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
                    793:                DBG_INF("row fetched");
                    794:        } else {
                    795:                set->data_cursor = NULL;
                    796:                DBG_INF("no more data");
                    797:        }
                    798:        DBG_INF("PASS");
                    799:        DBG_RETURN(PASS);
                    800: }
                    801: /* }}} */
                    802: 
                    803: 
                    804: /* {{{ mysqlnd_stmt_fetch_row_unbuffered */
                    805: static enum_func_status
                    806: mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
                    807: {
                    808:        enum_func_status ret;
                    809:        MYSQLND_STMT * s = (MYSQLND_STMT *) param;
                    810:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    811:        MYSQLND_PACKET_ROW * row_packet;
                    812: 
                    813:        DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
                    814: 
                    815:        *fetched_anything = FALSE;
                    816: 
                    817:        if (result->unbuf->eof_reached) {
                    818:                /* No more rows obviously */
1.1.1.2 ! misho     819:                DBG_INF("EOF already reached");
1.1       misho     820:                DBG_RETURN(PASS);
                    821:        }
                    822:        if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) {
1.1.1.2 ! misho     823:                SET_CLIENT_ERROR(*result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
1.1       misho     824:                                                 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                    825:                DBG_ERR("command out of sync");
                    826:                DBG_RETURN(FAIL);
                    827:        }
                    828:        if (!(row_packet = result->row_packet)) {
                    829:                DBG_RETURN(FAIL);
                    830:        }
                    831: 
                    832:        /* Let the row packet fill our buffer and skip additional malloc + memcpy */
                    833:        row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
                    834: 
                    835:        /*
                    836:          If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to
                    837:          result->m.unbuffered_free_last_data() before it. The function returns always true.
                    838:        */
                    839:        if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
                    840:                unsigned int i, field_count = result->field_count;
                    841: 
                    842:                if (!row_packet->skip_extraction) {
                    843:                        result->m.unbuffered_free_last_data(result TSRMLS_CC);
                    844: 
                    845:                        result->unbuf->last_row_data = row_packet->fields;
                    846:                        result->unbuf->last_row_buffer = row_packet->row_buffer;
                    847:                        row_packet->fields = NULL;
                    848:                        row_packet->row_buffer = NULL;
                    849: 
                    850:                        if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
                    851:                                                                        result->unbuf->last_row_data,
                    852:                                                                        row_packet->field_count,
                    853:                                                                        row_packet->fields_metadata,
1.1.1.2 ! misho     854:                                                                        result->conn->options->numeric_and_datetime_as_unicode,
        !           855:                                                                        result->conn->options->int_and_float_native,
1.1       misho     856:                                                                        result->conn->stats TSRMLS_CC))
                    857:                        {
                    858:                                DBG_RETURN(FAIL);
                    859:                        }
                    860: 
                    861:                        for (i = 0; i < field_count; i++) {
                    862:                                if (stmt->result_bind[i].bound == TRUE) {
                    863:                                        zval *data = result->unbuf->last_row_data[i];
                    864:                                        /*
                    865:                                          stmt->result_bind[i].zv has been already destructed
                    866:                                          in result->m.unbuffered_free_last_data()
                    867:                                        */
                    868: #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                    869:                                        zval_dtor(stmt->result_bind[i].zv);
                    870: #endif
                    871:                                        if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
                    872:                                                if (
                    873:                                                        (Z_TYPE_P(data) == IS_STRING
                    874: #if MYSQLND_UNICODE
                    875:                                                        || Z_TYPE_P(data) == IS_UNICODE
                    876: #endif
                    877:                                                        )
                    878:                                                         && (result->meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data)))
                    879:                                                {
                    880:                                                        result->meta->fields[i].max_length = Z_STRLEN_P(data);
                    881:                                                }
                    882:                                                stmt->result_bind[i].zv->value = data->value;
                    883:                                                /* copied data, thus also the ownership. Thus null data */
                    884:                                                ZVAL_NULL(data);
                    885:                                        }
                    886:                                }
                    887:                        }
                    888:                        MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF);
                    889:                } else {
                    890:                        DBG_INF("skipping extraction");
                    891:                        /*
                    892:                          Data has been allocated and usually result->m.unbuffered_free_last_data()
                    893:                          frees it but we can't call this function as it will cause problems with
                    894:                          the bound variables. Thus we need to do part of what it does or Zend will
                    895:                          report leaks.
                    896:                        */
                    897:                        row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
                    898:                        row_packet->row_buffer = NULL;
                    899:                }
                    900: 
                    901:                result->unbuf->row_count++;
                    902:                *fetched_anything = TRUE;
                    903:        } else if (ret == FAIL) {
                    904:                if (row_packet->error_info.error_no) {
1.1.1.2 ! misho     905:                        COPY_CLIENT_ERROR(*stmt->conn->error_info, row_packet->error_info);
        !           906:                        COPY_CLIENT_ERROR(*stmt->error_info, row_packet->error_info);
1.1       misho     907:                }
                    908:                CONN_SET_STATE(result->conn, CONN_READY);
                    909:                result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
                    910:        } else if (row_packet->eof) {
                    911:                DBG_INF("EOF");
                    912:                /* Mark the connection as usable again */
                    913:                result->unbuf->eof_reached = TRUE;
1.1.1.2 ! misho     914:                result->conn->upsert_status->warning_count = row_packet->warning_count;
        !           915:                result->conn->upsert_status->server_status = row_packet->server_status;
1.1       misho     916:                /*
                    917:                  result->row_packet will be cleaned when
                    918:                  destroying the result object
                    919:                */
1.1.1.2 ! misho     920:                if (result->conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS) {
1.1       misho     921:                        CONN_SET_STATE(result->conn, CONN_NEXT_RESULT_PENDING);
                    922:                } else {
                    923:                        CONN_SET_STATE(result->conn, CONN_READY);
                    924:                }
                    925:        }
                    926: 
                    927:        DBG_INF_FMT("ret=%s fetched_anything=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
                    928:        DBG_RETURN(ret);
                    929: }
                    930: /* }}} */
                    931: 
                    932: 
                    933: /* {{{ mysqlnd_stmt::use_result */
                    934: static MYSQLND_RES *
                    935: MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC)
                    936: {
                    937:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho     938:        MYSQLND_RES * result;
        !           939:        MYSQLND_CONN_DATA * conn;
1.1       misho     940: 
                    941:        DBG_ENTER("mysqlnd_stmt::use_result");
                    942:        if (!stmt || !stmt->conn || !stmt->result) {
                    943:                DBG_RETURN(NULL);
                    944:        }
                    945:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                    946: 
                    947:        conn = stmt->conn;
                    948: 
                    949:        if (!stmt->field_count ||
                    950:                (!stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_FETCHING_DATA) ||
                    951:                (stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) ||
                    952:                (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
                    953:        {
1.1.1.2 ! misho     954:                SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
1.1       misho     955:                                                 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                    956:                DBG_ERR("command out of sync");
                    957:                DBG_RETURN(NULL);
                    958:        }
                    959: 
1.1.1.2 ! misho     960:        SET_EMPTY_ERROR(*stmt->error_info);
1.1       misho     961: 
                    962:        MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);
                    963:        result = stmt->result;
                    964: 
                    965:        result->m.use_result(stmt->result, TRUE TSRMLS_CC);
                    966:        result->m.fetch_row     = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
                    967:                                                                                           mysqlnd_stmt_fetch_row_unbuffered;
                    968:        stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
                    969: 
                    970:        DBG_INF_FMT("%p", result);
                    971:        DBG_RETURN(result);
                    972: }
                    973: /* }}} */
                    974: 
                    975: 
                    976: #define STMT_ID_LENGTH 4
                    977: 
                    978: /* {{{ mysqlnd_fetch_row_cursor */
                    979: enum_func_status
                    980: mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
                    981: {
                    982:        enum_func_status ret;
                    983:        MYSQLND_STMT * s = (MYSQLND_STMT *) param;
                    984:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                    985:        zend_uchar buf[STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
                    986:        MYSQLND_PACKET_ROW * row_packet;
                    987: 
                    988:        DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
                    989: 
                    990:        if (!stmt || !stmt->conn || !result || !result->conn || !result->unbuf) {
                    991:                DBG_ERR("no statement");
                    992:                DBG_RETURN(FAIL);
                    993:        }
                    994: 
                    995:        DBG_INF_FMT("stmt=%lu flags=%u", stmt->stmt_id, flags);
                    996: 
                    997:        if (stmt->state < MYSQLND_STMT_USER_FETCHING) {
                    998:                /* Only initted - error */
1.1.1.2 ! misho     999:                SET_CLIENT_ERROR(*stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
1.1       misho    1000:                                                mysqlnd_out_of_sync);
                   1001:                DBG_ERR("command out of sync");
                   1002:                DBG_RETURN(FAIL);
                   1003:        }
                   1004:        if (!(row_packet = result->row_packet)) {
                   1005:                DBG_RETURN(FAIL);
                   1006:        }
                   1007: 
1.1.1.2 ! misho    1008:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1009:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1010: 
                   1011:        int4store(buf, stmt->stmt_id);
                   1012:        int4store(buf + STMT_ID_LENGTH, 1); /* for now fetch only one row */
                   1013: 
1.1.1.2 ! misho    1014:        if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, buf, sizeof(buf),
1.1       misho    1015:                                                                                          PROT_LAST /* we will handle the response packet*/,
                   1016:                                                                                          FALSE, TRUE TSRMLS_CC)) {
1.1.1.2 ! misho    1017:                COPY_CLIENT_ERROR(*stmt->error_info, *stmt->conn->error_info);
1.1       misho    1018:                DBG_RETURN(FAIL);
                   1019:        }
                   1020: 
                   1021:        row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
                   1022: 
                   1023:        if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
                   1024:                unsigned int i, field_count = result->field_count;
                   1025: 
                   1026:                if (!row_packet->skip_extraction) {
                   1027:                        result->m.unbuffered_free_last_data(result TSRMLS_CC);
                   1028: 
                   1029:                        result->unbuf->last_row_data = row_packet->fields;
                   1030:                        result->unbuf->last_row_buffer = row_packet->row_buffer;
                   1031:                        row_packet->fields = NULL;
                   1032:                        row_packet->row_buffer = NULL;
                   1033: 
                   1034:                        if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
                   1035:                                                                          result->unbuf->last_row_data,
                   1036:                                                                          row_packet->field_count,
                   1037:                                                                          row_packet->fields_metadata,
1.1.1.2 ! misho    1038:                                                                          result->conn->options->numeric_and_datetime_as_unicode,
        !          1039:                                                                          result->conn->options->int_and_float_native,
1.1       misho    1040:                                                                          result->conn->stats TSRMLS_CC))
                   1041:                        {
                   1042:                                DBG_RETURN(FAIL);                                                 
                   1043:                        }
                   1044: 
                   1045:                        /* If no result bind, do nothing. We consumed the data */
                   1046:                        for (i = 0; i < field_count; i++) {
                   1047:                                if (stmt->result_bind[i].bound == TRUE) {
                   1048:                                        zval *data = result->unbuf->last_row_data[i];
                   1049:                                        /*
                   1050:                                          stmt->result_bind[i].zv has been already destructed
                   1051:                                          in result->m.unbuffered_free_last_data()
                   1052:                                        */
                   1053: #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                   1054:                                        zval_dtor(stmt->result_bind[i].zv);
                   1055: #endif
                   1056:                                        DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, stmt->result_bind[i].zv,
                   1057:                                                                Z_TYPE_P(data), Z_REFCOUNT_P(stmt->result_bind[i].zv));
                   1058:                                        if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data))) {
                   1059:                                                if ((Z_TYPE_P(data) == IS_STRING
                   1060: #if MYSQLND_UNICODE
                   1061:                                                        || Z_TYPE_P(data) == IS_UNICODE
                   1062: #endif
                   1063:                                                        )
                   1064:                                                         && (result->meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data)))
                   1065:                                                {
                   1066:                                                        result->meta->fields[i].max_length = Z_STRLEN_P(data);
                   1067:                                                }
                   1068:                                                stmt->result_bind[i].zv->value = data->value;
                   1069:                                                /* copied data, thus also the ownership. Thus null data */
                   1070:                                                ZVAL_NULL(data);
                   1071:                                        }
                   1072:                                }
                   1073:                        }
                   1074:                } else {
                   1075:                        DBG_INF("skipping extraction");
                   1076:                        /*
                   1077:                          Data has been allocated and usually result->m.unbuffered_free_last_data()
                   1078:                          frees it but we can't call this function as it will cause problems with
                   1079:                          the bound variables. Thus we need to do part of what it does or Zend will
                   1080:                          report leaks.
                   1081:                        */
                   1082:                        row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
                   1083:                        row_packet->row_buffer = NULL;
                   1084:                }
                   1085:                /* We asked for one row, the next one should be EOF, eat it */
                   1086:                ret = PACKET_READ(row_packet, result->conn);
                   1087:                if (row_packet->row_buffer) {
                   1088:                        row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
                   1089:                        row_packet->row_buffer = NULL;
                   1090:                }
                   1091:                MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
                   1092: 
                   1093:                result->unbuf->row_count++;
                   1094:                *fetched_anything = TRUE;
                   1095:        } else {
                   1096:                *fetched_anything = FALSE;
                   1097: 
1.1.1.2 ! misho    1098:                stmt->upsert_status->warning_count =
        !          1099:                        stmt->conn->upsert_status->warning_count =
1.1       misho    1100:                                row_packet->warning_count;
                   1101: 
1.1.1.2 ! misho    1102:                stmt->upsert_status->server_status = 
        !          1103:                        stmt->conn->upsert_status->server_status =
1.1       misho    1104:                                row_packet->server_status;
                   1105: 
                   1106:                result->unbuf->eof_reached = row_packet->eof;
                   1107:        }
1.1.1.2 ! misho    1108:        stmt->upsert_status->warning_count =
        !          1109:                stmt->conn->upsert_status->warning_count =
1.1       misho    1110:                        row_packet->warning_count;
1.1.1.2 ! misho    1111:        stmt->upsert_status->server_status = 
        !          1112:                stmt->conn->upsert_status->server_status =
1.1       misho    1113:                        row_packet->server_status;
                   1114: 
                   1115:        DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u",
                   1116:                                ret == PASS? "PASS":"FAIL", *fetched_anything,
                   1117:                                row_packet->server_status, row_packet->warning_count,
                   1118:                                result->unbuf->eof_reached);
                   1119:        DBG_RETURN(ret);
                   1120: }
                   1121: /* }}} */
                   1122: 
                   1123: 
                   1124: /* {{{ mysqlnd_stmt::fetch */
                   1125: static enum_func_status
                   1126: MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fetched_anything TSRMLS_DC)
                   1127: {
                   1128:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1129:        enum_func_status ret;
                   1130:        DBG_ENTER("mysqlnd_stmt::fetch");
                   1131:        if (!stmt || !stmt->conn) {
                   1132:                DBG_RETURN(FAIL);
                   1133:        }
                   1134:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                   1135: 
                   1136:        if (!stmt->result ||
                   1137:                stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
                   1138:                SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                   1139: 
                   1140:                DBG_ERR("command out of sync");
                   1141:                DBG_RETURN(FAIL);
                   1142:        } else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
                   1143:                /* Execute only once. We have to free the previous contents of user's bound vars */
                   1144: 
                   1145:                stmt->default_rset_handler(s TSRMLS_CC);
                   1146:        }
                   1147:        stmt->state = MYSQLND_STMT_USER_FETCHING;
                   1148: 
1.1.1.2 ! misho    1149:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1150:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1151: 
                   1152:        DBG_INF_FMT("result_bind=%p separated_once=%u", stmt->result_bind, stmt->result_zvals_separated_once);
                   1153:        /*
                   1154:          The user might have not bound any variables for result.
                   1155:          Do the binding once she does it.
                   1156:        */
                   1157:        if (stmt->result_bind && !stmt->result_zvals_separated_once) {
                   1158:                unsigned int i;
                   1159:                /*
                   1160:                  mysqlnd_stmt_store_result() has been called free the bind
                   1161:                  variables to prevent leaking of their previous content.
                   1162:                */
                   1163:                for (i = 0; i < stmt->result->field_count; i++) {
                   1164:                        if (stmt->result_bind[i].bound == TRUE) {
                   1165:                                zval_dtor(stmt->result_bind[i].zv);
                   1166:                                ZVAL_NULL(stmt->result_bind[i].zv);
                   1167:                        }
                   1168:                }
                   1169:                stmt->result_zvals_separated_once = TRUE;
                   1170:        }
                   1171: 
                   1172:        ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything TSRMLS_CC);
                   1173:        DBG_RETURN(ret);
                   1174: }
                   1175: /* }}} */
                   1176: 
                   1177: 
                   1178: /* {{{ mysqlnd_stmt::reset */
                   1179: static enum_func_status
                   1180: MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s TSRMLS_DC)
                   1181: {
                   1182:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1183:        enum_func_status ret = PASS;
                   1184:        zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
                   1185: 
                   1186:        DBG_ENTER("mysqlnd_stmt::reset");
                   1187:        if (!stmt || !stmt->conn) {
                   1188:                DBG_RETURN(FAIL);
                   1189:        }
                   1190:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                   1191: 
1.1.1.2 ! misho    1192:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1193:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1194: 
                   1195:        if (stmt->stmt_id) {
1.1.1.2 ! misho    1196:                MYSQLND_CONN_DATA * conn = stmt->conn;
1.1       misho    1197:                if (stmt->param_bind) {
                   1198:                        unsigned int i;
                   1199:                        DBG_INF("resetting long data");
                   1200:                        /* Reset Long Data */
                   1201:                        for (i = 0; i < stmt->param_count; i++) {
                   1202:                                if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
                   1203:                                        stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
                   1204:                                }
                   1205:                        }
                   1206:                }
                   1207: 
1.1.1.2 ! misho    1208:                s->m->flush(s TSRMLS_CC);
        !          1209: 
        !          1210:                /*
        !          1211:                  Don't free now, let the result be usable. When the stmt will again be
        !          1212:                  executed then the result set will be cleaned, the bound variables will
        !          1213:                  be separated before that.
        !          1214:                */
        !          1215: 
        !          1216:                int4store(cmd_buf, stmt->stmt_id);
        !          1217:                if (CONN_GET_STATE(conn) == CONN_READY &&
        !          1218:                        FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, cmd_buf,
        !          1219:                                                                                                  sizeof(cmd_buf), PROT_OK_PACKET,
        !          1220:                                                                                                  FALSE, TRUE TSRMLS_CC))) {
        !          1221:                        COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
        !          1222:                }
        !          1223:                *stmt->upsert_status = *conn->upsert_status;
        !          1224: 
        !          1225:                stmt->state = MYSQLND_STMT_PREPARED;
        !          1226:        }
        !          1227:        DBG_INF(ret == PASS? "PASS":"FAIL");
        !          1228:        DBG_RETURN(ret);
        !          1229: }
        !          1230: /* }}} */
        !          1231: 
        !          1232: 
        !          1233: /* {{{ mysqlnd_stmt::flush */
        !          1234: static enum_func_status
        !          1235: MYSQLND_METHOD(mysqlnd_stmt, flush)(MYSQLND_STMT * const s TSRMLS_DC)
        !          1236: {
        !          1237:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
        !          1238:        enum_func_status ret = PASS;
        !          1239: 
        !          1240:        DBG_ENTER("mysqlnd_stmt::flush");
        !          1241:        if (!stmt || !stmt->conn) {
        !          1242:                DBG_RETURN(FAIL);
        !          1243:        }
        !          1244:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
        !          1245: 
        !          1246:        if (stmt->stmt_id) {
1.1       misho    1247:                /*
                   1248:                  If the user decided to close the statement right after execute()
                   1249:                  We have to call the appropriate use_result() or store_result() and
                   1250:                  clean.
                   1251:                */
                   1252:                do {
                   1253:                        if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
                   1254:                                DBG_INF("fetching result set header");
                   1255:                                stmt->default_rset_handler(s TSRMLS_CC);
                   1256:                                stmt->state = MYSQLND_STMT_USER_FETCHING;
                   1257:                        }
                   1258: 
                   1259:                        if (stmt->result) {
                   1260:                                DBG_INF("skipping result");
                   1261:                                stmt->result->m.skip_result(stmt->result TSRMLS_CC);
                   1262:                        }
                   1263:                } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
                   1264: 
                   1265:                stmt->state = MYSQLND_STMT_PREPARED;
                   1266:        }
                   1267:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   1268:        DBG_RETURN(ret);
                   1269: }
                   1270: /* }}} */
                   1271: 
                   1272: 
                   1273: /* {{{ mysqlnd_stmt::send_long_data */
                   1274: static enum_func_status
                   1275: MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
                   1276:                                                                                         const char * const data, unsigned long length TSRMLS_DC)
                   1277: {
                   1278:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1279:        enum_func_status ret = FAIL;
1.1.1.2 ! misho    1280:        MYSQLND_CONN_DATA * conn;
        !          1281:        zend_uchar * cmd_buf;
1.1       misho    1282:        enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
                   1283: 
                   1284:        DBG_ENTER("mysqlnd_stmt::send_long_data");
                   1285:        if (!stmt || !stmt->conn) {
                   1286:                DBG_RETURN(FAIL);
                   1287:        }
                   1288:        DBG_INF_FMT("stmt=%lu param_no=%u data_len=%lu", stmt->stmt_id, param_no, length);
                   1289: 
                   1290:        conn = stmt->conn;
                   1291: 
1.1.1.2 ! misho    1292:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1293:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1294: 
                   1295:        if (stmt->state < MYSQLND_STMT_PREPARED) {
                   1296:                SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
                   1297:                DBG_ERR("not prepared");
                   1298:                DBG_RETURN(FAIL);
                   1299:        }
                   1300:        if (!stmt->param_bind) {
                   1301:                SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                   1302:                DBG_ERR("command out of sync");
                   1303:                DBG_RETURN(FAIL);
                   1304:        }
                   1305:        if (param_no >= stmt->param_count) {
                   1306:                SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
                   1307:                DBG_ERR("invalid param_no");
                   1308:                DBG_RETURN(FAIL);
                   1309:        }
                   1310:        if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {
                   1311:                SET_STMT_ERROR(stmt, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, mysqlnd_not_bound_as_blob);
                   1312:                DBG_ERR("param_no is not of a blob type");
                   1313:                DBG_RETURN(FAIL);
                   1314:        }
                   1315: 
                   1316:        /*
                   1317:          XXX:  Unfortunately we have to allocate additional buffer to be able the
                   1318:                        additional data, which is like a header inside the payload.
                   1319:                        This should be optimised, but it will be a pervasive change, so
                   1320:                        conn->m->simple_command() will accept not a buffer, but actually MYSQLND_STRING*
                   1321:                        terminated by NULL, to send. If the strings are not big, we can collapse them
                   1322:                        on the buffer every connection has, but otherwise we will just send them
                   1323:                        one by one to the wire.
                   1324:        */
                   1325: 
                   1326:        if (CONN_GET_STATE(conn) == CONN_READY) {
                   1327:                size_t packet_len;
                   1328:                cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
                   1329:                if (cmd_buf) {
                   1330:                        stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
                   1331: 
                   1332:                        int4store(cmd_buf, stmt->stmt_id);
                   1333:                        int2store(cmd_buf + STMT_ID_LENGTH, param_no);
                   1334:                        memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length);
                   1335: 
                   1336:                        /* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/
1.1.1.2 ! misho    1337:                        ret = conn->m->simple_command(conn, cmd, cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC);
1.1       misho    1338:                        mnd_efree(cmd_buf);
                   1339:                        if (FAIL == ret) {
1.1.1.2 ! misho    1340:                                COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
1.1       misho    1341:                        }
                   1342:                } else {
                   1343:                        ret = FAIL;
1.1.1.2 ! misho    1344:                        SET_OOM_ERROR(*stmt->error_info);
        !          1345:                        SET_OOM_ERROR(*conn->error_info);
1.1       misho    1346:                }
                   1347:                /*
                   1348:                  Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not
                   1349:                  sent response packets. According to documentation the only way to get an error
                   1350:                  is to have out-of-memory on the server-side. However, that's not true, as if
                   1351:                  max_allowed_packet_size is smaller than the chunk being sent to the server, the
                   1352:                  latter will complain with an error message. However, normally we don't expect
                   1353:                  an error message, thus we continue. When sending the next command, which expects
                   1354:                  response we will read the unexpected data and error message will look weird.
                   1355:                  Therefore we do non-blocking read to clean the line, if there is a need.
                   1356:                  Nevertheless, there is a built-in protection when sending a command packet, that
                   1357:                  checks if the line is clear - useful for debug purposes and to be switched off
                   1358:                  in release builds.
                   1359: 
                   1360:                  Maybe we can make it automatic by checking what's the value of
                   1361:                  max_allowed_packet_size on the server and resending the data.
                   1362:                */
                   1363: #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
                   1364: #if HAVE_USLEEP && !defined(PHP_WIN32)
                   1365:                usleep(120000);
                   1366: #endif
                   1367:                if ((packet_len = conn->net->m.consume_uneaten_data(conn->net, cmd TSRMLS_CC))) {
                   1368:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error "
                   1369:                                                         "while sending long data. Probably max_allowed_packet_size "
                   1370:                                                         "is smaller than the data. You have to increase it or send "
                   1371:                                                         "smaller chunks of data. Answer was "MYSQLND_SZ_T_SPEC" bytes long.", packet_len);
                   1372:                        SET_STMT_ERROR(stmt, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE,
                   1373:                                                        "Server responded to COM_STMT_SEND_LONG_DATA.");
                   1374:                        ret = FAIL;
                   1375:                }
                   1376: #endif
                   1377:        }
                   1378: 
                   1379:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   1380:        DBG_RETURN(ret);
                   1381: }
                   1382: /* }}} */
                   1383: 
                   1384: 
                   1385: /* {{{ mysqlnd_stmt::bind_parameters */
                   1386: static enum_func_status
                   1387: MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
                   1388: {
                   1389:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1390:        DBG_ENTER("mysqlnd_stmt::bind_param");
                   1391:        if (!stmt || !stmt->conn) {
                   1392:                DBG_RETURN(FAIL);
                   1393:        }
                   1394:        DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
                   1395: 
                   1396:        if (stmt->state < MYSQLND_STMT_PREPARED) {
                   1397:                SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
                   1398:                DBG_ERR("not prepared");
                   1399:                if (param_bind) {
                   1400:                        s->m->free_parameter_bind(s, param_bind TSRMLS_CC);
                   1401:                }
                   1402:                DBG_RETURN(FAIL);
                   1403:        }
                   1404: 
1.1.1.2 ! misho    1405:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1406:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1407: 
                   1408:        if (stmt->param_count) {
                   1409:                unsigned int i = 0;
                   1410: 
                   1411:                if (!param_bind) {
                   1412:                        SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported");
                   1413:                        DBG_ERR("Re-binding (still) not supported");
                   1414:                        DBG_RETURN(FAIL);
                   1415:                } else if (stmt->param_bind) {
                   1416:                        DBG_INF("Binding");
                   1417:                        /*
                   1418:                          There is already result bound.
                   1419:                          Forbid for now re-binding!!
                   1420:                        */
                   1421:                        for (i = 0; i < stmt->param_count; i++) {
                   1422:                                /*
1.1.1.2 ! misho    1423:                                  We may have the last reference, then call zval_ptr_dtor() or we may leak memory.
1.1       misho    1424:                                  Switching from bind_one_parameter to bind_parameters may result in zv being NULL
                   1425:                                */
                   1426:                                if (stmt->param_bind[i].zv) {
                   1427:                                        zval_ptr_dtor(&stmt->param_bind[i].zv);
                   1428:                                }
                   1429:                        }
                   1430:                        if (stmt->param_bind != param_bind) {
                   1431:                                s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
                   1432:                        }
                   1433:                }
                   1434: 
                   1435:                stmt->param_bind = param_bind;
                   1436:                for (i = 0; i < stmt->param_count; i++) {
                   1437:                        /* The client will use stmt_send_long_data */
                   1438:                        DBG_INF_FMT("%u is of type %u", i, stmt->param_bind[i].type);
                   1439:                        /* Prevent from freeing */
                   1440:                        /* Don't update is_ref, or we will leak during conversion */
                   1441:                        Z_ADDREF_P(stmt->param_bind[i].zv);
                   1442:                        stmt->param_bind[i].flags = 0;
                   1443:                        if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
                   1444:                                stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
                   1445:                        }
                   1446:                }
                   1447:                stmt->send_types_to_server = 1;
                   1448:        }
                   1449:        DBG_INF("PASS");
                   1450:        DBG_RETURN(PASS);
                   1451: }
                   1452: /* }}} */
                   1453: 
                   1454: 
                   1455: /* {{{ mysqlnd_stmt::bind_one_parameter */
                   1456: static enum_func_status
                   1457: MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigned int param_no,
                   1458:                                                                                                 zval * const zv, zend_uchar type TSRMLS_DC)
                   1459: {
                   1460:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1461:        DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
                   1462:        if (!stmt || !stmt->conn) {
                   1463:                DBG_RETURN(FAIL);
                   1464:        }
1.1.1.2 ! misho    1465:        DBG_INF_FMT("stmt=%lu param_no=%u param_count=%u type=%u", stmt->stmt_id, param_no, stmt->param_count, type);
1.1       misho    1466: 
                   1467:        if (stmt->state < MYSQLND_STMT_PREPARED) {
                   1468:                SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
                   1469:                DBG_ERR("not prepared");
                   1470:                DBG_RETURN(FAIL);
                   1471:        }
                   1472: 
                   1473:        if (param_no >= stmt->param_count) {
                   1474:                SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
                   1475:                DBG_ERR("invalid param_no");
                   1476:                DBG_RETURN(FAIL);
                   1477:        }
1.1.1.2 ! misho    1478:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1479:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1480: 
                   1481:        if (stmt->param_count) {
                   1482:                if (!stmt->param_bind) {
                   1483:                        stmt->param_bind = mnd_ecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND));
                   1484:                        if (!stmt->param_bind) {
                   1485:                                DBG_RETURN(FAIL);
                   1486:                        }
                   1487:                }
                   1488: 
                   1489:                /* Prevent from freeing */
                   1490:                /* Don't update is_ref, or we will leak during conversion */
                   1491:                Z_ADDREF_P(zv);
                   1492:                DBG_INF("Binding");
                   1493:                /* Release what we had, if we had */
                   1494:                if (stmt->param_bind[param_no].zv) {
                   1495:                        zval_ptr_dtor(&stmt->param_bind[param_no].zv);
                   1496:                }
                   1497:                if (type == MYSQL_TYPE_LONG_BLOB) {
                   1498:                        /* The client will use stmt_send_long_data */
                   1499:                        stmt->param_bind[param_no].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
                   1500:                }
                   1501:                stmt->param_bind[param_no].zv = zv;
                   1502:                stmt->param_bind[param_no].type = type;
                   1503: 
                   1504:                stmt->send_types_to_server = 1;
                   1505:        }
                   1506:        DBG_INF("PASS");
                   1507:        DBG_RETURN(PASS);
                   1508: }
                   1509: /* }}} */
                   1510: 
                   1511: 
                   1512: /* {{{ mysqlnd_stmt::refresh_bind_param */
                   1513: static enum_func_status
                   1514: MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const s TSRMLS_DC)
                   1515: {
                   1516:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1517:        DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
                   1518:        if (!stmt || !stmt->conn) {
                   1519:                DBG_RETURN(FAIL);
                   1520:        }
                   1521:        DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
                   1522: 
                   1523:        if (stmt->state < MYSQLND_STMT_PREPARED) {
                   1524:                SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
                   1525:                DBG_ERR("not prepared");
                   1526:                DBG_RETURN(FAIL);
                   1527:        }
                   1528: 
1.1.1.2 ! misho    1529:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1530:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1531: 
                   1532:        if (stmt->param_count) {
                   1533:                stmt->send_types_to_server = 1;
                   1534:        }
                   1535:        DBG_RETURN(PASS);
                   1536: }
                   1537: /* }}} */
                   1538: 
                   1539: 
                   1540: /* {{{ mysqlnd_stmt::bind_result */
                   1541: static enum_func_status
                   1542: MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
                   1543:                                                                                  MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC)
                   1544: {
                   1545:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1546:        DBG_ENTER("mysqlnd_stmt::bind_result");
                   1547:        if (!stmt || !stmt->conn) {
                   1548:                DBG_RETURN(FAIL);
                   1549:        }
                   1550:        DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
                   1551: 
                   1552:        if (stmt->state < MYSQLND_STMT_PREPARED) {
                   1553:                SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
                   1554:                if (result_bind) {
                   1555:                        s->m->free_result_bind(s, result_bind TSRMLS_CC);
                   1556:                }
                   1557:                DBG_ERR("not prepared");
                   1558:                DBG_RETURN(FAIL);
                   1559:        }
                   1560: 
1.1.1.2 ! misho    1561:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1562:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1563: 
                   1564:        if (stmt->field_count) {
                   1565:                unsigned int i = 0;
                   1566: 
                   1567:                if (!result_bind) {
                   1568:                        DBG_ERR("no result bind passed");
                   1569:                        DBG_RETURN(FAIL);
                   1570:                }
                   1571: 
                   1572:                mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
                   1573:                stmt->result_zvals_separated_once = FALSE;
                   1574:                stmt->result_bind = result_bind;
                   1575:                for (i = 0; i < stmt->field_count; i++) {
                   1576:                        /* Prevent from freeing */
                   1577:                        Z_ADDREF_P(stmt->result_bind[i].zv);
                   1578:                        DBG_INF_FMT("ref of %p = %u", stmt->result_bind[i].zv, Z_REFCOUNT_P(stmt->result_bind[i].zv));
                   1579:                        /*
                   1580:                          Don't update is_ref !!! it's not our job
                   1581:                          Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
                   1582:                          will fail.
                   1583:                        */
                   1584:                        stmt->result_bind[i].bound = TRUE;
                   1585:                }
                   1586:        } else if (result_bind) {
                   1587:                s->m->free_result_bind(s, result_bind TSRMLS_CC);
                   1588:        }
                   1589:        DBG_INF("PASS");
                   1590:        DBG_RETURN(PASS);
                   1591: }
                   1592: /* }}} */
                   1593: 
                   1594: 
                   1595: /* {{{ mysqlnd_stmt::bind_result */
                   1596: static enum_func_status
                   1597: MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
                   1598: {
                   1599:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1600:        DBG_ENTER("mysqlnd_stmt::bind_result");
                   1601:        if (!stmt || !stmt->conn) {
                   1602:                DBG_RETURN(FAIL);
                   1603:        }
                   1604:        DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
                   1605: 
                   1606:        if (stmt->state < MYSQLND_STMT_PREPARED) {
                   1607:                SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
                   1608:                DBG_ERR("not prepared");
                   1609:                DBG_RETURN(FAIL);
                   1610:        }
                   1611: 
                   1612:        if (param_no >= stmt->field_count) {
                   1613:                SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
                   1614:                DBG_ERR("invalid param_no");
                   1615:                DBG_RETURN(FAIL);
                   1616:        }
                   1617: 
1.1.1.2 ! misho    1618:        SET_EMPTY_ERROR(*stmt->error_info);
        !          1619:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    1620: 
                   1621:        if (stmt->field_count) {
                   1622:                mysqlnd_stmt_separate_one_result_bind(s, param_no TSRMLS_CC);
                   1623:                /* Guaranteed is that stmt->result_bind is NULL */
                   1624:                if (!stmt->result_bind) {
                   1625:                        stmt->result_bind = mnd_ecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND));
                   1626:                } else {
                   1627:                        stmt->result_bind = mnd_erealloc(stmt->result_bind, stmt->field_count * sizeof(MYSQLND_RESULT_BIND));
                   1628:                }
                   1629:                if (!stmt->result_bind) {
                   1630:                        DBG_RETURN(FAIL);
                   1631:                }
                   1632:                ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
                   1633:                /*
                   1634:                  Don't update is_ref !!! it's not our job
                   1635:                  Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
                   1636:                  will fail.
                   1637:                */
                   1638:                stmt->result_bind[param_no].bound = TRUE;
                   1639:        }
                   1640:        DBG_INF("PASS");
                   1641:        DBG_RETURN(PASS);
                   1642: }
                   1643: /* }}} */
                   1644: 
                   1645: 
                   1646: /* {{{ mysqlnd_stmt::insert_id */
                   1647: static uint64_t
                   1648: MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1649: {
                   1650:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1651:        return stmt? stmt->upsert_status->last_insert_id : 0;
1.1       misho    1652: }
                   1653: /* }}} */
                   1654: 
                   1655: 
                   1656: /* {{{ mysqlnd_stmt::affected_rows */
                   1657: static uint64_t
                   1658: MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1659: {
                   1660:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1661:        return stmt? stmt->upsert_status->affected_rows : 0;
1.1       misho    1662: }
                   1663: /* }}} */
                   1664: 
                   1665: 
                   1666: /* {{{ mysqlnd_stmt::num_rows */
                   1667: static uint64_t
                   1668: MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1669: {
                   1670:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1671:        return stmt && stmt->result? mysqlnd_num_rows(stmt->result):0;
                   1672: }
                   1673: /* }}} */
                   1674: 
                   1675: 
                   1676: /* {{{ mysqlnd_stmt::warning_count */
                   1677: static unsigned int
                   1678: MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1679: {
                   1680:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1681:        return stmt? stmt->upsert_status->warning_count : 0;
1.1       misho    1682: }
                   1683: /* }}} */
                   1684: 
                   1685: 
                   1686: /* {{{ mysqlnd_stmt::server_status */
                   1687: static unsigned int
                   1688: MYSQLND_METHOD(mysqlnd_stmt, server_status)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1689: {
                   1690:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1691:        return stmt? stmt->upsert_status->server_status : 0;
1.1       misho    1692: }
                   1693: /* }}} */
                   1694: 
                   1695: 
                   1696: /* {{{ mysqlnd_stmt::field_count */
                   1697: static unsigned int
                   1698: MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1699: {
                   1700:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1701:        return stmt? stmt->field_count : 0;
                   1702: }
                   1703: /* }}} */
                   1704: 
                   1705: 
                   1706: /* {{{ mysqlnd_stmt::param_count */
                   1707: static unsigned int
                   1708: MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1709: {
                   1710:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1711:        return stmt? stmt->param_count : 0;
                   1712: }
                   1713: /* }}} */
                   1714: 
                   1715: 
                   1716: /* {{{ mysqlnd_stmt::errno */
                   1717: static unsigned int
                   1718: MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1719: {
                   1720:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1721:        return stmt? stmt->error_info->error_no : 0;
1.1       misho    1722: }
                   1723: /* }}} */
                   1724: 
                   1725: 
                   1726: /* {{{ mysqlnd_stmt::error */
                   1727: static const char *
                   1728: MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1729: {
                   1730:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1731:        return stmt? stmt->error_info->error : 0;
1.1       misho    1732: }
                   1733: /* }}} */
                   1734: 
                   1735: 
                   1736: /* {{{ mysqlnd_stmt::sqlstate */
                   1737: static const char *
                   1738: MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s TSRMLS_DC)
                   1739: {
                   1740:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    1741:        return stmt && stmt->error_info->sqlstate[0] ? stmt->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
1.1       misho    1742: }
                   1743: /* }}} */
                   1744: 
                   1745: 
                   1746: /* {{{ mysqlnd_stmt::data_seek */
                   1747: static enum_func_status
                   1748: MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const s, uint64_t row TSRMLS_DC)
                   1749: {
                   1750:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1751:        return stmt && stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
                   1752: }
                   1753: /* }}} */
                   1754: 
                   1755: 
                   1756: /* {{{ mysqlnd_stmt::param_metadata */
                   1757: static MYSQLND_RES *
                   1758: MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
                   1759: {
                   1760:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1761:        if (!stmt || !stmt->param_count) {
                   1762:                return NULL;
                   1763:        }
                   1764:        return NULL;
                   1765: }
                   1766: /* }}} */
                   1767: 
                   1768: 
                   1769: /* {{{ mysqlnd_stmt::result_metadata */
                   1770: static MYSQLND_RES *
                   1771: MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
                   1772: {
                   1773:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1774:        MYSQLND_RES *result;
                   1775: 
                   1776:        DBG_ENTER("mysqlnd_stmt::result_metadata");
                   1777:        if (!stmt) {
                   1778:                DBG_RETURN(NULL);
                   1779:        }
                   1780:        DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
                   1781: 
                   1782:        if (!stmt->field_count || !stmt->conn || !stmt->result || !stmt->result->meta) {
                   1783:                DBG_INF("NULL");
                   1784:                DBG_RETURN(NULL);
                   1785:        }
                   1786: 
                   1787:        if (stmt->update_max_length && stmt->result->stored_data) {
                   1788:                /* stored result, we have to update the max_length before we clone the meta data :( */
                   1789:                stmt->result->m.initialize_result_set_rest(stmt->result TSRMLS_CC);
                   1790:        }
                   1791:        /*
                   1792:          TODO: This implementation is kind of a hack,
                   1793:                        find a better way to do it. In different functions I have put
                   1794:                        fuses to check for result->m.fetch_row() being NULL. This should
                   1795:                        be handled in a better way.
                   1796: 
                   1797:          In the meantime we don't need a zval cache reference for this fake
                   1798:          result set, so we don't get one.
                   1799:        */
                   1800:        do {
                   1801:                result = stmt->conn->m->result_init(stmt->field_count, stmt->persistent TSRMLS_CC);
                   1802:                if (!result) {
                   1803:                        break;
                   1804:                }
                   1805:                result->type = MYSQLND_RES_NORMAL;
                   1806:                result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
                   1807:                result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
                   1808:                if (!result->unbuf) {
                   1809:                        break;
                   1810:                }
                   1811:                result->unbuf->eof_reached = TRUE;
                   1812:                result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
                   1813:                if (!result->meta) {
                   1814:                        break;
                   1815:                }
                   1816: 
                   1817:                DBG_INF_FMT("result=%p", result);
                   1818:                DBG_RETURN(result);
                   1819:        } while (0);
                   1820: 
1.1.1.2 ! misho    1821:        SET_OOM_ERROR(*stmt->conn->error_info);
1.1       misho    1822:        if (result) {
                   1823:                result->m.free_result(result, TRUE TSRMLS_CC);
                   1824:        }
                   1825:        DBG_RETURN(NULL);
                   1826: }
                   1827: /* }}} */
                   1828: 
                   1829: 
                   1830: /* {{{ mysqlnd_stmt::attr_set */
                   1831: static enum_func_status
                   1832: MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
                   1833:                                                                           enum mysqlnd_stmt_attr attr_type,
                   1834:                                                                           const void * const value TSRMLS_DC)
                   1835: {
                   1836:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1837:        DBG_ENTER("mysqlnd_stmt::attr_set");
                   1838:        if (!stmt) {
                   1839:                DBG_RETURN(FAIL);
                   1840:        }
                   1841:        DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
                   1842: 
                   1843:        switch (attr_type) {
                   1844:                case STMT_ATTR_UPDATE_MAX_LENGTH:{
                   1845:                        zend_uchar bval = *(zend_uchar *) value;
                   1846:                        /*
                   1847:                          XXX : libmysql uses my_bool, but mysqli uses ulong as storage on the stack
                   1848:                          and mysqlnd won't be used out of the scope of PHP -> use ulong.
                   1849:                        */
                   1850:                        stmt->update_max_length = bval? TRUE:FALSE;
                   1851:                        break;
                   1852:                }
                   1853:                case STMT_ATTR_CURSOR_TYPE: {
                   1854:                        unsigned int ival = *(unsigned int *) value;
                   1855:                        if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) {
                   1856:                                SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
                   1857:                                DBG_INF("FAIL");
                   1858:                                DBG_RETURN(FAIL);
                   1859:                        }
                   1860:                        stmt->flags = ival;
                   1861:                        break;
                   1862:                }
                   1863:                case STMT_ATTR_PREFETCH_ROWS: {
                   1864:                        unsigned int ival = *(unsigned int *) value;
                   1865:                        if (ival == 0) {
                   1866:                                ival = MYSQLND_DEFAULT_PREFETCH_ROWS;
                   1867:                        } else if (ival > 1) {
                   1868:                                SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
                   1869:                                DBG_INF("FAIL");
                   1870:                                DBG_RETURN(FAIL);
                   1871:                        }
                   1872:                        stmt->prefetch_rows = ival;
                   1873:                        break;
                   1874:                }
                   1875:                default:
                   1876:                        SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
                   1877:                        DBG_RETURN(FAIL);
                   1878:        }
                   1879:        DBG_INF("PASS");
                   1880:        DBG_RETURN(PASS);
                   1881: }
                   1882: /* }}} */
                   1883: 
                   1884: 
                   1885: /* {{{ mysqlnd_stmt::attr_get */
                   1886: static enum_func_status
                   1887: MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
                   1888:                                                                           enum mysqlnd_stmt_attr attr_type,
                   1889:                                                                           void * const value TSRMLS_DC)
                   1890: {
                   1891:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1892:        DBG_ENTER("mysqlnd_stmt::attr_set");
                   1893:        if (!stmt) {
                   1894:                DBG_RETURN(FAIL);
                   1895:        }
                   1896:        DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
                   1897: 
                   1898:        switch (attr_type) {
                   1899:                case STMT_ATTR_UPDATE_MAX_LENGTH:
                   1900:                        *(zend_bool *) value= stmt->update_max_length;
                   1901:                        break;
                   1902:                case STMT_ATTR_CURSOR_TYPE:
                   1903:                        *(unsigned long *) value= stmt->flags;
                   1904:                        break;
                   1905:                case STMT_ATTR_PREFETCH_ROWS:
                   1906:                        *(unsigned long *) value= stmt->prefetch_rows;
                   1907:                        break;
                   1908:                default:
                   1909:                        DBG_RETURN(FAIL);
                   1910:        }
                   1911:        DBG_INF_FMT("value=%lu", value);
                   1912:        DBG_RETURN(PASS);
                   1913: }
                   1914: /* }}} */
                   1915: 
1.1.1.2 ! misho    1916: 
1.1       misho    1917: /* free_result() doesn't actually free stmt->result but only the buffers */
                   1918: /* {{{ mysqlnd_stmt::free_result */
                   1919: static enum_func_status
                   1920: MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s TSRMLS_DC)
                   1921: {
                   1922:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1923:        DBG_ENTER("mysqlnd_stmt::free_result");
                   1924:        if (!stmt || !stmt->conn) {
                   1925:                DBG_RETURN(FAIL);
                   1926:        }
                   1927:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                   1928: 
                   1929:        if (!stmt->result) {
                   1930:                DBG_INF("no result");
                   1931:                DBG_RETURN(PASS);
                   1932:        }
                   1933: 
                   1934:        /*
                   1935:          If right after execute() we have to call the appropriate
                   1936:          use_result() or store_result() and clean.
                   1937:        */
                   1938:        if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
                   1939:                DBG_INF("fetching result set header");
                   1940:                /* Do implicit use_result and then flush the result */
                   1941:                stmt->default_rset_handler = s->m->use_result;
                   1942:                stmt->default_rset_handler(s TSRMLS_CC);
                   1943:        }
                   1944: 
                   1945:        if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
                   1946:                DBG_INF("skipping result");
                   1947:                /* Flush if anything is left and unbuffered set */
                   1948:                stmt->result->m.skip_result(stmt->result TSRMLS_CC);
                   1949:                /*
                   1950:                  Separate the bound variables, which point to the result set, then
                   1951:                  destroy the set.
                   1952:                */
                   1953:                mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
                   1954: 
                   1955:                /* Now we can destroy the result set */
                   1956:                stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
                   1957:        }
                   1958: 
                   1959:        if (stmt->state > MYSQLND_STMT_PREPARED) {
                   1960:                /* As the buffers have been freed, we should go back to PREPARED */
                   1961:                stmt->state = MYSQLND_STMT_PREPARED;
                   1962:        }
                   1963: 
                   1964:        /* Line is free! */
                   1965:        CONN_SET_STATE(stmt->conn, CONN_READY);
                   1966: 
                   1967:        DBG_RETURN(PASS);
                   1968: }
                   1969: /* }}} */
                   1970: 
                   1971: 
                   1972: /* {{{ mysqlnd_stmt_separate_result_bind */
                   1973: static void
                   1974: mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC)
                   1975: {
                   1976:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   1977:        unsigned int i;
                   1978: 
                   1979:        DBG_ENTER("mysqlnd_stmt_separate_result_bind");
                   1980:        if (!stmt) {
                   1981:                DBG_VOID_RETURN;
                   1982:        }
1.1.1.2 ! misho    1983:        DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count);
1.1       misho    1984: 
                   1985:        if (!stmt->result_bind) {
                   1986:                DBG_VOID_RETURN;
                   1987:        }
                   1988: 
                   1989:        /*
                   1990:          Because only the bound variables can point to our internal buffers, then
                   1991:          separate or free only them. Free is possible because the user could have
                   1992:          lost reference.
                   1993:        */
                   1994:        for (i = 0; i < stmt->field_count; i++) {
                   1995:                /* Let's try with no cache */
                   1996:                if (stmt->result_bind[i].bound == TRUE) {
                   1997:                        DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNT_P(stmt->result_bind[i].zv));
                   1998:                        /*
                   1999:                          We have to separate the actual zval value of the bound
                   2000:                          variable from our allocated zvals or we will face double-free
                   2001:                        */
                   2002:                        if (Z_REFCOUNT_P(stmt->result_bind[i].zv) > 1) {
                   2003: #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                   2004:                                zval_copy_ctor(stmt->result_bind[i].zv);
                   2005: #endif
                   2006:                                zval_ptr_dtor(&stmt->result_bind[i].zv);
                   2007:                        } else {
                   2008:                                /*
                   2009:                                  If it is a string, what is pointed will be freed
                   2010:                                  later in free_result(). We need to remove the variable to
                   2011:                                  which the user has lost reference.
                   2012:                                */
                   2013: #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                   2014:                                ZVAL_NULL(stmt->result_bind[i].zv);
                   2015: #endif
                   2016:                                zval_ptr_dtor(&stmt->result_bind[i].zv);
                   2017:                        }
                   2018:                }
                   2019:        }
                   2020:        s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC);
                   2021:        stmt->result_bind = NULL;
                   2022: 
                   2023:        DBG_VOID_RETURN;
                   2024: }
                   2025: /* }}} */
                   2026: 
                   2027: 
                   2028: /* {{{ mysqlnd_stmt_separate_one_result_bind */
                   2029: static void
                   2030: mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
                   2031: {
                   2032:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   2033:        DBG_ENTER("mysqlnd_stmt_separate_one_result_bind");
                   2034:        if (!stmt) {
                   2035:                DBG_VOID_RETURN;
                   2036:        }
1.1.1.2 ! misho    2037:        DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no);
1.1       misho    2038: 
                   2039:        if (!stmt->result_bind) {
                   2040:                DBG_VOID_RETURN;
                   2041:        }
                   2042: 
                   2043:        /*
                   2044:          Because only the bound variables can point to our internal buffers, then
                   2045:          separate or free only them. Free is possible because the user could have
                   2046:          lost reference.
                   2047:        */
                   2048:        /* Let's try with no cache */
                   2049:        if (stmt->result_bind[param_no].bound == TRUE) {
                   2050:                DBG_INF_FMT("%u has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
                   2051:                /*
                   2052:                  We have to separate the actual zval value of the bound
                   2053:                  variable from our allocated zvals or we will face double-free
                   2054:                */
                   2055:                if (Z_REFCOUNT_P(stmt->result_bind[param_no].zv) > 1) {
                   2056: #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                   2057:                        zval_copy_ctor(stmt->result_bind[param_no].zv);
                   2058: #endif
                   2059:                        zval_ptr_dtor(&stmt->result_bind[param_no].zv);
                   2060:                } else {
                   2061:                        /*
                   2062:                          If it is a string, what is pointed will be freed
                   2063:                          later in free_result(). We need to remove the variable to
                   2064:                          which the user has lost reference.
                   2065:                        */
                   2066: #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
                   2067:                        ZVAL_NULL(stmt->result_bind[param_no].zv);
                   2068: #endif
                   2069:                        zval_ptr_dtor(&stmt->result_bind[param_no].zv);
                   2070:                }
                   2071:        }
                   2072: 
                   2073:        DBG_VOID_RETURN;
                   2074: }
                   2075: /* }}} */
                   2076: 
                   2077: 
                   2078: /* {{{ mysqlnd_stmt::free_stmt_content */
                   2079: static void
                   2080: MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC)
                   2081: {
                   2082:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   2083:        DBG_ENTER("mysqlnd_stmt::free_stmt_content");
                   2084:        if (!stmt) {
                   2085:                DBG_VOID_RETURN;
                   2086:        }
1.1.1.2 ! misho    2087:        DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u", stmt->stmt_id, stmt->param_bind, stmt->param_count);
1.1       misho    2088: 
                   2089:        /* Destroy the input bind */
                   2090:        if (stmt->param_bind) {
                   2091:                unsigned int i;
                   2092:                /*
                   2093:                  Because only the bound variables can point to our internal buffers, then
                   2094:                  separate or free only them. Free is possible because the user could have
                   2095:                  lost reference.
                   2096:                */
                   2097:                for (i = 0; i < stmt->param_count; i++) {
                   2098:                        /*
                   2099:                          If bind_one_parameter was used, but not everything was
                   2100:                          bound and nothing was fetched, then some `zv` could be NULL
                   2101:                        */
                   2102:                        if (stmt->param_bind[i].zv) {
                   2103:                                zval_ptr_dtor(&stmt->param_bind[i].zv);
                   2104:                        }
                   2105:                }
                   2106:                s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
                   2107:                stmt->param_bind = NULL;
                   2108:        }
                   2109: 
                   2110:        /*
                   2111:          First separate the bound variables, which point to the result set, then
                   2112:          destroy the set.
                   2113:        */
                   2114:        mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
                   2115:        /* Not every statement has a result set attached */
                   2116:        if (stmt->result) {
                   2117:                stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
                   2118:                stmt->result = NULL;
                   2119:        }
1.1.1.2 ! misho    2120:        if (stmt->error_info->error_list) {
        !          2121:                zend_llist_clean(stmt->error_info->error_list);
        !          2122:                mnd_pefree(stmt->error_info->error_list, s->persistent);
        !          2123:                stmt->error_info->error_list = NULL;
        !          2124:        }
1.1       misho    2125: 
                   2126:        DBG_VOID_RETURN;
                   2127: }
                   2128: /* }}} */
                   2129: 
                   2130: 
                   2131: /* {{{ mysqlnd_stmt::net_close */
                   2132: static enum_func_status
                   2133: MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
                   2134: {
                   2135:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1.1.1.2 ! misho    2136:        MYSQLND_CONN_DATA * conn;
1.1       misho    2137:        zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
                   2138:        enum_mysqlnd_collected_stats statistic = STAT_LAST;
                   2139: 
                   2140:        DBG_ENTER("mysqlnd_stmt::net_close");
                   2141:        if (!stmt || !stmt->conn) {
                   2142:                DBG_RETURN(FAIL);
                   2143:        }
                   2144:        DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
                   2145: 
                   2146:        conn = stmt->conn;
                   2147: 
1.1.1.2 ! misho    2148:        SET_EMPTY_ERROR(*stmt->error_info);
        !          2149:        SET_EMPTY_ERROR(*stmt->conn->error_info);
1.1       misho    2150: 
                   2151:        /*
                   2152:          If the user decided to close the statement right after execute()
                   2153:          We have to call the appropriate use_result() or store_result() and
                   2154:          clean.
                   2155:        */
                   2156:        do {
                   2157:                if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
                   2158:                        DBG_INF("fetching result set header");
                   2159:                        stmt->default_rset_handler(s TSRMLS_CC);
                   2160:                        stmt->state = MYSQLND_STMT_USER_FETCHING;
                   2161:                }
                   2162: 
                   2163:                /* unbuffered set not fetched to the end ? Clean the line */
                   2164:                if (stmt->result) {
                   2165:                        DBG_INF("skipping result");
                   2166:                        stmt->result->m.skip_result(stmt->result TSRMLS_CC);
                   2167:                }
                   2168:        } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
                   2169:        /*
                   2170:          After this point we are allowed to free the result set,
                   2171:          as we have cleaned the line
                   2172:        */
                   2173:        if (stmt->stmt_id) {
                   2174:                MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE?  STAT_FREE_RESULT_IMPLICIT:
                   2175:                                                                                                                STAT_FREE_RESULT_EXPLICIT);
                   2176: 
                   2177:                int4store(cmd_buf, stmt->stmt_id);
                   2178:                if (CONN_GET_STATE(conn) == CONN_READY &&
1.1.1.2 ! misho    2179:                        FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf),
1.1       misho    2180:                                                                                   PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
                   2181:                                                                                   FALSE, TRUE TSRMLS_CC)) {
1.1.1.2 ! misho    2182:                        COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
1.1       misho    2183:                        DBG_RETURN(FAIL);
                   2184:                }
                   2185:        }
                   2186:        switch (stmt->execute_count) {
                   2187:                case 0:
                   2188:                        statistic = STAT_PS_PREPARED_NEVER_EXECUTED;
                   2189:                        break;
                   2190:                case 1:
                   2191:                        statistic = STAT_PS_PREPARED_ONCE_USED;
                   2192:                        break;
                   2193:                default:
                   2194:                        break;
                   2195:        }
                   2196:        if (statistic != STAT_LAST) {
                   2197:                MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
                   2198:        }
                   2199: 
                   2200:        if (stmt->execute_cmd_buffer.buffer) {
                   2201:                mnd_pefree(stmt->execute_cmd_buffer.buffer, stmt->persistent);
                   2202:                stmt->execute_cmd_buffer.buffer = NULL;
                   2203:        }
                   2204: 
                   2205:        s->m->free_stmt_content(s TSRMLS_CC);
                   2206: 
                   2207:        if (stmt->conn) {
                   2208:                stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
                   2209:                stmt->conn = NULL;
                   2210:        }
                   2211: 
                   2212:        DBG_RETURN(PASS);
                   2213: }
                   2214: /* }}} */
                   2215: 
                   2216: /* {{{ mysqlnd_stmt::dtor */
                   2217: static enum_func_status
                   2218: MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
                   2219: {
                   2220:        MYSQLND_STMT_DATA * stmt = (s != NULL) ? s->data:NULL;
                   2221:        enum_func_status ret = FAIL;
                   2222:        zend_bool persistent = (s != NULL) ? s->persistent : 0;
                   2223: 
                   2224:        DBG_ENTER("mysqlnd_stmt::dtor");
                   2225:        if (stmt) {
                   2226:                DBG_INF_FMT("stmt=%p", stmt);
                   2227: 
                   2228:                MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE?  STAT_STMT_CLOSE_IMPLICIT:
                   2229:                                                                                                                STAT_STMT_CLOSE_EXPLICIT);
                   2230: 
                   2231:                ret = s->m->net_close(s, implicit TSRMLS_CC);
                   2232:                mnd_pefree(stmt, persistent);
                   2233:        }
                   2234:        mnd_pefree(s, persistent);
                   2235: 
                   2236:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   2237:        DBG_RETURN(ret);
                   2238: }
                   2239: /* }}} */
                   2240: 
                   2241: 
                   2242: /* {{{ mysqlnd_stmt::alloc_param_bind */
                   2243: static MYSQLND_PARAM_BIND *
                   2244: MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind)(MYSQLND_STMT * const s TSRMLS_DC)
                   2245: {
                   2246:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   2247:        DBG_ENTER("mysqlnd_stmt::alloc_param_bind");
                   2248:        if (!stmt) {
                   2249:                DBG_RETURN(NULL);
                   2250:        }
                   2251:        DBG_RETURN(mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent));
                   2252: }
                   2253: /* }}} */
                   2254: 
                   2255: 
                   2256: /* {{{ mysqlnd_stmt::alloc_result_bind */
                   2257: static MYSQLND_RESULT_BIND *
                   2258: MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind)(MYSQLND_STMT * const s TSRMLS_DC)
                   2259: {
                   2260:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   2261:        DBG_ENTER("mysqlnd_stmt::alloc_result_bind");
                   2262:        if (!stmt) {
                   2263:                DBG_RETURN(NULL);
                   2264:        }
                   2265:        DBG_RETURN(mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent));
                   2266: }
                   2267: /* }}} */
                   2268: 
                   2269: 
                   2270: /* {{{ param_bind::free_parameter_bind */
                   2271: PHPAPI void
                   2272: MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * param_bind TSRMLS_DC)
                   2273: {
                   2274:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   2275:        if (stmt) {
                   2276:                mnd_pefree(param_bind, stmt->persistent);
                   2277:        }
                   2278: }
                   2279: /* }}} */
                   2280: 
                   2281: 
                   2282: /* {{{ mysqlnd_stmt::free_result_bind */
                   2283: PHPAPI void
                   2284: MYSQLND_METHOD(mysqlnd_stmt, free_result_bind)(MYSQLND_STMT * const s, MYSQLND_RESULT_BIND * result_bind TSRMLS_DC)
                   2285: {
                   2286:        MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
                   2287:        if (stmt) {
                   2288:                mnd_pefree(result_bind, stmt->persistent);
                   2289:        }
                   2290: }
                   2291: /* }}} */
                   2292: 
                   2293: 
                   2294: 
                   2295: MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
                   2296:        MYSQLND_METHOD(mysqlnd_stmt, prepare),
                   2297:        MYSQLND_METHOD(mysqlnd_stmt, execute),
                   2298:        MYSQLND_METHOD(mysqlnd_stmt, use_result),
                   2299:        MYSQLND_METHOD(mysqlnd_stmt, store_result),
                   2300:        MYSQLND_METHOD(mysqlnd_stmt, get_result),
                   2301:        MYSQLND_METHOD(mysqlnd_stmt, more_results),
                   2302:        MYSQLND_METHOD(mysqlnd_stmt, next_result),
                   2303:        MYSQLND_METHOD(mysqlnd_stmt, free_result),
                   2304:        MYSQLND_METHOD(mysqlnd_stmt, data_seek),
                   2305:        MYSQLND_METHOD(mysqlnd_stmt, reset),
                   2306:        MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close),
                   2307:        MYSQLND_METHOD(mysqlnd_stmt, dtor),
                   2308: 
                   2309:        MYSQLND_METHOD(mysqlnd_stmt, fetch),
                   2310: 
                   2311:        MYSQLND_METHOD(mysqlnd_stmt, bind_parameters),
                   2312:        MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter),
                   2313:        MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
                   2314:        MYSQLND_METHOD(mysqlnd_stmt, bind_result),
                   2315:        MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
                   2316:        MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
                   2317:        MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
                   2318:        MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
                   2319: 
                   2320:        MYSQLND_METHOD(mysqlnd_stmt, insert_id),
                   2321:        MYSQLND_METHOD(mysqlnd_stmt, affected_rows),
                   2322:        MYSQLND_METHOD(mysqlnd_stmt, num_rows),
                   2323: 
                   2324:        MYSQLND_METHOD(mysqlnd_stmt, param_count),
                   2325:        MYSQLND_METHOD(mysqlnd_stmt, field_count),
                   2326:        MYSQLND_METHOD(mysqlnd_stmt, warning_count),
                   2327: 
                   2328:        MYSQLND_METHOD(mysqlnd_stmt, errno),
                   2329:        MYSQLND_METHOD(mysqlnd_stmt, error),
                   2330:        MYSQLND_METHOD(mysqlnd_stmt, sqlstate),
                   2331: 
                   2332:        MYSQLND_METHOD(mysqlnd_stmt, attr_get),
                   2333:        MYSQLND_METHOD(mysqlnd_stmt, attr_set),
                   2334: 
                   2335: 
                   2336:        MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind),
                   2337:        MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind),
                   2338:        MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind),
                   2339:        MYSQLND_METHOD(mysqlnd_stmt, free_result_bind),
                   2340:        MYSQLND_METHOD(mysqlnd_stmt, server_status),
                   2341:        mysqlnd_stmt_execute_generate_request,
                   2342:        mysqlnd_stmt_execute_parse_response,
1.1.1.2 ! misho    2343:        MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content),
        !          2344:        MYSQLND_METHOD(mysqlnd_stmt, flush)
1.1       misho    2345: MYSQLND_CLASS_METHODS_END;
                   2346: 
                   2347: 
                   2348: /* {{{ _mysqlnd_stmt_init */
1.1.1.2 ! misho    2349: MYSQLND_STMT *
        !          2350: _mysqlnd_stmt_init(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    2351: {
1.1.1.2 ! misho    2352:        MYSQLND_STMT * ret;
1.1       misho    2353:        DBG_ENTER("_mysqlnd_stmt_init");
1.1.1.2 ! misho    2354:        ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_prepared_statement(conn TSRMLS_CC);
        !          2355:        DBG_RETURN(ret);
1.1       misho    2356: }
                   2357: /* }}} */
                   2358: 
                   2359: 
                   2360: /* {{{ _mysqlnd_init_ps_subsystem */
                   2361: void _mysqlnd_init_ps_subsystem()
                   2362: {
1.1.1.2 ! misho    2363:        mysqlnd_stmt_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt));
1.1       misho    2364:        _mysqlnd_init_ps_fetch_subsystem();
                   2365: }
                   2366: /* }}} */
                   2367: 
                   2368: 
                   2369: /*
                   2370:  * Local variables:
                   2371:  * tab-width: 4
                   2372:  * c-basic-offset: 4
                   2373:  * End:
                   2374:  * vim600: noet sw=4 ts=4 fdm=marker
                   2375:  * vim<600: noet sw=4 ts=4
                   2376:  */

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