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

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

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