mariadb/sql/sp_rcontext.cc
Michael Widenius 70823e1d91 MDEV-5120 Test suite test maria-no-logging fails
The reason for the failure was a bug in an include file on debian that causes 'struct stat'
to have different sized depending on the environment.

This patch fixes so that we always include my_global.h or my_config.h before we include any other files.

Other things:
- Removed #include <my_global.h> in some include files; Better to always do this at the top level to have as few
  "always-include-this-file-first' files as possible.
- Removed usage of some include files that where already included by my_global.h or by other files.


client/mysql_plugin.c:
  Use my_global.h first
client/mysqlslap.c:
  Remove duplicated include files
extra/comp_err.c:
  Remove duplicated include files
include/m_string.h:
  Remove duplicated include files
include/maria.h:
  Remove duplicated include files
libmysqld/emb_qcache.cc:
  Use my_global.h first
plugin/semisync/semisync.h:
  Use my_pthread.h first
sql/datadict.cc:
  Use my_global.h first
sql/debug_sync.cc:
  Use my_global.h first
sql/derror.cc:
  Use my_global.h first
sql/des_key_file.cc:
  Use my_global.h first
sql/discover.cc:
  Use my_global.h first
sql/event_data_objects.cc:
  Use my_global.h first
sql/event_db_repository.cc:
  Use my_global.h first
sql/event_parse_data.cc:
  Use my_global.h first
sql/event_queue.cc:
  Use my_global.h first
sql/event_scheduler.cc:
  Use my_global.h first
sql/events.cc:
  Use my_global.h first
sql/field.cc:
  Use my_global.h first
  Remove duplicated include files
sql/field_conv.cc:
  Use my_global.h first
sql/filesort.cc:
  Use my_global.h first
  Remove duplicated include files
sql/gstream.cc:
  Use my_global.h first
sql/ha_ndbcluster.cc:
  Use my_global.h first
sql/ha_ndbcluster_binlog.cc:
  Use my_global.h first
sql/ha_ndbcluster_cond.cc:
  Use my_global.h first
sql/ha_partition.cc:
  Use my_global.h first
sql/handler.cc:
  Use my_global.h first
sql/hash_filo.cc:
  Use my_global.h first
sql/hostname.cc:
  Use my_global.h first
sql/init.cc:
  Use my_global.h first
sql/item.cc:
  Use my_global.h first
sql/item_buff.cc:
  Use my_global.h first
sql/item_cmpfunc.cc:
  Use my_global.h first
sql/item_create.cc:
  Use my_global.h first
sql/item_geofunc.cc:
  Use my_global.h first
sql/item_inetfunc.cc:
  Use my_global.h first
sql/item_row.cc:
  Use my_global.h first
sql/item_strfunc.cc:
  Use my_global.h first
sql/item_subselect.cc:
  Use my_global.h first
sql/item_sum.cc:
  Use my_global.h first
sql/item_timefunc.cc:
  Use my_global.h first
sql/item_xmlfunc.cc:
  Use my_global.h first
sql/key.cc:
  Use my_global.h first
sql/lock.cc:
  Use my_global.h first
sql/log.cc:
  Use my_global.h first
sql/log_event.cc:
  Use my_global.h first
sql/log_event_old.cc:
  Use my_global.h first
sql/mf_iocache.cc:
  Use my_global.h first
sql/mysql_install_db.cc:
  Remove duplicated include files
sql/mysqld.cc:
  Remove duplicated include files
sql/net_serv.cc:
  Remove duplicated include files
sql/opt_range.cc:
  Use my_global.h first
sql/opt_subselect.cc:
  Use my_global.h first
sql/opt_sum.cc:
  Use my_global.h first
sql/parse_file.cc:
  Use my_global.h first
sql/partition_info.cc:
  Use my_global.h first
sql/procedure.cc:
  Use my_global.h first
sql/protocol.cc:
  Use my_global.h first
sql/records.cc:
  Use my_global.h first
