mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
Allowing prepared statements in stored functions when
a stored function is used in an assignment right hand.
Both DEFAULT clause of a variable initialization and
the right side of the SET statement are supported:
CREATE PROCEDURE p1()
BEGIN
-- case 1: DEFAULT clause
DECLARE spvar1 INT DEFAULT f1_with_ps(); -- OK
-- case 2: SP variable assignment statement
DECLARE spvar2 INT;
SET spvar2= f1_with_ps(); -- OK
END;
- Only assignments to SP variables works for now:
* SET spvar= func_with_ps(); -- OK
* SET @uvar= func_with_ps(); -- Error
- Only bare function calls are supported for now. Using a function in
an expression does not make it PS-safe yet:
SET v= f1()+0;
- The parser now does not reject PS statements in stored functions.
PS applicability in stored functions is now detected at run time.
Note, PS statements in triggers are still prohibited by the parser.
- Functions with PS do not acquire MDL locks on tables, and no MDL is
taken on the routines themselves either. They work like procedures in
terms of table opening and routine locking: a concurrent DROP FUNCTION
can complete while such a function is executing.
- Functions with PS are not replicated as a single `SELECT f1()` call.
They are replicated per-statement, like procedures.
Helper changes:
- Changing the return result for LEX::sp_variable_declarations_init()
from void to bool to catch errors in the caller properly.
Misc:
- This patch incorporates fixes for the following bugs found during debugging:
MDEV-40224,MDEV-40225,MDEV-40226,MDEV-40227,MDEV-40240,
MDEV-40285,MDEV-40288,MDEV-40315,MDEV-40318,MDEV-40890,MDEV-40900,
MDEV-40901,MDEV-40913,MDEV-40914,MDEV-41013,MDEV-41015,MDEV-41019
Assisted-by: Claude - reviews and minor clean-ups
146 lines
4.6 KiB
C++
146 lines
4.6 KiB
C++
#ifndef ITEM_ROW_INCLUDED
|
|
#define ITEM_ROW_INCLUDED
|
|
|
|
#include "item_composite.h"
|
|
|
|
/*
|
|
Copyright (c) 2002, 2013, Oracle and/or its affiliates.
|
|
|
|
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-1335 USA */
|
|
|
|
/**
|
|
Row items used for comparing rows and IN operations on rows:
|
|
|
|
@verbatim
|
|
(a, b, c) > (10, 10, 30)
|
|
(a, b, c) = (select c, d, e, from t1 where x=12)
|
|
(a, b, c) IN ((1,2,2), (3,4,5), (6,7,8)
|
|
(a, b, c) IN (select c, d, e, from t1)
|
|
@endverbatim
|
|
*/
|
|
|
|
|
|
/**
|
|
Item which stores (x,y,...) and ROW(x,y,...).
|
|
Note that this can be recursive: ((x,y),(z,t)) is a ROW of ROWs.
|
|
*/
|
|
class Item_row: public Item_composite,
|
|
private Used_tables_and_const_cache
|
|
{
|
|
table_map not_null_tables_cache;
|
|
/**
|
|
If elements are made only of constants, of which one or more are
|
|
NULL. For example, this item is (1,2,NULL), or ( (1,NULL), (2,3) ).
|
|
*/
|
|
bool with_null;
|
|
public:
|
|
Item_row(THD *thd, List<Item> &list)
|
|
:Item_composite(thd, list),
|
|
not_null_tables_cache(0), with_null(0)
|
|
{ }
|
|
Item_row(THD *thd, Item_row *row)
|
|
:Item_composite(thd, static_cast<Item_args*>(row)),
|
|
Used_tables_and_const_cache(),
|
|
not_null_tables_cache(0), with_null(0)
|
|
{ }
|
|
|
|
const Type_handler *type_handler() const override { return &type_handler_row; }
|
|
Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
|
|
const Tmp_field_param *param) override
|
|
{
|
|
return NULL; // Check with Vicentiu why it's called for Item_row
|
|
}
|
|
bool is_null() override { return null_value; }
|
|
bool fix_fields(THD *thd, Item **ref) override;
|
|
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge)
|
|
override;
|
|
void cleanup() override;
|
|
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
|
|
List<Item> &fields, uint flags) override;
|
|
table_map used_tables() const override { return used_tables_cache; };
|
|
bool const_item() const override { return const_item_cache; };
|
|
void update_used_tables() override
|
|
{
|
|
used_tables_and_const_cache_init();
|
|
used_tables_and_const_cache_update_and_join(arg_count, args);
|
|
}
|
|
table_map not_null_tables() const override { return not_null_tables_cache; }
|
|
void print(String *str, enum_query_type query_type) override;
|
|
|
|
bool walk(Item_processor processor, void *arg,
|
|
item_walk_flags flags) override
|
|
{
|
|
if (walk_args(processor, arg, flags))
|
|
return true;
|
|
return (this->*processor)(arg);
|
|
}
|
|
Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override;
|
|
bool eval_not_null_tables(void *opt_arg) override;
|
|
bool find_not_null_fields(table_map allowed) override;
|
|
|
|
uint cols() const override { return arg_count; }
|
|
Item* element_index(uint i) override { return args[i]; }
|
|
Item** addr(uint i) override { return args + i; }
|
|
bool check_cols(uint c) override;
|
|
bool null_inside() override { return with_null; };
|
|
void bring_value() override;
|
|
|
|
void set_in_ps_safe_context() override
|
|
{
|
|
Item::set_in_ps_safe_context();
|
|
Item_args::set_in_ps_safe_context_args();
|
|
}
|
|
|
|
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
|
|
override
|
|
{
|
|
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
|
|
return this;
|
|
}
|
|
|
|
bool excl_dep_on_table(table_map tab_map) override
|
|
{
|
|
return Item_args::excl_dep_on_table(tab_map);
|
|
}
|
|
|
|
bool excl_dep_on_grouping_fields(st_select_lex *sel) override
|
|
{
|
|
return Item_args::excl_dep_on_grouping_fields(sel);
|
|
}
|
|
|
|
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override
|
|
{
|
|
return Item_args::excl_dep_on_in_subq_left_part(subq_pred);
|
|
}
|
|
|
|
bool check_vcol_func_processor(void *arg) override {return FALSE; }
|
|
|
|
protected:
|
|
bool ora_join_processor(void *arg) override
|
|
{
|
|
if (with_ora_join())
|
|
{
|
|
// Oracle join operator is used inside rows.
|
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC, MYF(0));
|
|
return(TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
Item *shallow_copy(THD *thd) const override
|
|
{ return get_item_copy<Item_row>(thd, this); }
|
|
Item *deep_copy(THD *thd) const override;
|
|
};
|
|
|
|
#endif /* ITEM_ROW_INCLUDED */
|