mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
A fix and test case for Bug#9478 "mysql_stmt_attr_set mysql_stmt_execute"
(crash on attempt to re-execute a statement with an open cursor) + post-review fixes.
This commit is contained in:
@ -95,6 +95,7 @@ extern const char *client_errors[]; /* Error messages */
|
|||||||
#define CR_FETCH_CANCELED 2050
|
#define CR_FETCH_CANCELED 2050
|
||||||
#define CR_NO_DATA 2051
|
#define CR_NO_DATA 2051
|
||||||
#define CR_NO_STMT_METADATA 2052
|
#define CR_NO_STMT_METADATA 2052
|
||||||
#define CR_ERROR_LAST /*Copy last error nr:*/ 2052
|
#define CR_NO_RESULT_SET 2053
|
||||||
|
#define CR_ERROR_LAST /*Copy last error nr:*/ 2053
|
||||||
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */
|
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ const char *client_errors[]=
|
|||||||
"Row retrieval was canceled by mysql_stmt_close() call",
|
"Row retrieval was canceled by mysql_stmt_close() call",
|
||||||
"Attempt to read column without prior row fetch",
|
"Attempt to read column without prior row fetch",
|
||||||
"Prepared statement contains no metadata",
|
"Prepared statement contains no metadata",
|
||||||
|
"Attempt to read a row while there is no result set associated with the statement"
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,6 +142,7 @@ const char *client_errors[]=
|
|||||||
"Row retrieval was canceled by mysql_stmt_close() call",
|
"Row retrieval was canceled by mysql_stmt_close() call",
|
||||||
"Attempt to read column without prior row fetch",
|
"Attempt to read column without prior row fetch",
|
||||||
"Prepared statement contains no metadata",
|
"Prepared statement contains no metadata",
|
||||||
|
"Attempt to read a row while there is no result set associated with the statement"
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -200,6 +202,7 @@ const char *client_errors[]=
|
|||||||
"Row retrieval was canceled by mysql_stmt_close() call",
|
"Row retrieval was canceled by mysql_stmt_close() call",
|
||||||
"Attempt to read column without prior row fetch",
|
"Attempt to read column without prior row fetch",
|
||||||
"Prepared statement contains no metadata",
|
"Prepared statement contains no metadata",
|
||||||
|
"Attempt to read a row while there is no result set associated with the statement"
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -1724,6 +1724,13 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
|
|||||||
static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data);
|
static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data);
|
||||||
static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field);
|
static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field);
|
||||||
|
|
||||||
|
/* Auxilary function used to reset statement handle. */
|
||||||
|
|
||||||
|
#define RESET_SERVER_SIDE 1
|
||||||
|
#define RESET_LONG_DATA 2
|
||||||
|
|
||||||
|
static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
|
Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
|
||||||
values stored in network buffer.
|
values stored in network buffer.
|
||||||
@ -2019,7 +2026,8 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
|
|||||||
/* This is second prepare with another statement */
|
/* This is second prepare with another statement */
|
||||||
char buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */
|
char buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */
|
||||||
|
|
||||||
mysql_stmt_free_result(stmt);
|
if (reset_stmt_handle(stmt, RESET_LONG_DATA))
|
||||||
|
DBUG_RETURN(1);
|
||||||
/*
|
/*
|
||||||
These members must be reset for API to
|
These members must be reset for API to
|
||||||
function in case of error or misuse.
|
function in case of error or misuse.
|
||||||
@ -2702,12 +2710,8 @@ static int
|
|||||||
stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)),
|
stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)),
|
||||||
unsigned char **row __attribute__((unused)))
|
unsigned char **row __attribute__((unused)))
|
||||||
{
|
{
|
||||||
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
|
set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate);
|
||||||
{
|
return 1;
|
||||||
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return MYSQL_NO_DATA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2817,7 +2821,8 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_stmt_free_result(stmt);
|
if (reset_stmt_handle(stmt, 0))
|
||||||
|
DBUG_RETURN(1);
|
||||||
/*
|
/*
|
||||||
No need to check for stmt->state: if the statement wasn't
|
No need to check for stmt->state: if the statement wasn't
|
||||||
prepared we'll get 'unknown statement handler' error from server.
|
prepared we'll get 'unknown statement handler' error from server.
|
||||||
@ -4805,16 +4810,21 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
|
|||||||
DBUG_RETURN(stmt->result.rows);
|
DBUG_RETURN(stmt->result.rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
|
|
||||||
|
/*
|
||||||
|
Free the client side memory buffers, reset long data state
|
||||||
|
on client if necessary, and reset the server side statement if
|
||||||
|
this has been requested.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
|
||||||
{
|
{
|
||||||
MYSQL_DATA *result= &stmt->result;
|
/* If statement hasn't been prepared there is nothing to reset */
|
||||||
DBUG_ENTER("mysql_stmt_free_result");
|
|
||||||
|
|
||||||
DBUG_ASSERT(stmt != 0);
|
|
||||||
|
|
||||||
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
|
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
|
||||||
{
|
{
|
||||||
MYSQL *mysql= stmt->mysql;
|
MYSQL *mysql= stmt->mysql;
|
||||||
|
MYSQL_DATA *result= &stmt->result;
|
||||||
|
my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor;
|
||||||
|
|
||||||
if (result->data)
|
if (result->data)
|
||||||
{
|
{
|
||||||
@ -4824,23 +4834,58 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
|
|||||||
result->rows= 0;
|
result->rows= 0;
|
||||||
stmt->data_cursor= NULL;
|
stmt->data_cursor= NULL;
|
||||||
}
|
}
|
||||||
|
if (flags & RESET_LONG_DATA)
|
||||||
if (mysql && stmt->field_count &&
|
|
||||||
(int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
|
|
||||||
{
|
{
|
||||||
if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
|
MYSQL_BIND *param= stmt->params, *param_end= param + stmt->param_count;
|
||||||
mysql->unbuffered_fetch_owner= 0;
|
/* Clear long_data_used flags */
|
||||||
if (mysql->status != MYSQL_STATUS_READY)
|
for (; param < param_end; param++)
|
||||||
|
param->long_data_used= 0;
|
||||||
|
}
|
||||||
|
stmt->read_row_func= stmt_read_row_no_data;
|
||||||
|
if (mysql)
|
||||||
|
{
|
||||||
|
if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
|
||||||
{
|
{
|
||||||
/* There is a result set and it belongs to this statement */
|
if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
|
||||||
(*mysql->methods->flush_use_result)(mysql);
|
mysql->unbuffered_fetch_owner= 0;
|
||||||
mysql->status= MYSQL_STATUS_READY;
|
if (stmt->field_count && mysql->status != MYSQL_STATUS_READY)
|
||||||
|
{
|
||||||
|
/* There is a result set and it belongs to this statement */
|
||||||
|
(*mysql->methods->flush_use_result)(mysql);
|
||||||
|
if (mysql->unbuffered_fetch_owner)
|
||||||
|
*mysql->unbuffered_fetch_owner= TRUE;
|
||||||
|
mysql->status= MYSQL_STATUS_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_cursor || (flags & RESET_SERVER_SIDE))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Reset the server side statement and close the server side
|
||||||
|
cursor if it exists.
|
||||||
|
*/
|
||||||
|
char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */
|
||||||
|
int4store(buff, stmt->stmt_id);
|
||||||
|
if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff,
|
||||||
|
sizeof(buff), 0, 0, 0))
|
||||||
|
{
|
||||||
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
|
mysql->net.sqlstate);
|
||||||
|
stmt->state= MYSQL_STMT_INIT_DONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stmt->state= MYSQL_STMT_PREPARE_DONE;
|
stmt->state= MYSQL_STMT_PREPARE_DONE;
|
||||||
stmt->read_row_func= stmt_read_row_no_data;
|
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_stmt_free_result");
|
||||||
|
|
||||||
|
/* Free the client side and close the server side cursor if there is one */
|
||||||
|
DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
@ -4913,33 +4958,10 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
|
|||||||
|
|
||||||
my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
|
my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */
|
|
||||||
MYSQL *mysql;
|
|
||||||
MYSQL_BIND *param, *param_end;
|
|
||||||
DBUG_ENTER("mysql_stmt_reset");
|
DBUG_ENTER("mysql_stmt_reset");
|
||||||
DBUG_ASSERT(stmt != 0);
|
DBUG_ASSERT(stmt != 0);
|
||||||
|
/* Reset the client and server sides of the prepared statement */
|
||||||
/* If statement hasnt been prepared there is nothing to reset */
|
DBUG_RETURN(reset_stmt_handle(stmt, RESET_SERVER_SIDE | RESET_LONG_DATA));
|
||||||
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
|
|
||||||
mysql= stmt->mysql->last_used_con;
|
|
||||||
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
|
|
||||||
if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff,
|
|
||||||
sizeof(buff), 0, 0, 0))
|
|
||||||
{
|
|
||||||
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
|
||||||
mysql->net.sqlstate);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear long_data_used for next call (as we do in mysql_stmt_execute() */
|
|
||||||
for (param= stmt->params, param_end= param + stmt->param_count;
|
|
||||||
param < param_end;
|
|
||||||
param++)
|
|
||||||
param->long_data_used= 0;
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -864,6 +864,8 @@ mysql_free_result(MYSQL_RES *result)
|
|||||||
{
|
{
|
||||||
(*mysql->methods->flush_use_result)(mysql);
|
(*mysql->methods->flush_use_result)(mysql);
|
||||||
mysql->status=MYSQL_STATUS_READY;
|
mysql->status=MYSQL_STATUS_READY;
|
||||||
|
if (mysql->unbuffered_fetch_owner)
|
||||||
|
*mysql->unbuffered_fetch_owner= TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_rows(result->data);
|
free_rows(result->data);
|
||||||
|
@ -4766,13 +4766,13 @@ ER_SUBQUERY_NO_1_ROW 21000
|
|||||||
swe "Subquery returnerade mer <20>n 1 rad"
|
swe "Subquery returnerade mer <20>n 1 rad"
|
||||||
ukr "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ¦<><C2A6><EFBFBD> <20>i<EFBFBD> 1 <20><><EFBFBD><EFBFBD><EFBFBD>"
|
ukr "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ¦<><C2A6><EFBFBD> <20>i<EFBFBD> 1 <20><><EFBFBD><EFBFBD><EFBFBD>"
|
||||||
ER_UNKNOWN_STMT_HANDLER
|
ER_UNKNOWN_STMT_HANDLER
|
||||||
dan "Unknown prepared statement handler (%ld) given to %s"
|
dan "Unknown prepared statement handler (%.*s) given to %s"
|
||||||
eng "Unknown prepared statement handler (%.*s) given to %s"
|
eng "Unknown prepared statement handler (%.*s) given to %s"
|
||||||
ger "Unbekannter Prepared-Statement-Handler (%.*s) f<>r %s angegeben"
|
ger "Unbekannter Prepared-Statement-Handler (%.*s) f<>r %s angegeben"
|
||||||
por "Desconhecido manipulador de declara<72><61>o preparado (%.*s) determinado para %s"
|
por "Desconhecido manipulador de declara<72><61>o preparado (%.*s) determinado para %s"
|
||||||
spa "Desconocido preparado comando handler (%ld) dado para %s"
|
spa "Desconocido preparado comando handler (%.*s) dado para %s"
|
||||||
swe "Ok<4F>nd PREPARED STATEMENT id (%ld) var given till %s"
|
swe "Ok<4F>nd PREPARED STATEMENT id (%.*s) var given till %s"
|
||||||
ukr "Unknown prepared statement handler (%ld) given to %s"
|
ukr "Unknown prepared statement handler (%.*s) given to %s"
|
||||||
ER_CORRUPT_HELP_DB
|
ER_CORRUPT_HELP_DB
|
||||||
eng "Help database is corrupt or does not exist"
|
eng "Help database is corrupt or does not exist"
|
||||||
ger "Die Hilfe-Datenbank ist besch<63>digt oder existiert nicht"
|
ger "Die Hilfe-Datenbank ist besch<63>digt oder existiert nicht"
|
||||||
@ -5352,3 +5352,7 @@ ER_BINLOG_UNSAFE_ROUTINE
|
|||||||
eng "This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
|
eng "This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
|
||||||
ER_BINLOG_CREATE_ROUTINE_NEED_SUPER
|
ER_BINLOG_CREATE_ROUTINE_NEED_SUPER
|
||||||
eng "You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
|
eng "You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
|
||||||
|
ER_EXEC_STMT_WITH_OPEN_CURSOR
|
||||||
|
eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it."
|
||||||
|
ER_STMT_HAS_NO_OPEN_CURSOR
|
||||||
|
eng "The statement (%d) has no open cursor."
|
||||||
|
@ -135,7 +135,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where)
|
|||||||
if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT)
|
if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT)
|
||||||
{
|
{
|
||||||
char llbuf[22];
|
char llbuf[22];
|
||||||
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), 22, llstr(id, llbuf), where);
|
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf),
|
||||||
|
where);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (Prepared_statement *) stmt;
|
return (Prepared_statement *) stmt;
|
||||||
@ -1969,7 +1970,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||||||
{
|
{
|
||||||
ulong stmt_id= uint4korr(packet);
|
ulong stmt_id= uint4korr(packet);
|
||||||
ulong flags= (ulong) ((uchar) packet[4]);
|
ulong flags= (ulong) ((uchar) packet[4]);
|
||||||
Cursor *cursor= 0;
|
Cursor *cursor;
|
||||||
/*
|
/*
|
||||||
Query text for binary log, or empty string if the query is not put into
|
Query text for binary log, or empty string if the query is not put into
|
||||||
binary log.
|
binary log.
|
||||||
@ -1995,6 +1996,13 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cursor= stmt->cursor;
|
||||||
|
if (cursor && cursor->is_open())
|
||||||
|
{
|
||||||
|
my_error(ER_EXEC_STMT_WITH_OPEN_CURSOR, MYF(0));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_ASSERT(thd->free_list == NULL);
|
DBUG_ASSERT(thd->free_list == NULL);
|
||||||
mysql_reset_thd_for_next_command(thd);
|
mysql_reset_thd_for_next_command(thd);
|
||||||
if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
|
if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
|
||||||
@ -2013,7 +2021,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info",("Using READ_ONLY cursor"));
|
DBUG_PRINT("info",("Using READ_ONLY cursor"));
|
||||||
if (!stmt->cursor &&
|
if (!cursor &&
|
||||||
!(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
|
!(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
/* If lex->result is set, mysql_execute_command will use it */
|
/* If lex->result is set, mysql_execute_command will use it */
|
||||||
@ -2208,13 +2216,15 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
|||||||
Statement *stmt;
|
Statement *stmt;
|
||||||
DBUG_ENTER("mysql_stmt_fetch");
|
DBUG_ENTER("mysql_stmt_fetch");
|
||||||
|
|
||||||
if (!(stmt= thd->stmt_map.find(stmt_id)) ||
|
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
|
||||||
!stmt->cursor ||
|
DBUG_VOID_RETURN;
|
||||||
!stmt->cursor->is_open())
|
|
||||||
|
if (!stmt->cursor || !stmt->cursor->is_open())
|
||||||
{
|
{
|
||||||
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, "fetch");
|
my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0));
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->current_arena= stmt;
|
thd->current_arena= stmt;
|
||||||
thd->set_n_backup_statement(stmt, &thd->stmt_backup);
|
thd->set_n_backup_statement(stmt, &thd->stmt_backup);
|
||||||
stmt->cursor->init_thd(thd);
|
stmt->cursor->init_thd(thd);
|
||||||
@ -2266,6 +2276,9 @@ void mysql_stmt_reset(THD *thd, char *packet)
|
|||||||
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
|
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
|
if (stmt->cursor && stmt->cursor->is_open())
|
||||||
|
stmt->cursor->close();
|
||||||
|
|
||||||
stmt->state= Item_arena::PREPARED;
|
stmt->state= Item_arena::PREPARED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1742,6 +1742,7 @@ Cursor::init_from_thd(THD *thd)
|
|||||||
/*
|
/*
|
||||||
XXX: thd->locked_tables is not changed.
|
XXX: thd->locked_tables is not changed.
|
||||||
What problems can we have with it if cursor is open?
|
What problems can we have with it if cursor is open?
|
||||||
|
TODO: must be fixed because of the prelocked mode.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
TODO: grab thd->free_list here?
|
TODO: grab thd->free_list here?
|
||||||
@ -1871,10 +1872,6 @@ Cursor::fetch(ulong num_rows)
|
|||||||
}
|
}
|
||||||
else if (error != NESTED_LOOP_KILLED)
|
else if (error != NESTED_LOOP_KILLED)
|
||||||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||||||
/* free cursor memory */
|
|
||||||
free_items(free_list);
|
|
||||||
free_list= 0;
|
|
||||||
free_root(&main_mem_root, MYF(0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1914,6 +1911,13 @@ Cursor::close()
|
|||||||
}
|
}
|
||||||
join= 0;
|
join= 0;
|
||||||
unit= 0;
|
unit= 0;
|
||||||
|
free_items(free_list);
|
||||||
|
free_list= 0;
|
||||||
|
/*
|
||||||
|
Must be last, as some memory might be allocated for free purposes,
|
||||||
|
like in free_tmp_table() (TODO: fix this issue)
|
||||||
|
*/
|
||||||
|
free_root(mem_root, MYF(0));
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1922,12 +1926,6 @@ Cursor::~Cursor()
|
|||||||
{
|
{
|
||||||
if (is_open())
|
if (is_open())
|
||||||
close();
|
close();
|
||||||
free_items(free_list);
|
|
||||||
/*
|
|
||||||
Must be last, as some memory might be allocated for free purposes,
|
|
||||||
like in free_tmp_table() (TODO: fix this issue)
|
|
||||||
*/
|
|
||||||
free_root(&main_mem_root, MYF(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
@ -364,6 +364,10 @@ class JOIN :public Sql_alloc
|
|||||||
/*
|
/*
|
||||||
Server-side cursor (now stands only for basic read-only cursor)
|
Server-side cursor (now stands only for basic read-only cursor)
|
||||||
See class implementation in sql_select.cc
|
See class implementation in sql_select.cc
|
||||||
|
A cursor has its own runtime state - list of used items and memory root of
|
||||||
|
used memory - which is different from Prepared statement runtime: it must
|
||||||
|
be different at least for the purpose of reusing the same prepared
|
||||||
|
statement for many cursors.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Cursor: public Sql_alloc, public Item_arena
|
class Cursor: public Sql_alloc, public Item_arena
|
||||||
|
@ -2269,7 +2269,7 @@ static void test_ps_conj_select()
|
|||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
int_data= 1;
|
int_data= 1;
|
||||||
strcpy(str_data, "hh");
|
strmov(str_data, "hh");
|
||||||
str_length= strlen(str_data);
|
str_length= strlen(str_data);
|
||||||
|
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
@ -7288,7 +7288,7 @@ static void test_decimal_bug()
|
|||||||
rc= mysql_stmt_bind_param(stmt, bind);
|
rc= mysql_stmt_bind_param(stmt, bind);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
strcpy(data, "8.0");
|
strmov(data, "8.0");
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
@ -7306,7 +7306,7 @@ static void test_decimal_bug()
|
|||||||
rc= mysql_stmt_fetch(stmt);
|
rc= mysql_stmt_fetch(stmt);
|
||||||
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
||||||
|
|
||||||
strcpy(data, "5.61");
|
strmov(data, "5.61");
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
@ -7331,7 +7331,7 @@ static void test_decimal_bug()
|
|||||||
rc= mysql_stmt_fetch(stmt);
|
rc= mysql_stmt_fetch(stmt);
|
||||||
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
||||||
|
|
||||||
strcpy(data, "10.22"); is_null= 0;
|
strmov(data, "10.22"); is_null= 0;
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
@ -8510,13 +8510,13 @@ static void test_sqlmode()
|
|||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
/* PIPES_AS_CONCAT */
|
/* PIPES_AS_CONCAT */
|
||||||
strcpy(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\"");
|
strmov(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\"");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n With %s", query);
|
fprintf(stdout, "\n With %s", query);
|
||||||
rc= mysql_query(mysql, query);
|
rc= mysql_query(mysql, query);
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
strcpy(query, "INSERT INTO test_piping VALUES(?||?)");
|
strmov(query, "INSERT INTO test_piping VALUES(?||?)");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n query: %s", query);
|
fprintf(stdout, "\n query: %s", query);
|
||||||
stmt= mysql_simple_prepare(mysql, query);
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
@ -8542,7 +8542,7 @@ static void test_sqlmode()
|
|||||||
rc= mysql_stmt_bind_param(stmt, bind);
|
rc= mysql_stmt_bind_param(stmt, bind);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
strcpy(c1, "My"); strcpy(c2, "SQL");
|
strmov(c1, "My"); strmov(c2, "SQL");
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
@ -8552,20 +8552,20 @@ static void test_sqlmode()
|
|||||||
rc= mysql_query(mysql, "DELETE FROM test_piping");
|
rc= mysql_query(mysql, "DELETE FROM test_piping");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
strcpy(query, "SELECT connection_id ()");
|
strmov(query, "SELECT connection_id ()");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n query: %s", query);
|
fprintf(stdout, "\n query: %s", query);
|
||||||
stmt= mysql_simple_prepare(mysql, query);
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
check_stmt_r(stmt);
|
check_stmt_r(stmt);
|
||||||
|
|
||||||
/* ANSI */
|
/* ANSI */
|
||||||
strcpy(query, "SET SQL_MODE= \"ANSI\"");
|
strmov(query, "SET SQL_MODE= \"ANSI\"");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n With %s", query);
|
fprintf(stdout, "\n With %s", query);
|
||||||
rc= mysql_query(mysql, query);
|
rc= mysql_query(mysql, query);
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
strcpy(query, "INSERT INTO test_piping VALUES(?||?)");
|
strmov(query, "INSERT INTO test_piping VALUES(?||?)");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n query: %s", query);
|
fprintf(stdout, "\n query: %s", query);
|
||||||
stmt= mysql_simple_prepare(mysql, query);
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
@ -8576,7 +8576,7 @@ static void test_sqlmode()
|
|||||||
rc= mysql_stmt_bind_param(stmt, bind);
|
rc= mysql_stmt_bind_param(stmt, bind);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
strcpy(c1, "My"); strcpy(c2, "SQL");
|
strmov(c1, "My"); strmov(c2, "SQL");
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
@ -8584,7 +8584,7 @@ static void test_sqlmode()
|
|||||||
verify_col_data("test_piping", "name", "MySQL");
|
verify_col_data("test_piping", "name", "MySQL");
|
||||||
|
|
||||||
/* ANSI mode spaces ... */
|
/* ANSI mode spaces ... */
|
||||||
strcpy(query, "SELECT connection_id ()");
|
strmov(query, "SELECT connection_id ()");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n query: %s", query);
|
fprintf(stdout, "\n query: %s", query);
|
||||||
stmt= mysql_simple_prepare(mysql, query);
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
@ -8604,13 +8604,13 @@ static void test_sqlmode()
|
|||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
/* IGNORE SPACE MODE */
|
/* IGNORE SPACE MODE */
|
||||||
strcpy(query, "SET SQL_MODE= \"IGNORE_SPACE\"");
|
strmov(query, "SET SQL_MODE= \"IGNORE_SPACE\"");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n With %s", query);
|
fprintf(stdout, "\n With %s", query);
|
||||||
rc= mysql_query(mysql, query);
|
rc= mysql_query(mysql, query);
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
strcpy(query, "SELECT connection_id ()");
|
strmov(query, "SELECT connection_id ()");
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
fprintf(stdout, "\n query: %s", query);
|
fprintf(stdout, "\n query: %s", query);
|
||||||
stmt= mysql_simple_prepare(mysql, query);
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
@ -9115,7 +9115,7 @@ static void test_bug2248()
|
|||||||
|
|
||||||
/* This too should not hang but should return proper error */
|
/* This too should not hang but should return proper error */
|
||||||
rc= mysql_stmt_fetch(stmt);
|
rc= mysql_stmt_fetch(stmt);
|
||||||
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
DIE_UNLESS(rc == 1);
|
||||||
|
|
||||||
/* This too should not hang but should not bark */
|
/* This too should not hang but should not bark */
|
||||||
rc= mysql_stmt_store_result(stmt);
|
rc= mysql_stmt_store_result(stmt);
|
||||||
@ -9124,7 +9124,7 @@ static void test_bug2248()
|
|||||||
/* This should return proper error */
|
/* This should return proper error */
|
||||||
rc= mysql_stmt_fetch(stmt);
|
rc= mysql_stmt_fetch(stmt);
|
||||||
check_execute_r(stmt, rc);
|
check_execute_r(stmt, rc);
|
||||||
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
DIE_UNLESS(rc == 1);
|
||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
@ -10266,7 +10266,7 @@ static void test_union_param()
|
|||||||
my_bool my_null= FALSE;
|
my_bool my_null= FALSE;
|
||||||
myheader("test_union_param");
|
myheader("test_union_param");
|
||||||
|
|
||||||
strcpy(my_val, "abc");
|
strmov(my_val, "abc");
|
||||||
|
|
||||||
query= (char*)"select ? as my_col union distinct select ?";
|
query= (char*)"select ? as my_col union distinct select ?";
|
||||||
stmt= mysql_simple_prepare(mysql, query);
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
@ -10548,14 +10548,14 @@ static void test_bug3796()
|
|||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
printf("Concat result: '%s'\n", out_buff);
|
printf("Concat result: '%s'\n", out_buff);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
strcpy(canonical_buff, concat_arg0);
|
strmov(canonical_buff, concat_arg0);
|
||||||
strcat(canonical_buff, "ONE");
|
strcat(canonical_buff, "ONE");
|
||||||
DIE_UNLESS(strlen(canonical_buff) == out_length &&
|
DIE_UNLESS(strlen(canonical_buff) == out_length &&
|
||||||
strncmp(out_buff, canonical_buff, out_length) == 0);
|
strncmp(out_buff, canonical_buff, out_length) == 0);
|
||||||
|
|
||||||
rc= mysql_stmt_fetch(stmt);
|
rc= mysql_stmt_fetch(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
strcpy(canonical_buff + strlen(concat_arg0), "TWO");
|
strmov(canonical_buff + strlen(concat_arg0), "TWO");
|
||||||
DIE_UNLESS(strlen(canonical_buff) == out_length &&
|
DIE_UNLESS(strlen(canonical_buff) == out_length &&
|
||||||
strncmp(out_buff, canonical_buff, out_length) == 0);
|
strncmp(out_buff, canonical_buff, out_length) == 0);
|
||||||
if (!opt_silent)
|
if (!opt_silent)
|
||||||
@ -10852,7 +10852,8 @@ static void test_view()
|
|||||||
rc= mysql_stmt_prepare(stmt, query, strlen(query));
|
rc= mysql_stmt_prepare(stmt, query, strlen(query));
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
strcpy(str_data, "TEST");
|
strmov(str_data, "TEST");
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
bind[0].buffer_type= FIELD_TYPE_STRING;
|
bind[0].buffer_type= FIELD_TYPE_STRING;
|
||||||
bind[0].buffer= (char *)&str_data;
|
bind[0].buffer= (char *)&str_data;
|
||||||
bind[0].buffer_length= 50;
|
bind[0].buffer_length= 50;
|
||||||
@ -10971,8 +10972,9 @@ static void test_view_2where()
|
|||||||
" AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS "
|
" AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS "
|
||||||
" INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)");
|
" INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
for (i=0; i < 8; i++) {
|
for (i=0; i < 8; i++) {
|
||||||
strcpy(parms[i], "1");
|
strmov(parms[i], "1");
|
||||||
bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
|
bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
|
||||||
bind[i].buffer = (char *)&parms[i];
|
bind[i].buffer = (char *)&parms[i];
|
||||||
bind[i].buffer_length = 100;
|
bind[i].buffer_length = 100;
|
||||||
@ -11019,6 +11021,7 @@ static void test_view_star()
|
|||||||
myquery(rc);
|
myquery(rc);
|
||||||
rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1");
|
rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
for (i= 0; i < 2; i++) {
|
for (i= 0; i < 2; i++) {
|
||||||
sprintf((char *)&parms[i], "%d", i);
|
sprintf((char *)&parms[i], "%d", i);
|
||||||
bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
|
bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
|
||||||
@ -11084,6 +11087,7 @@ static void test_view_insert()
|
|||||||
rc= mysql_stmt_prepare(select_stmt, query, strlen(query));
|
rc= mysql_stmt_prepare(select_stmt, query, strlen(query));
|
||||||
check_execute(select_stmt, rc);
|
check_execute(select_stmt, rc);
|
||||||
|
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
bind[0].buffer_type = FIELD_TYPE_LONG;
|
bind[0].buffer_type = FIELD_TYPE_LONG;
|
||||||
bind[0].buffer = (char *)&my_val;
|
bind[0].buffer = (char *)&my_val;
|
||||||
bind[0].length = &my_length;
|
bind[0].length = &my_length;
|
||||||
@ -11187,6 +11191,7 @@ static void test_view_insert_fields()
|
|||||||
" F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8"
|
" F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8"
|
||||||
" from t1 T0001");
|
" from t1 T0001");
|
||||||
|
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
for (i= 0; i < 11; i++)
|
for (i= 0; i < 11; i++)
|
||||||
{
|
{
|
||||||
l[i]= 20;
|
l[i]= 20;
|
||||||
@ -11194,7 +11199,7 @@ static void test_view_insert_fields()
|
|||||||
bind[i].is_null= 0;
|
bind[i].is_null= 0;
|
||||||
bind[i].buffer= (char *)&parm[i];
|
bind[i].buffer= (char *)&parm[i];
|
||||||
|
|
||||||
strcpy(parm[i], "1");
|
strmov(parm[i], "1");
|
||||||
bind[i].buffer_length= 2;
|
bind[i].buffer_length= 2;
|
||||||
bind[i].length= &l[i];
|
bind[i].length= &l[i];
|
||||||
}
|
}
|
||||||
@ -12707,6 +12712,7 @@ from t2);");
|
|||||||
rc= mysql_query(mysql, "DROP VIEW v1");
|
rc= mysql_query(mysql, "DROP VIEW v1");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
rc= mysql_query(mysql, "DROP TABLE t1, t2");
|
rc= mysql_query(mysql, "DROP TABLE t1, t2");
|
||||||
|
mysql_free_result(res);
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -12923,6 +12929,152 @@ static void test_bug9520()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
We can't have more than one cursor open for a prepared statement.
|
||||||
|
Test re-executions of a PS with cursor; mysql_stmt_reset must close
|
||||||
|
the cursor attached to the statement, if there is one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void test_bug9478()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
MYSQL_BIND bind[1];
|
||||||
|
char a[6];
|
||||||
|
ulong a_len;
|
||||||
|
int rc, i;
|
||||||
|
|
||||||
|
myheader("test_bug9478");
|
||||||
|
|
||||||
|
mysql_query(mysql, "drop table if exists t1");
|
||||||
|
mysql_query(mysql, "create table t1 (id integer not null primary key, "
|
||||||
|
" name varchar(20) not null)");
|
||||||
|
rc= mysql_query(mysql, "insert into t1 (id, name) values "
|
||||||
|
" (1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
stmt= open_cursor("select name from t1 where id=2");
|
||||||
|
|
||||||
|
bzero(bind, sizeof(bind));
|
||||||
|
bind[0].buffer_type= MYSQL_TYPE_STRING;
|
||||||
|
bind[0].buffer= (char*) a;
|
||||||
|
bind[0].buffer_length= sizeof(a);
|
||||||
|
bind[0].length= &a_len;
|
||||||
|
mysql_stmt_bind_result(stmt, bind);
|
||||||
|
|
||||||
|
for (i= 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Fetched row: %s\n", a);
|
||||||
|
|
||||||
|
/*
|
||||||
|
The query above is a one-row result set. Therefore, there is no
|
||||||
|
cursor associated with it, as the server won't bother with opening
|
||||||
|
a cursor for a one-row result set. The first row was read from the
|
||||||
|
server in the fetch above. But there is eof packet pending in the
|
||||||
|
network. mysql_stmt_execute will flush the packet and successfully
|
||||||
|
execute the statement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Fetched row: %s\n", a);
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Fetched row: %s\n", a);
|
||||||
|
|
||||||
|
rc= mysql_stmt_reset(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
DIE_UNLESS(rc && mysql_stmt_errno(stmt));
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Got error (as expected): %s\n", mysql_stmt_error(stmt));
|
||||||
|
}
|
||||||
|
rc= mysql_stmt_close(stmt);
|
||||||
|
DIE_UNLESS(rc == 0);
|
||||||
|
|
||||||
|
/* Test the case with a server side cursor */
|
||||||
|
stmt= open_cursor("select name from t1");
|
||||||
|
|
||||||
|
mysql_stmt_bind_result(stmt, bind);
|
||||||
|
|
||||||
|
for (i= 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Fetched row: %s\n", a);
|
||||||
|
/*
|
||||||
|
Although protocol-wise an attempt to execute a statement which
|
||||||
|
already has an open cursor associated with it will yield an error,
|
||||||
|
the client library behavior tested here is consistent with
|
||||||
|
the non-cursor execution scenario: mysql_stmt_execute will
|
||||||
|
silently close the cursor if necessary.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
char buff[9];
|
||||||
|
bzero(buff, sizeof(buff));
|
||||||
|
/* Fill in the execute packet */
|
||||||
|
int4store(buff, stmt->stmt_id);
|
||||||
|
int4store(buff+5, 1);
|
||||||
|
rc= ((*mysql->methods->advanced_command)(mysql, COM_EXECUTE, buff,
|
||||||
|
sizeof(buff), 0,0,1) ||
|
||||||
|
(*mysql->methods->read_query_result)(mysql));
|
||||||
|
DIE_UNLESS(rc);
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Got error (as expected): %s\n", mysql_error(mysql));
|
||||||
|
}
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
while (! (rc= mysql_stmt_fetch(stmt)))
|
||||||
|
{
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Fetched row: %s\n", a);
|
||||||
|
}
|
||||||
|
DIE_UNLESS(rc == MYSQL_NO_DATA);
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Fetched row: %s\n", a);
|
||||||
|
|
||||||
|
rc= mysql_stmt_reset(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
DIE_UNLESS(rc && mysql_stmt_errno(stmt));
|
||||||
|
if (!opt_silent && i == 0)
|
||||||
|
printf("Got error (as expected): %s\n", mysql_stmt_error(stmt));
|
||||||
|
}
|
||||||
|
|
||||||
|
rc= mysql_stmt_close(stmt);
|
||||||
|
DIE_UNLESS(rc == 0);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "drop table t1");
|
||||||
|
myquery(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read and parse arguments and MySQL options from my.cnf
|
Read and parse arguments and MySQL options from my.cnf
|
||||||
*/
|
*/
|
||||||
@ -13153,6 +13305,7 @@ static struct my_tests_st my_tests[]= {
|
|||||||
{ "test_bug8880", test_bug8880 },
|
{ "test_bug8880", test_bug8880 },
|
||||||
{ "test_bug9159", test_bug9159 },
|
{ "test_bug9159", test_bug9159 },
|
||||||
{ "test_bug9520", test_bug9520 },
|
{ "test_bug9520", test_bug9520 },
|
||||||
|
{ "test_bug9478", test_bug9478 },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user