sql/records.h:
  Don't include my_global.h
  Better to do this at the upper level
sql/repl_failsafe.cc:
  Use my_global.h first
sql/rpl_filter.cc:
  Use my_global.h first
sql/rpl_gtid.cc:
  Use my_global.h first
sql/rpl_handler.cc:
  Use my_global.h first
sql/rpl_injector.cc:
  Use my_global.h first
sql/rpl_record.cc:
  Use my_global.h first
sql/rpl_record_old.cc:
  Use my_global.h first
sql/rpl_reporting.cc:
  Use my_global.h first
sql/rpl_rli.cc:
  Use my_global.h first
sql/rpl_tblmap.cc:
  Use my_global.h first
sql/rpl_utility.cc:
  Use my_global.h first
sql/set_var.cc:
  Added comment
sql/slave.cc:
  Use my_global.h first
sql/sp.cc:
  Use my_global.h first
sql/sp_cache.cc:
  Use my_global.h first
sql/sp_head.cc:
  Use my_global.h first
sql/sp_pcontext.cc:
  Use my_global.h first
sql/sp_rcontext.cc:
  Use my_global.h first
sql/spatial.cc:
  Use my_global.h first
sql/sql_acl.cc:
  Use my_global.h first
sql/sql_admin.cc:
  Use my_global.h first
sql/sql_analyse.cc:
  Use my_global.h first
sql/sql_audit.cc:
  Use my_global.h first
sql/sql_base.cc:
  Use my_global.h first
sql/sql_binlog.cc:
  Use my_global.h first
sql/sql_bootstrap.cc:
  Use my_global.h first
  Use my_global.h first
sql/sql_cache.cc:
  Use my_global.h first
sql/sql_class.cc:
  Use my_global.h first
sql/sql_client.cc:
  Use my_global.h first
sql/sql_connect.cc:
  Use my_global.h first
sql/sql_crypt.cc:
  Use my_global.h first
sql/sql_cursor.cc:
  Use my_global.h first
sql/sql_db.cc:
  Use my_global.h first
sql/sql_delete.cc:
  Use my_global.h first
sql/sql_derived.cc:
  Use my_global.h first
sql/sql_do.cc:
  Use my_global.h first
sql/sql_error.cc:
  Use my_global.h first
sql/sql_explain.cc:
  Use my_global.h first
sql/sql_expression_cache.cc:
  Use my_global.h first
sql/sql_handler.cc:
  Use my_global.h first
sql/sql_help.cc:
  Use my_global.h first
sql/sql_insert.cc:
  Use my_global.h first
sql/sql_lex.cc:
  Use my_global.h first
sql/sql_load.cc:
  Use my_global.h first
sql/sql_locale.cc:
  Use my_global.h first
sql/sql_manager.cc:
  Use my_global.h first
sql/sql_parse.cc:
  Use my_global.h first
sql/sql_partition.cc:
  Use my_global.h first
sql/sql_plugin.cc:
  Added comment
sql/sql_prepare.cc:
  Use my_global.h first
sql/sql_priv.h:
  Added error if we use this before including my_global.h
  This check is here becasue so many files includes sql_priv.h first.
sql/sql_profile.cc:
  Use my_global.h first
sql/sql_reload.cc:
  Use my_global.h first
sql/sql_rename.cc:
  Use my_global.h first
sql/sql_repl.cc:
  Use my_global.h first
sql/sql_select.cc:
  Use my_global.h first
sql/sql_servers.cc:
  Use my_global.h first
sql/sql_show.cc:
  Added comment
sql/sql_signal.cc:
  Use my_global.h first
sql/sql_statistics.cc:
  Use my_global.h first
sql/sql_table.cc:
  Use my_global.h first
sql/sql_tablespace.cc:
  Use my_global.h first
sql/sql_test.cc:
  Use my_global.h first
sql/sql_time.cc:
  Use my_global.h first
sql/sql_trigger.cc:
  Use my_global.h first
sql/sql_udf.cc:
  Use my_global.h first
