mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge bodhi.(none):/opt/local/work/mysql-5.0-runtime
into bodhi.(none):/opt/local/work/mysql-5.1-runtime
This commit is contained in:
221
sql/table.cc
221
sql/table.cc
@ -2849,15 +2849,144 @@ void st_table::reset_item_list(List<Item> *item_list) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the initial purpose of this TABLE_LIST object in the list of
|
||||
used tables. We need to track this information on table-by-
|
||||
table basis, since when this table becomes an element of the
|
||||
pre-locked list, it's impossible to identify which SQL
|
||||
sub-statement it has been originally used in.
|
||||
|
||||
E.g.:
|
||||
|
||||
User request: SELECT * FROM t1 WHERE f1();
|
||||
FUNCTION f1(): DELETE FROM t2; RETURN 1;
|
||||
BEFORE DELETE trigger on t2: INSERT INTO t3 VALUES (old.a);
|
||||
|
||||
For this user request, the pre-locked list will contain t1, t2, t3
|
||||
table elements, each needed for different DML.
|
||||
|
||||
This method is called immediately after parsing for tables
|
||||
of the table list of the top-level select lex.
|
||||
|
||||
The trigger event map is updated to reflect INSERT, UPDATE, DELETE,
|
||||
REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE ..
|
||||
REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE
|
||||
clause.
|
||||
*/
|
||||
|
||||
void
|
||||
TABLE_LIST::set_trg_event_type(const st_lex *lex)
|
||||
{
|
||||
enum trg_event_type trg_event;
|
||||
|
||||
/*
|
||||
Some auxiliary operations
|
||||
(e.g. GRANT processing) create TABLE_LIST instances outside
|
||||
the parser. Additionally, some commands (e.g. OPTIMIZE) change
|
||||
the lock type for a table only after parsing is done. Luckily,
|
||||
these do not fire triggers and do not need to pre-load them.
|
||||
For these TABLE_LISTs set_trg_event_type is never called, and
|
||||
trg_event_map is always empty. That means that the pre-locking
|
||||
algorithm will ignore triggers defined on these tables, if
|
||||
any, and the execution will either fail with an assert in
|
||||
sql_trigger.cc or with an error that a used table was not
|
||||
pre-locked, in case of a production build.
|
||||
|
||||
TODO: this usage pattern creates unnecessary module dependencies
|
||||
and should be rewritten to go through the parser.
|
||||
Table list instances created outside the parser in most cases
|
||||
refer to mysql.* system tables. It is not allowed to have
|
||||
a trigger on a system table, but keeping track of
|
||||
initialization provides extra safety in case this limitation
|
||||
is circumvented.
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a fast check to filter out statements that do
|
||||
not change data, or tables on the right side, in case of
|
||||
INSERT .. SELECT, CREATE TABLE .. SELECT and so on.
|
||||
Here we also filter out OPTIMIZE statement and non-updateable
|
||||
views, for which lock_type is TL_UNLOCK or TL_READ after
|
||||
parsing.
|
||||
*/
|
||||
if (static_cast<int>(lock_type) < static_cast<int>(TL_WRITE_ALLOW_WRITE))
|
||||
return;
|
||||
|
||||
switch (lex->sql_command) {
|
||||
/*
|
||||
Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE
|
||||
clause, it will be handled later in this method.
|
||||
*/
|
||||
case SQLCOM_INSERT: /* fall through */
|
||||
case SQLCOM_INSERT_SELECT:
|
||||
/*
|
||||
LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT
|
||||
triggers.
|
||||
If the statement also has REPLACE clause, it will be
|
||||
handled later in this method.
|
||||
*/
|
||||
case SQLCOM_LOAD: /* fall through */
|
||||
/*
|
||||
REPLACE is semantically equivalent to INSERT. In case
|
||||
of a primary or unique key conflict, it deletes the old
|
||||
record and inserts a new one. So we also may need to
|
||||
fire ON DELETE triggers. This functionality is handled
|
||||
later in this method.
|
||||
*/
|
||||
case SQLCOM_REPLACE: /* fall through */
|
||||
case SQLCOM_REPLACE_SELECT:
|
||||
/*
|
||||
CREATE TABLE ... SELECT defaults to INSERT if the table or
|
||||
view already exists. REPLACE option of CREATE TABLE ...
|
||||
REPLACE SELECT is handled later in this method.
|
||||
*/
|
||||
case SQLCOM_CREATE_TABLE:
|
||||
trg_event= TRG_EVENT_INSERT;
|
||||
break;
|
||||
/* Basic update and multi-update */
|
||||
case SQLCOM_UPDATE: /* fall through */
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
trg_event= TRG_EVENT_UPDATE;
|
||||
break;
|
||||
/* Basic delete and multi-delete */
|
||||
case SQLCOM_DELETE: /* fall through */
|
||||
case SQLCOM_DELETE_MULTI:
|
||||
trg_event= TRG_EVENT_DELETE;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
OK to return, since value of 'duplicates' is irrelevant
|
||||
for non-updating commands.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
trg_event_map|= static_cast<uint8>(1 << static_cast<int>(trg_event));
|
||||
|
||||
switch (lex->duplicates) {
|
||||
case DUP_UPDATE:
|
||||
trg_event= TRG_EVENT_UPDATE;
|
||||
break;
|
||||
case DUP_REPLACE:
|
||||
trg_event= TRG_EVENT_DELETE;
|
||||
break;
|
||||
case DUP_ERROR:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
trg_event_map|= static_cast<uint8>(1 << static_cast<int>(trg_event));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
calculate md5 of query
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::calc_md5()
|
||||
TABLE_LIST::calc_md5()
|
||||
buffer buffer for md5 writing
|
||||
*/
|
||||
|
||||
void st_table_list::calc_md5(char *buffer)
|
||||
void TABLE_LIST::calc_md5(char *buffer)
|
||||
{
|
||||
my_MD5_CTX context;
|
||||
uchar digest[16];
|
||||
@ -2882,10 +3011,10 @@ void st_table_list::calc_md5(char *buffer)
|
||||
it (it is a kind of optimisation)
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::set_underlying_merge()
|
||||
TABLE_LIST::set_underlying_merge()
|
||||
*/
|
||||
|
||||
void st_table_list::set_underlying_merge()
|
||||
void TABLE_LIST::set_underlying_merge()
|
||||
{
|
||||
TABLE_LIST *tbl;
|
||||
|
||||
@ -2920,7 +3049,7 @@ void st_table_list::set_underlying_merge()
|
||||
setup fields of placeholder of merged VIEW
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::setup_underlying()
|
||||
TABLE_LIST::setup_underlying()
|
||||
thd - thread handler
|
||||
|
||||
DESCRIPTION
|
||||
@ -2933,9 +3062,9 @@ void st_table_list::set_underlying_merge()
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
bool st_table_list::setup_underlying(THD *thd)
|
||||
bool TABLE_LIST::setup_underlying(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::setup_underlying");
|
||||
DBUG_ENTER("TABLE_LIST::setup_underlying");
|
||||
|
||||
if (!field_translation && merge_underlying_list)
|
||||
{
|
||||
@ -2998,7 +3127,7 @@ bool st_table_list::setup_underlying(THD *thd)
|
||||
Prepare where expression of view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prep_where()
|
||||
TABLE_LIST::prep_where()
|
||||
thd - thread handler
|
||||
conds - condition of this JOIN
|
||||
no_where_clause - do not build WHERE or ON outer qwery do not need it
|
||||
@ -3012,10 +3141,10 @@ bool st_table_list::setup_underlying(THD *thd)
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
bool st_table_list::prep_where(THD *thd, Item **conds,
|
||||
bool TABLE_LIST::prep_where(THD *thd, Item **conds,
|
||||
bool no_where_clause)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prep_where");
|
||||
DBUG_ENTER("TABLE_LIST::prep_where");
|
||||
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
@ -3115,7 +3244,7 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded)
|
||||
Prepare check option expression of table
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prep_check_option()
|
||||
TABLE_LIST::prep_check_option()
|
||||
thd - thread handler
|
||||
check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE,
|
||||
VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED)
|
||||
@ -3130,16 +3259,16 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded)
|
||||
This method builds check option condition to use it later on
|
||||
every call (usual execution or every SP/PS call).
|
||||
This method have to be called after WHERE preparation
|
||||
(st_table_list::prep_where)
|
||||
(TABLE_LIST::prep_where)
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prep_check_option");
|
||||
DBUG_ENTER("TABLE_LIST::prep_check_option");
|
||||
bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED;
|
||||
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
@ -3198,12 +3327,12 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
Hide errors which show view underlying table information
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::hide_view_error()
|
||||
TABLE_LIST::hide_view_error()
|
||||
thd thread handler
|
||||
|
||||
*/
|
||||
|
||||
void st_table_list::hide_view_error(THD *thd)
|
||||
void TABLE_LIST::hide_view_error(THD *thd)
|
||||
{
|
||||
/* Hide "Unknown column" or "Unknown function" error */
|
||||
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
|
||||
@ -3234,7 +3363,7 @@ void st_table_list::hide_view_error(THD *thd)
|
||||
table_to_find (TABLE)
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::find_underlying_table()
|
||||
TABLE_LIST::find_underlying_table()
|
||||
table_to_find table to find
|
||||
|
||||
RETURN
|
||||
@ -3242,7 +3371,7 @@ void st_table_list::hide_view_error(THD *thd)
|
||||
found table reference
|
||||
*/
|
||||
|
||||
st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
|
||||
TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find)
|
||||
{
|
||||
/* is this real table and table which we are looking for? */
|
||||
if (table == table_to_find && merge_underlying_list == 0)
|
||||
@ -3261,10 +3390,10 @@ st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
|
||||
cleunup items belonged to view fields translation table
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::cleanup_items()
|
||||
TABLE_LIST::cleanup_items()
|
||||
*/
|
||||
|
||||
void st_table_list::cleanup_items()
|
||||
void TABLE_LIST::cleanup_items()
|
||||
{
|
||||
if (!field_translation)
|
||||
return;
|
||||
@ -3280,7 +3409,7 @@ void st_table_list::cleanup_items()
|
||||
check CHECK OPTION condition
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::view_check_option()
|
||||
TABLE_LIST::view_check_option()
|
||||
ignore_failure ignore check option fail
|
||||
|
||||
RETURN
|
||||
@ -3289,7 +3418,7 @@ void st_table_list::cleanup_items()
|
||||
VIEW_CHECK_SKIP FAILED, but continue
|
||||
*/
|
||||
|
||||
int st_table_list::view_check_option(THD *thd, bool ignore_failure)
|
||||
int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure)
|
||||
{
|
||||
if (check_option && check_option->val_int() == 0)
|
||||
{
|
||||
@ -3314,7 +3443,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
|
||||
table belong to given mask
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::check_single_table()
|
||||
TABLE_LIST::check_single_table()
|
||||
table_arg reference on variable where to store found table
|
||||
(should be 0 on call, to find table, or point to table for
|
||||
unique test)
|
||||
@ -3326,9 +3455,9 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
|
||||
TRUE found several tables
|
||||
*/
|
||||
|
||||
bool st_table_list::check_single_table(st_table_list **table_arg,
|
||||
bool TABLE_LIST::check_single_table(TABLE_LIST **table_arg,
|
||||
table_map map,
|
||||
st_table_list *view_arg)
|
||||
TABLE_LIST *view_arg)
|
||||
{
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
@ -3361,7 +3490,7 @@ bool st_table_list::check_single_table(st_table_list **table_arg,
|
||||
TRUE - out of memory
|
||||
*/
|
||||
|
||||
bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
||||
bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root)
|
||||
{
|
||||
if (table)
|
||||
{
|
||||
@ -3385,7 +3514,7 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
||||
Test if this is a leaf with respect to name resolution.
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::is_leaf_for_name_resolution()
|
||||
TABLE_LIST::is_leaf_for_name_resolution()
|
||||
|
||||
DESCRIPTION
|
||||
A table reference is a leaf with respect to name resolution if
|
||||
@ -3397,7 +3526,7 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
||||
RETURN
|
||||
TRUE if a leaf, FALSE otherwise.
|
||||
*/
|
||||
bool st_table_list::is_leaf_for_name_resolution()
|
||||
bool TABLE_LIST::is_leaf_for_name_resolution()
|
||||
{
|
||||
return (view || is_natural_join || is_join_columns_complete ||
|
||||
!nested_join);
|
||||
@ -3409,7 +3538,7 @@ bool st_table_list::is_leaf_for_name_resolution()
|
||||
respect to name resolution.
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::first_leaf_for_name_resolution()
|
||||
TABLE_LIST::first_leaf_for_name_resolution()
|
||||
|
||||
DESCRIPTION
|
||||
Given that 'this' is a nested table reference, recursively walk
|
||||
@ -3427,7 +3556,7 @@ bool st_table_list::is_leaf_for_name_resolution()
|
||||
else return 'this'
|
||||
*/
|
||||
|
||||
TABLE_LIST *st_table_list::first_leaf_for_name_resolution()
|
||||
TABLE_LIST *TABLE_LIST::first_leaf_for_name_resolution()
|
||||
{
|
||||
TABLE_LIST *cur_table_ref;
|
||||
NESTED_JOIN *cur_nested_join;
|
||||
@ -3467,7 +3596,7 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution()
|
||||
respect to name resolution.
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::last_leaf_for_name_resolution()
|
||||
TABLE_LIST::last_leaf_for_name_resolution()
|
||||
|
||||
DESCRIPTION
|
||||
Given that 'this' is a nested table reference, recursively walk
|
||||
@ -3485,7 +3614,7 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution()
|
||||
- else - 'this'
|
||||
*/
|
||||
|
||||
TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
|
||||
TABLE_LIST *TABLE_LIST::last_leaf_for_name_resolution()
|
||||
{
|
||||
TABLE_LIST *cur_table_ref= this;
|
||||
NESTED_JOIN *cur_nested_join;
|
||||
@ -3527,7 +3656,7 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
|
||||
want_access Acess which we require
|
||||
*/
|
||||
|
||||
void st_table_list::register_want_access(ulong want_access)
|
||||
void TABLE_LIST::register_want_access(ulong want_access)
|
||||
{
|
||||
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
|
||||
want_access&= ~SHOW_VIEW_ACL;
|
||||
@ -3546,7 +3675,7 @@ void st_table_list::register_want_access(ulong want_access)
|
||||
Load security context information for this view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prepare_view_securety_context()
|
||||
TABLE_LIST::prepare_view_securety_context()
|
||||
thd [in] thread handler
|
||||
|
||||
RETURN
|
||||
@ -3555,9 +3684,9 @@ void st_table_list::register_want_access(ulong want_access)
|
||||
*/
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
bool st_table_list::prepare_view_securety_context(THD *thd)
|
||||
bool TABLE_LIST::prepare_view_securety_context(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prepare_view_securety_context");
|
||||
DBUG_ENTER("TABLE_LIST::prepare_view_securety_context");
|
||||
DBUG_PRINT("enter", ("table: %s", alias));
|
||||
|
||||
DBUG_ASSERT(!prelocking_placeholder && view);
|
||||
@ -3606,17 +3735,17 @@ bool st_table_list::prepare_view_securety_context(THD *thd)
|
||||
Find security context of current view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::find_view_security_context()
|
||||
TABLE_LIST::find_view_security_context()
|
||||
thd [in] thread handler
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *st_table_list::find_view_security_context(THD *thd)
|
||||
Security_context *TABLE_LIST::find_view_security_context(THD *thd)
|
||||
{
|
||||
Security_context *sctx;
|
||||
TABLE_LIST *upper_view= this;
|
||||
DBUG_ENTER("st_table_list::find_view_security_context");
|
||||
DBUG_ENTER("TABLE_LIST::find_view_security_context");
|
||||
|
||||
DBUG_ASSERT(view);
|
||||
while (upper_view && !upper_view->view_suid)
|
||||
@ -3645,7 +3774,7 @@ Security_context *st_table_list::find_view_security_context(THD *thd)
|
||||
Prepare security context and load underlying tables priveleges for view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prepare_security()
|
||||
TABLE_LIST::prepare_security()
|
||||
thd [in] thread handler
|
||||
|
||||
RETURN
|
||||
@ -3653,11 +3782,11 @@ Security_context *st_table_list::find_view_security_context(THD *thd)
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool st_table_list::prepare_security(THD *thd)
|
||||
bool TABLE_LIST::prepare_security(THD *thd)
|
||||
{
|
||||
List_iterator_fast<TABLE_LIST> tb(*view_tables);
|
||||
TABLE_LIST *tbl;
|
||||
DBUG_ENTER("st_table_list::prepare_security");
|
||||
DBUG_ENTER("TABLE_LIST::prepare_security");
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *save_security_ctx= thd->security_ctx;
|
||||
|
||||
@ -4406,10 +4535,10 @@ void st_table::mark_columns_needed_for_insert()
|
||||
Cleanup this table for re-execution.
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::reinit_before_use()
|
||||
TABLE_LIST::reinit_before_use()
|
||||
*/
|
||||
|
||||
void st_table_list::reinit_before_use(THD *thd)
|
||||
void TABLE_LIST::reinit_before_use(THD *thd)
|
||||
{
|
||||
/*
|
||||
Reset old pointers to TABLEs: they are not valid since the tables
|
||||
@ -4436,7 +4565,7 @@ void st_table_list::reinit_before_use(THD *thd)
|
||||
Return subselect that contains the FROM list this table is taken from
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::containing_subselect()
|
||||
TABLE_LIST::containing_subselect()
|
||||
|
||||
RETURN
|
||||
Subselect item for the subquery that contains the FROM list
|
||||
@ -4445,7 +4574,7 @@ void st_table_list::reinit_before_use(THD *thd)
|
||||
|
||||
*/
|
||||
|
||||
Item_subselect *st_table_list::containing_subselect()
|
||||
Item_subselect *TABLE_LIST::containing_subselect()
|
||||
{
|
||||
return (select_lex ? select_lex->master_unit()->item : 0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user