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

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

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