summaryrefslogtreecommitdiff
path: root/sql/sp_head.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r--sql/sp_head.cc217
1 files changed, 147 insertions, 70 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 6d982aac937..d23b5e88baa 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -412,6 +412,26 @@ Item *THD::sp_fix_func_item(Item **it_addr)
/**
+ Prepare an Item for evaluation as an assignment source,
+ for assignment to the given target.
+
+ @param to - the assignment target
+ @param it_addr - a pointer on item refernce
+
+ @retval - NULL on error
+ @retval - a prepared item pointer on success
+*/
+Item *THD::sp_fix_func_item_for_assignment(const Field *to, Item **it_addr)
+{
+ DBUG_ENTER("THD::sp_fix_func_item_for_assignment");
+ Item *res= sp_fix_func_item(it_addr);
+ if (res && (!res->check_assignability_to(to, false)))
+ DBUG_RETURN(res);
+ DBUG_RETURN(NULL);
+}
+
+
+/**
Evaluate an expression and store the result in the field.
@param result_field the field to store the result
@@ -2080,7 +2100,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
/* Arguments must be fixed in Item_func_sp::fix_fields */
DBUG_ASSERT(argp[arg_no]->fixed());
- if ((err_status= (*func_ctx)->set_parameter(thd, arg_no, &(argp[arg_no]))))
+ err_status= bind_input_param(thd, argp[arg_no], arg_no, *func_ctx, TRUE);
+ if (err_status)
goto err_with_cleanup;
}
@@ -2203,6 +2224,19 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
err_status= TRUE;
}
+ else
+ {
+ /*
+ Copy back all OUT or INOUT values to the previous frame, or
+ set global user variables
+ */
+ for (arg_no= 0; arg_no < argcount; arg_no++)
+ {
+ err_status= bind_output_param(thd, argp[arg_no], arg_no, octx, *func_ctx);
+ if (err_status)
+ break;
+ }
+ }
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -2325,50 +2359,9 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!arg_item)
break;
- sp_variable *spvar= m_pcont->find_variable(i);
-
- if (!spvar)
- continue;
-
- if (spvar->mode != sp_variable::MODE_IN)
- {
- Settable_routine_parameter *srp=
- arg_item->get_settable_routine_parameter();
-
- if (!srp)
- {
- my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, ErrConvDQName(this).ptr());
- err_status= TRUE;
- break;
- }
-
- srp->set_required_privilege(spvar->mode == sp_variable::MODE_INOUT);
- }
-
- if (spvar->mode == sp_variable::MODE_OUT)
- {
- Item_null *null_item= new (thd->mem_root) Item_null(thd);
- Item *tmp_item= null_item;
-
- if (!null_item ||
- nctx->set_parameter(thd, i, &tmp_item))
- {
- DBUG_PRINT("error", ("set variable failed"));
- err_status= TRUE;
- break;
- }
- }
- else
- {
- if (nctx->set_parameter(thd, i, it_args.ref()))
- {
- DBUG_PRINT("error", ("set variable 2 failed"));
- err_status= TRUE;
- break;
- }
- }
-
- TRANSACT_TRACKER(add_trx_state_from_thd(thd));
+ err_status= bind_input_param(thd, arg_item, i, nctx, FALSE);
+ if (err_status)
+ break;
}
/*
@@ -2478,31 +2471,9 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!arg_item)
break;
- sp_variable *spvar= m_pcont->find_variable(i);
-
- if (spvar->mode == sp_variable::MODE_IN)
- continue;
-
- Settable_routine_parameter *srp=
- arg_item->get_settable_routine_parameter();
-
- DBUG_ASSERT(srp);
-
- if (srp->set_value(thd, octx, nctx->get_variable_addr(i)))
- {
- DBUG_PRINT("error", ("set value failed"));
- err_status= TRUE;
+ err_status= bind_output_param(thd, arg_item, i, octx, nctx);
+ if (err_status)
break;
- }
-
- Send_field *out_param_info= new (thd->mem_root) Send_field(thd, nctx->get_parameter(i));
- out_param_info->db_name= m_db;
- out_param_info->table_name= m_name;
- out_param_info->org_table_name= m_name;
- out_param_info->col_name= spvar->name;
- out_param_info->org_col_name= spvar->name;
-
- srp->set_out_param_info(out_param_info);
}
}
@@ -2533,6 +2504,112 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
DBUG_RETURN(err_status);
}
+bool
+sp_head::bind_input_param(THD *thd,
+ Item *arg_item,
+ uint arg_no,
+ sp_rcontext *nctx,
+ bool is_function)
+{
+ DBUG_ENTER("sp_head::bind_input_param");
+
+ sp_variable *spvar= m_pcont->find_variable(arg_no);
+ if (!spvar)
+ DBUG_RETURN(FALSE);
+
+ if (spvar->mode != sp_variable::MODE_IN)
+ {
+ Settable_routine_parameter *srp=
+ arg_item->get_settable_routine_parameter();
+
+ if (!srp)
+ {
+ my_error(ER_SP_NOT_VAR_ARG, MYF(0), arg_no+1, ErrConvDQName(this).ptr());
+ DBUG_RETURN(TRUE);
+ }
+
+ if (is_function)
+ {
+ /*
+ Check if the function is called from SELECT/INSERT/UPDATE/DELETE query
+ and parameter is OUT or INOUT.
+ If yes, it is an invalid call - throw error.
+ */
+ if (thd->lex->sql_command == SQLCOM_SELECT ||
+ thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->sql_command == SQLCOM_INSERT_SELECT ||
+ thd->lex->sql_command == SQLCOM_UPDATE ||
+ thd->lex->sql_command == SQLCOM_DELETE)
+ {
+ my_error(ER_SF_OUT_INOUT_ARG_NOT_ALLOWED, MYF(0), arg_no+1, m_name.str);
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ srp->set_required_privilege(spvar->mode == sp_variable::MODE_INOUT);
+ }
+
+ if (spvar->mode == sp_variable::MODE_OUT)
+ {
+ Item_null *null_item= new (thd->mem_root) Item_null(thd);
+ Item *tmp_item= null_item;
+
+ if (!null_item ||
+ nctx->set_parameter(thd, arg_no, &tmp_item))
+ {
+ DBUG_PRINT("error", ("set variable failed"));
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ {
+ if (nctx->set_parameter(thd, arg_no, &arg_item))
+ {
+ DBUG_PRINT("error", ("set variable 2 failed"));
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ TRANSACT_TRACKER(add_trx_state_from_thd(thd));
+
+ DBUG_RETURN(FALSE);
+}
+
+bool
+sp_head::bind_output_param(THD *thd,
+ Item *arg_item,
+ uint arg_no,
+ sp_rcontext *octx,
+ sp_rcontext *nctx)
+{
+ DBUG_ENTER("sp_head::bind_output_param");
+
+ sp_variable *spvar= m_pcont->find_variable(arg_no);
+ if (spvar->mode == sp_variable::MODE_IN)
+ DBUG_RETURN(FALSE);
+
+ Settable_routine_parameter *srp=
+ arg_item->get_settable_routine_parameter();
+
+ DBUG_ASSERT(srp);
+
+ if (srp->set_value(thd, octx, nctx->get_variable_addr(arg_no)))
+ {
+ DBUG_PRINT("error", ("set value failed"));
+ DBUG_RETURN(TRUE);
+ }
+
+ Send_field *out_param_info= new (thd->mem_root) Send_field(thd, nctx->get_parameter(arg_no));
+ out_param_info->db_name= m_db;
+ out_param_info->table_name= m_name;
+ out_param_info->org_table_name= m_name;
+ out_param_info->col_name= spvar->name;
+ out_param_info->org_col_name= spvar->name;
+
+ srp->set_out_param_info(out_param_info);
+
+ DBUG_RETURN(FALSE);
+}
/**
Reset lex during parsing, before we parse a sub statement.
@@ -4072,7 +4149,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= thd->sp_prepare_func_item(&m_expr);
+ it= thd->sp_prepare_func_item(&m_expr, 1);
if (! it)
{
res= -1;