sql/sql_union.cc:
  Use my_global.h first
sql/sql_update.cc:
  Use my_global.h first
sql/sql_view.cc:
  Use my_global.h first
sql/sys_vars.cc:
  Added comment
sql/table.cc:
  Use my_global.h first
sql/thr_malloc.cc:
  Use my_global.h first
sql/transaction.cc:
  Use my_global.h first
sql/uniques.cc:
  Use my_global.h first
sql/unireg.cc:
  Use my_global.h first
sql/unireg.h:
  Removed inclusion of my_global.h
storage/archive/ha_archive.cc:
  Added comment
storage/blackhole/ha_blackhole.cc:
  Use my_global.h first
storage/csv/ha_tina.cc:
  Use my_global.h first
storage/csv/transparent_file.cc:
  Use my_global.h first
storage/federated/ha_federated.cc:
  Use my_global.h first
storage/federatedx/federatedx_io.cc:
  Use my_global.h first
storage/federatedx/federatedx_io_mysql.cc:
  Use my_global.h first
storage/federatedx/federatedx_io_null.cc:
  Use my_global.h first
storage/federatedx/federatedx_txn.cc:
  Use my_global.h first
storage/heap/ha_heap.cc:
  Use my_global.h first
storage/innobase/handler/handler0alter.cc:
  Use my_global.h first
storage/maria/ha_maria.cc:
  Use my_global.h first
storage/maria/unittest/ma_maria_log_cleanup.c:
  Remove duplicated include files
storage/maria/unittest/test_file.c:
  Added comment
storage/myisam/ha_myisam.cc:
  Move sql_plugin.h first as this includes my_global.h
storage/myisammrg/ha_myisammrg.cc:
  Use my_global.h first
storage/oqgraph/oqgraph_thunk.cc:
  Use my_config.h and my_global.h first
  One could not include my_global.h before oqgraph_thunk.h (don't know why)
storage/spider/ha_spider.cc:
  Use my_global.h first
storage/spider/hs_client/config.cpp:
  Use my_global.h first
storage/spider/hs_client/escape.cpp:
  Use my_global.h first
storage/spider/hs_client/fatal.cpp:
  Use my_global.h first
storage/spider/hs_client/hstcpcli.cpp:
  Use my_global.h first
storage/spider/hs_client/socket.cpp:
  Use my_global.h first
storage/spider/hs_client/string_util.cpp:
  Use my_global.h first
storage/spider/spd_conn.cc:
  Use my_global.h first
storage/spider/spd_copy_tables.cc:
  Use my_global.h first
storage/spider/spd_db_conn.cc:
  Use my_global.h first
storage/spider/spd_db_handlersocket.cc:
  Use my_global.h first
storage/spider/spd_db_mysql.cc:
  Use my_global.h first
storage/spider/spd_db_oracle.cc:
  Use my_global.h first
storage/spider/spd_direct_sql.cc:
  Use my_global.h first
storage/spider/spd_i_s.cc:
  Use my_global.h first
storage/spider/spd_malloc.cc:
  Use my_global.h first
storage/spider/spd_param.cc:
  Use my_global.h first
storage/spider/spd_ping_table.cc:
  Use my_global.h first
storage/spider/spd_sys_table.cc:
  Use my_global.h first
storage/spider/spd_table.cc:
  Use my_global.h first
storage/spider/spd_trx.cc:
  Use my_global.h first
storage/xtradb/handler/handler0alter.cc:
  Use my_global.h first
storage/xtradb/handler/i_s.cc:
  Use my_global.h first
2014-09-30 20:31:14 +03:00

558 lines
14 KiB
C++

/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <my_global.h>
#include "sql_priv.h"
#include "unireg.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
#include "mysql.h"
#include "sp_head.h"
#include "sql_cursor.h"
#include "sp_rcontext.h"
#include "sp_pcontext.h"
#include "sql_select.h" // create_virtual_tmp_table
///////////////////////////////////////////////////////////////////////////
// sp_rcontext implementation.
///////////////////////////////////////////////////////////////////////////
sp_rcontext::sp_rcontext(const sp_pcontext *root_parsing_ctx,
Field *return_value_fld,
bool in_sub_stmt)
:end_partial_result_set(false),
m_root_parsing_ctx(root_parsing_ctx),
m_var_table(NULL),
m_return_value_fld(return_value_fld),
m_return_value_set(false),
m_in_sub_stmt(in_sub_stmt),
m_ccount(0)
{
}
sp_rcontext::~sp_rcontext()
{
if (m_var_table)
free_blobs(m_var_table);
// Leave m_handlers, m_handler_call_stack, m_var_items, m_cstack
// and m_case_expr_holders untouched.
// They are allocated in mem roots and will be freed accordingly.
}
sp_rcontext *sp_rcontext::create(THD *thd,
const sp_pcontext *root_parsing_ctx,
Field *return_value_fld)
{
sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
return_value_fld,
thd->in_sub_stmt);
if (!ctx)
return NULL;
if (ctx->alloc_arrays(thd) ||
ctx->init_var_table(thd) ||
ctx->init_var_items(thd))
{
delete ctx;
return NULL;
}
return ctx;
}
bool sp_rcontext::alloc_arrays(THD *thd)
{
{
size_t n= m_root_parsing_ctx->max_cursor_index();
m_cstack.reset(
static_cast<sp_cursor **> (
thd->alloc(n * sizeof (sp_cursor*))),
n);
}
{
size_t n= m_root_parsing_ctx->get_num_case_exprs();
m_case_expr_holders.reset(
static_cast<Item_cache **> (
thd->calloc(n * sizeof (Item_cache*))),
n);
}
return !m_cstack.array() || !m_case_expr_holders.array();
}
bool sp_rcontext::init_var_table(THD *thd)
{
List<Create_field> field_def_lst;
if (!m_root_parsing_ctx->max_var_index())
return false;
m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index());
if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
return true;
m_var_table->copy_blobs= true;
m_var_table->alias.set("", 0, m_var_table->alias.charset());
return false;
}
bool sp_rcontext::init_var_items(THD *thd)
{
uint num_vars= m_root_parsing_ctx->max_var_index();
m_var_items.reset(
static_cast<Item **> (
thd->alloc(num_vars * sizeof (Item *))),
num_vars);
if (!m_var_items.array())
return true;
for (uint idx = 0; idx < num_vars; ++idx)
{
if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
return true;
}
return false;
}
bool sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
{
DBUG_ASSERT(m_return_value_fld);
m_return_value_set = true;
return sp_eval_expr(thd, m_return_value_fld, return_value_item);
}
bool sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper,
sp_instr_cpush *i)
{
/*
We should create cursors in the callers arena, as
it could be (and usually is) used in several instructions.
*/
sp_cursor *c= new (callers_arena->mem_root) sp_cursor(lex_keeper, i);
if (c == NULL)
return true;
m_cstack[m_ccount++]= c;
return false;
}
void sp_rcontext::pop_cursors(uint count)
{
DBUG_ASSERT(m_ccount >= count);
while (count--)
delete m_cstack[--m_ccount];
}
bool sp_rcontext::push_handler(sp_handler *handler, uint first_ip)
{
/*
We should create handler entries in the callers arena, as
they could be (and usually are) used in several instructions.
*/
sp_handler_entry *he=
new (callers_arena->mem_root) sp_handler_entry(handler, first_ip);
if (he == NULL)
return true;
return m_handlers.append(he);
}
void sp_rcontext::pop_handlers(size_t count)
{
DBUG_ASSERT(m_handlers.elements() >= count);
for (size_t i= 0; i < count; ++i)
m_handlers.pop();
}
bool sp_rcontext::handle_sql_condition(THD *thd,
uint *ip,
const sp_instr *cur_spi)
{
DBUG_ENTER("sp_rcontext::handle_sql_condition");
/*
If this is a fatal sub-statement error, and this runtime
context corresponds to a sub-statement, no CONTINUE/EXIT
handlers from this context are applicable: try to locate one
in the outer scope.
*/
if (thd->is_fatal_sub_stmt_error && m_in_sub_stmt)
DBUG_RETURN(false);
Diagnostics_area *da= thd->get_stmt_da();
const sp_handler *found_handler= NULL;
const Sql_condition *found_condition= NULL;
if (thd->is_error())
{
found_handler=
cur_spi->m_ctx->find_handler(da->get_sqlstate(),
da->sql_errno(),
Sql_condition::WARN_LEVEL_ERROR);
if (found_handler)
found_condition= da->get_error_condition();
/*
Found condition can be NULL if the diagnostics area was full
when the error was raised. It can also be NULL if
Diagnostics_area::set_error_status(uint sql_error) was used.
In these cases, make a temporary Sql_condition here so the
error can be handled.
*/
if (!found_condition)
{
Sql_condition *condition=
new (callers_arena->mem_root) Sql_condition(callers_arena->mem_root);
condition->set(da->sql_errno(), da->get_sqlstate(),
Sql_condition::WARN_LEVEL_ERROR,
da->message());
found_condition= condition;
}
}
else if (da->current_statement_warn_count())
{
Diagnostics_area::Sql_condition_iterator it= da->sql_conditions();
const Sql_condition *c;
// Here we need to find the last warning/note from the stack.
// In MySQL most substantial warning is the last one.
// (We could have used a reverse iterator here if one existed)
while ((c= it++))
{
if (c->get_level() == Sql_condition::WARN_LEVEL_WARN ||
c->get_level() == Sql_condition::WARN_LEVEL_NOTE)
{
const sp_handler *handler=
cur_spi->m_ctx->find_handler(c->get_sqlstate(),
c->get_sql_errno(),
c->get_level());
if (handler)
{
found_handler= handler;
found_condition= c;
}
}
}
}
if (!found_handler)
DBUG_RETURN(false);
// At this point, we know that:
// - there is a pending SQL-condition (error or warning);
// - there is an SQL-handler for it.
DBUG_ASSERT(found_condition);
sp_handler_entry *handler_entry= NULL;
for (size_t i= 0; i < m_handlers.elements(); ++i)
{
sp_handler_entry *h= m_handlers.at(i);
if (h->handler == found_handler)
{
handler_entry= h;
break;
}
}
/*
handler_entry usually should not be NULL here, as that indicates
that the parser context thinks a HANDLER should be activated,
but the runtime context cannot find it.
However, this can happen (and this is in line with the Standard)
if SQL-condition has been raised before DECLARE HANDLER instruction
is processed.
For example:
CREATE PROCEDURE p()
BEGIN
DECLARE v INT DEFAULT 'get'; -- raises SQL-warning here
DECLARE EXIT HANDLER ... -- this handler does not catch the warning
END
*/
if (!handler_entry)
DBUG_RETURN(false);
// Mark active conditions so that they can be deleted when the handler exits.
da->mark_sql_conditions_for_removal();
uint continue_ip= handler_entry->handler->type == sp_handler::CONTINUE ?
cur_spi->get_cont_dest() : 0;
/* End aborted result set. */
if (end_partial_result_set)
thd->protocol->end_partial_result_set(thd);
/* Reset error state. */
thd->clear_error();
thd->killed= NOT_KILLED; // Some errors set thd->killed
// (e.g. "bad data").
/* Add a frame to handler-call-stack. */
Sql_condition_info *cond_info=
new (callers_arena->mem_root) Sql_condition_info(found_condition,
callers_arena);
Handler_call_frame *frame=
new (callers_arena->mem_root) Handler_call_frame(cond_info, continue_ip);
m_handler_call_stack.append(frame);
*ip= handler_entry->first_ip;
DBUG_RETURN(true);
}
uint sp_rcontext::exit_handler(Diagnostics_area *da)
{
DBUG_ENTER("sp_rcontext::exit_handler");
DBUG_ASSERT(m_handler_call_stack.elements() > 0);
Handler_call_frame *f= m_handler_call_stack.pop();
/*
Remove the SQL conditions that were present in DA when the
handler was activated.
*/
da->remove_marked_sql_conditions();
uint continue_ip= f->continue_ip;
DBUG_RETURN(continue_ip);
}
int sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
{
if (!value)
{
field->set_null();
return 0;
}
return sp_eval_expr(thd, field, value);
}
Item_cache *sp_rcontext::create_case_expr_holder(THD *thd,
const Item *item) const
{
Item_cache *holder;
Query_arena current_arena;
thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
holder= Item_cache::get_cache(item);
thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
return holder;
}
bool sp_rcontext::set_case_expr(THD *thd, int case_expr_id,
Item **case_expr_item_ptr)
{
Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr);
if (!case_expr_item)
return true;
if (!m_case_expr_holders[case_expr_id] ||
m_case_expr_holders[case_expr_id]->result_type() !=
case_expr_item->result_type())
{
m_case_expr_holders[case_expr_id]=
create_case_expr_holder(thd, case_expr_item);
}
m_case_expr_holders[case_expr_id]->store(case_expr_item);
m_case_expr_holders[case_expr_id]->cache_value();
return false;
}
///////////////////////////////////////////////////////////////////////////
// sp_cursor implementation.
///////////////////////////////////////////////////////////////////////////
sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
:m_lex_keeper(lex_keeper),
server_side_cursor(NULL),
m_i(i)
{
/*
currsor can't be stored in QC, so we should prevent opening QC for
try to write results which are absent.
*/
lex_keeper->disable_query_cache();
}
/*
Open an SP cursor
SYNOPSIS
open()
THD Thread handler
RETURN
0 in case of success, -1 otherwise
*/
int sp_cursor::open(THD *thd)
{
if (server_side_cursor)
{
my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN),
MYF(0));
return -1;
}
if (mysql_open_cursor(thd, &result, &server_side_cursor))
return -1;
return 0;
}
int sp_cursor::close(THD *thd)
{
if (! server_side_cursor)
{
my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
return -1;
}
destroy();
return 0;
}
void sp_cursor::destroy()
{
delete server_side_cursor;
server_side_cursor= NULL;
}
int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
{
if (! server_side_cursor)
{
my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
return -1;
}
if (vars->elements != result.get_field_count())
{
my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
return -1;
}
DBUG_EXECUTE_IF("bug23032_emit_warning",
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR,
ER(ER_UNKNOWN_ERROR)););
result.set_spvar_list(vars);
/* Attempt to fetch one row */
if (server_side_cursor->is_open())
server_side_cursor->fetch(1);
/*
If the cursor was pointing after the last row, the fetch will
close it instead of sending any rows.
*/
if (! server_side_cursor->is_open())
{
my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
return -1;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
// sp_cursor::Select_fetch_into_spvars implementation.
///////////////////////////////////////////////////////////////////////////
int sp_cursor::Select_fetch_into_spvars::prepare(List<Item> &fields,
SELECT_LEX_UNIT *u)
{
/*
Cache the number of columns in the result set in order to easily
return an error if column count does not match value count.
*/
field_count= fields.elements;
return select_result_interceptor::prepare(fields, u);
}
int sp_cursor::Select_fetch_into_spvars::send_data(List<Item> &items)
{
List_iterator_fast<sp_variable> spvar_iter(*spvar_list);
List_iterator_fast<Item> item_iter(items);
sp_variable *spvar;
Item *item;
/* Must be ensured by the caller */
DBUG_ASSERT(spvar_list->elements == items.elements);
/*
Assign the row fetched from a server side cursor to stored
procedure variables.
*/
for (; spvar= spvar_iter++, item= item_iter++; )
{
if (thd->spcont->set_variable(thd, spvar->offset, &item))
return true;
}
return false;
}