Merge mysql.com:/home/timka/mysql/src/5.0-2486
into mysql.com:/home/timka/mysql/src/5.1-dbg sql/item.cc: Auto merged sql/item.h: Auto merged sql/mysql_priv.h: Auto merged sql/sql_acl.cc: Auto merged sql/sql_acl.h: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.h: Auto merged sql/sql_base.cc: SCCS merged sql/table.cc: SCCS merged
This commit is contained in:
commit
f1ac6bb975
@ -5207,7 +5207,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
|
|||||||
set field_idx properly.
|
set field_idx properly.
|
||||||
*/
|
*/
|
||||||
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
|
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
|
||||||
0, 0, &field_idx, 0);
|
0, &field_idx);
|
||||||
thd->set_query_id= save_set_query_id;
|
thd->set_query_id= save_set_query_id;
|
||||||
triggers= table->triggers;
|
triggers= table->triggers;
|
||||||
}
|
}
|
||||||
|
42
sql/item.h
42
sql/item.h
@ -326,6 +326,48 @@ struct Name_resolution_context: Sql_alloc
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Store and restore the current state of a name resolution context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Name_resolution_context_state
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
TABLE_LIST *save_table_list;
|
||||||
|
TABLE_LIST *save_first_name_resolution_table;
|
||||||
|
TABLE_LIST *save_next_name_resolution_table;
|
||||||
|
bool save_resolve_in_select_list;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TABLE_LIST *save_next_local;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Save the state of a name resolution context. */
|
||||||
|
void save_state(Name_resolution_context *context, TABLE_LIST *table_list)
|
||||||
|
{
|
||||||
|
save_table_list= context->table_list;
|
||||||
|
save_first_name_resolution_table= context->first_name_resolution_table;
|
||||||
|
save_next_name_resolution_table= (context->first_name_resolution_table) ?
|
||||||
|
context->first_name_resolution_table->
|
||||||
|
next_name_resolution_table :
|
||||||
|
NULL;
|
||||||
|
save_resolve_in_select_list= context->resolve_in_select_list;
|
||||||
|
save_next_local= table_list->next_local;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore a name resolution context from saved state. */
|
||||||
|
void restore_state(Name_resolution_context *context, TABLE_LIST *table_list)
|
||||||
|
{
|
||||||
|
table_list->next_local= save_next_local;
|
||||||
|
context->table_list= save_table_list;
|
||||||
|
context->first_name_resolution_table= save_first_name_resolution_table;
|
||||||
|
if (context->first_name_resolution_table)
|
||||||
|
context->first_name_resolution_table->
|
||||||
|
next_name_resolution_table= save_next_name_resolution_table;
|
||||||
|
context->resolve_in_select_list= save_resolve_in_select_list;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
typedef bool (Item::*Item_processor)(byte *arg);
|
typedef bool (Item::*Item_processor)(byte *arg);
|
||||||
|
@ -820,18 +820,15 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||||||
bool check_privileges, bool register_tree_change);
|
bool check_privileges, bool register_tree_change);
|
||||||
Field *
|
Field *
|
||||||
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
||||||
const char *name, const char *item_name,
|
const char *name, uint length,
|
||||||
const char *table_name, const char *db_name,
|
const char *item_name, const char *db_name,
|
||||||
uint length, Item **ref,
|
const char *table_name, Item **ref,
|
||||||
bool check_grants_table, bool check_grants_view,
|
bool check_privileges, bool allow_rowid,
|
||||||
bool allow_rowid,
|
|
||||||
uint *cached_field_index_ptr,
|
uint *cached_field_index_ptr,
|
||||||
bool register_tree_change, TABLE_LIST **actual_table);
|
bool register_tree_change, TABLE_LIST **actual_table);
|
||||||
Field *
|
Field *
|
||||||
find_field_in_table(THD *thd, TABLE *table, const char *name,
|
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
||||||
uint length, bool check_grants, bool allow_rowid,
|
bool allow_rowid, uint *cached_field_index_ptr);
|
||||||
uint *cached_field_index_ptr,
|
|
||||||
Security_context *sctx);
|
|
||||||
Field *
|
Field *
|
||||||
find_field_in_table_sef(TABLE *table, const char *name);
|
find_field_in_table_sef(TABLE *table, const char *name);
|
||||||
|
|
||||||
@ -950,8 +947,9 @@ create_field * new_create_field(THD *thd, char *field_name, enum_field_types typ
|
|||||||
uint uint_geom_type);
|
uint uint_geom_type);
|
||||||
void store_position_for_column(const char *name);
|
void store_position_for_column(const char *name);
|
||||||
bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
|
bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
|
||||||
Name_resolution_context *make_join_on_context(THD *thd, TABLE_LIST *left_op,
|
bool push_new_name_resolution_context(THD *thd,
|
||||||
TABLE_LIST *right_op);
|
TABLE_LIST *left_op,
|
||||||
|
TABLE_LIST *right_op);
|
||||||
void add_join_on(TABLE_LIST *b,Item *expr);
|
void add_join_on(TABLE_LIST *b,Item *expr);
|
||||||
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
|
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
|
||||||
bool add_proc_to_list(THD *thd, Item *item);
|
bool add_proc_to_list(THD *thd, Item *item);
|
||||||
|
106
sql/sql_acl.cc
106
sql/sql_acl.cc
@ -2760,8 +2760,9 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
|
|||||||
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
|
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
|
||||||
TABLE_LIST *dummy;
|
TABLE_LIST *dummy;
|
||||||
Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
|
Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
|
||||||
|
column->column.length(),
|
||||||
column->column.ptr(), NULL, NULL,
|
column->column.ptr(), NULL, NULL,
|
||||||
column->column.length(), 0, 1, 1, 0,
|
NULL, TRUE, FALSE,
|
||||||
&unused_field_idx, FALSE, &dummy);
|
&unused_field_idx, FALSE, &dummy);
|
||||||
if (f == (Field*)0)
|
if (f == (Field*)0)
|
||||||
{
|
{
|
||||||
@ -3616,11 +3617,28 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check column rights in given security context
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
check_grant_column()
|
||||||
|
thd thread handler
|
||||||
|
grant grant information structure
|
||||||
|
db_name db name
|
||||||
|
table_name table name
|
||||||
|
name column name
|
||||||
|
length column name length
|
||||||
|
sctx security context
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE OK
|
||||||
|
TRUE access denied
|
||||||
|
*/
|
||||||
|
|
||||||
bool check_grant_column(THD *thd, GRANT_INFO *grant,
|
bool check_grant_column(THD *thd, GRANT_INFO *grant,
|
||||||
const char *db_name, const char *table_name,
|
const char *db_name, const char *table_name,
|
||||||
const char *name, uint length, uint show_tables)
|
const char *name, uint length, Security_context *sctx)
|
||||||
{
|
{
|
||||||
Security_context *sctx= thd->security_ctx;
|
|
||||||
GRANT_TABLE *grant_table;
|
GRANT_TABLE *grant_table;
|
||||||
GRANT_COLUMN *grant_column;
|
GRANT_COLUMN *grant_column;
|
||||||
ulong want_access= grant->want_privilege & ~grant->privilege;
|
ulong want_access= grant->want_privilege & ~grant->privilege;
|
||||||
@ -3651,31 +3669,77 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
|
|||||||
rw_unlock(&LOCK_grant);
|
rw_unlock(&LOCK_grant);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
#ifdef NOT_USED
|
|
||||||
if (show_tables && (grant_column || grant->privilege & COL_ACLS))
|
|
||||||
{
|
|
||||||
rw_unlock(&LOCK_grant); /* purecov: deadcode */
|
|
||||||
DBUG_RETURN(0); /* purecov: deadcode */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
rw_unlock(&LOCK_grant);
|
rw_unlock(&LOCK_grant);
|
||||||
if (!show_tables)
|
char command[128];
|
||||||
{
|
get_privilege_desc(command, sizeof(command), want_access);
|
||||||
char command[128];
|
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
|
||||||
get_privilege_desc(command, sizeof(command), want_access);
|
command,
|
||||||
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
|
sctx->priv_user,
|
||||||
command,
|
sctx->host_or_ip,
|
||||||
sctx->priv_user,
|
name,
|
||||||
sctx->host_or_ip,
|
table_name);
|
||||||
name,
|
|
||||||
table_name);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check the access right to a column depending on the type of table.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
check_column_grant_in_table_ref()
|
||||||
|
thd thread handler
|
||||||
|
table_ref table reference where to check the field
|
||||||
|
name name of field to check
|
||||||
|
length length of name
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Check the access rights to a column depending on the type of table
|
||||||
|
reference where the column is checked. The function provides a
|
||||||
|
generic interface to check column access rights that hides the
|
||||||
|
heterogeneity of the column representation - whether it is a view
|
||||||
|
or a stored table colum.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE OK
|
||||||
|
TRUE access denied
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
|
||||||
|
const char *name, uint length)
|
||||||
|
{
|
||||||
|
GRANT_INFO *grant;
|
||||||
|
const char *db_name;
|
||||||
|
const char *table_name;
|
||||||
|
Security_context *sctx= test(table_ref->security_ctx) ?
|
||||||
|
table_ref->security_ctx : thd->security_ctx;
|
||||||
|
|
||||||
|
if (table_ref->view || table_ref->field_translation)
|
||||||
|
{
|
||||||
|
/* View or derived information schema table. */
|
||||||
|
grant= &(table_ref->grant);
|
||||||
|
db_name= table_ref->view_db.str;
|
||||||
|
table_name= table_ref->view_name.str;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Normal or temporary table. */
|
||||||
|
TABLE *table= table_ref->table;
|
||||||
|
grant= &(table->grant);
|
||||||
|
db_name= table->s->db;
|
||||||
|
table_name= table->s->table_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grant->want_privilege)
|
||||||
|
return check_grant_column(thd, grant, db_name, table_name, name,
|
||||||
|
length, sctx);
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
|
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
|
||||||
const char* db_name, const char *table_name,
|
const char* db_name, const char *table_name,
|
||||||
Field_iterator *fields)
|
Field_iterator *fields)
|
||||||
|
@ -205,7 +205,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
|||||||
uint show_command, uint number, bool dont_print_error);
|
uint show_command, uint number, bool dont_print_error);
|
||||||
bool check_grant_column (THD *thd, GRANT_INFO *grant,
|
bool check_grant_column (THD *thd, GRANT_INFO *grant,
|
||||||
const char *db_name, const char *table_name,
|
const char *db_name, const char *table_name,
|
||||||
const char *name, uint length, uint show_command=0);
|
const char *name, uint length, Security_context *sctx);
|
||||||
|
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
|
||||||
|
const char *name, uint length);
|
||||||
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
|
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
|
||||||
const char* db_name, const char *table_name,
|
const char* db_name, const char *table_name,
|
||||||
Field_iterator *fields);
|
Field_iterator *fields);
|
||||||
|
208
sql/sql_base.cc
208
sql/sql_base.cc
@ -3368,47 +3368,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
/*
|
|
||||||
Check column rights in given security context
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
check_grant_column_in_sctx()
|
|
||||||
thd thread handler
|
|
||||||
grant grant information structure
|
|
||||||
db db name
|
|
||||||
table table name
|
|
||||||
name column name
|
|
||||||
length column name length
|
|
||||||
check_grants need to check grants
|
|
||||||
sctx 0 or security context
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
FALSE OK
|
|
||||||
TRUE access denied
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
|
|
||||||
const char *db, const char *table,
|
|
||||||
const char *name, uint length,
|
|
||||||
bool check_grants,
|
|
||||||
Security_context *sctx)
|
|
||||||
{
|
|
||||||
if (!check_grants)
|
|
||||||
return FALSE;
|
|
||||||
Security_context *save_security_ctx= thd->security_ctx;
|
|
||||||
bool res;
|
|
||||||
if (sctx)
|
|
||||||
{
|
|
||||||
thd->security_ctx= sctx;
|
|
||||||
}
|
|
||||||
res= check_grant_column(thd, grant, db, table, name, length);
|
|
||||||
thd->security_ctx= save_security_ctx;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find a field by name in a view that uses merge algorithm.
|
Find a field by name in a view that uses merge algorithm.
|
||||||
|
|
||||||
@ -3417,11 +3376,10 @@ static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
|
|||||||
thd thread handler
|
thd thread handler
|
||||||
table_list view to search for 'name'
|
table_list view to search for 'name'
|
||||||
name name of field
|
name name of field
|
||||||
item_name name of item if it will be created (VIEW)
|
|
||||||
length length of name
|
length length of name
|
||||||
|
item_name name of item if it will be created (VIEW)
|
||||||
ref expression substituted in VIEW should be passed
|
ref expression substituted in VIEW should be passed
|
||||||
using this reference (return view_ref_found)
|
using this reference (return view_ref_found)
|
||||||
check_grants do check columns grants for view?
|
|
||||||
register_tree_change TRUE if ref is not stack variable and we
|
register_tree_change TRUE if ref is not stack variable and we
|
||||||
need register changes in item tree
|
need register changes in item tree
|
||||||
|
|
||||||
@ -3433,8 +3391,8 @@ static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
|
|||||||
|
|
||||||
static Field *
|
static Field *
|
||||||
find_field_in_view(THD *thd, TABLE_LIST *table_list,
|
find_field_in_view(THD *thd, TABLE_LIST *table_list,
|
||||||
const char *name, const char *item_name,
|
const char *name, uint length,
|
||||||
uint length, Item **ref, bool check_grants,
|
const char *item_name, Item **ref,
|
||||||
bool register_tree_change)
|
bool register_tree_change)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("find_field_in_view");
|
DBUG_ENTER("find_field_in_view");
|
||||||
@ -3451,24 +3409,13 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
|
|||||||
{
|
{
|
||||||
if (!my_strcasecmp(system_charset_info, field_it.name(), name))
|
if (!my_strcasecmp(system_charset_info, field_it.name(), name))
|
||||||
{
|
{
|
||||||
if (table_list->schema_table_reformed)
|
|
||||||
/*
|
|
||||||
Translation table items are always Item_fields and fixed already
|
|
||||||
('mysql_schema_table' function). So we can return ->field. It is
|
|
||||||
used only for 'show & where' commands.
|
|
||||||
*/
|
|
||||||
DBUG_RETURN(((Item_field*) (field_it.item()))->field);
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
if (check_grant_column_in_sctx(thd, &table_list->grant,
|
|
||||||
table_list->view_db.str,
|
|
||||||
table_list->view_name.str, name, length,
|
|
||||||
check_grants,
|
|
||||||
table_list->security_ctx))
|
|
||||||
DBUG_RETURN(WRONG_GRANT);
|
|
||||||
#endif
|
|
||||||
// in PS use own arena or data will be freed after prepare
|
// in PS use own arena or data will be freed after prepare
|
||||||
if (register_tree_change)
|
if (register_tree_change)
|
||||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||||
|
/*
|
||||||
|
create_item() may, or may not create a new Item, depending on
|
||||||
|
the column reference. See create_view_field() for details.
|
||||||
|
*/
|
||||||
Item *item= field_it.create_item(thd);
|
Item *item= field_it.create_item(thd);
|
||||||
if (register_tree_change && arena)
|
if (register_tree_change && arena)
|
||||||
thd->restore_active_arena(arena, &backup);
|
thd->restore_active_arena(arena, &backup);
|
||||||
@ -3510,7 +3457,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
|
|||||||
length [in] length of name
|
length [in] length of name
|
||||||
ref [in/out] if 'name' is resolved to a view field, ref is
|
ref [in/out] if 'name' is resolved to a view field, ref is
|
||||||
set to point to the found view field
|
set to point to the found view field
|
||||||
check_grants [in] do check columns grants?
|
|
||||||
register_tree_change [in] TRUE if ref is not stack variable and we
|
register_tree_change [in] TRUE if ref is not stack variable and we
|
||||||
need register changes in item tree
|
need register changes in item tree
|
||||||
actual_table [out] the original table reference where the field
|
actual_table [out] the original table reference where the field
|
||||||
@ -3531,8 +3477,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
|
|||||||
|
|
||||||
static Field *
|
static Field *
|
||||||
find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
|
find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
|
||||||
uint length, Item **ref, bool check_grants,
|
uint length, Item **ref, bool register_tree_change,
|
||||||
bool register_tree_change,
|
|
||||||
TABLE_LIST **actual_table)
|
TABLE_LIST **actual_table)
|
||||||
{
|
{
|
||||||
List_iterator_fast<Natural_join_column>
|
List_iterator_fast<Natural_join_column>
|
||||||
@ -3557,23 +3502,16 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
if (check_grants && nj_col->check_grants(thd, name, length))
|
|
||||||
DBUG_RETURN(WRONG_GRANT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (nj_col->view_field)
|
if (nj_col->view_field)
|
||||||
{
|
{
|
||||||
Item *item;
|
Item *item;
|
||||||
/*
|
|
||||||
The found field is a view field, we do as in find_field_in_view()
|
|
||||||
and return a pointer to pointer to the Item of that field.
|
|
||||||
*/
|
|
||||||
if (register_tree_change)
|
if (register_tree_change)
|
||||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||||
|
/*
|
||||||
|
create_item() may, or may not create a new Item, depending on the
|
||||||
|
column reference. See create_view_field() for details.
|
||||||
|
*/
|
||||||
item= nj_col->create_item(thd);
|
item= nj_col->create_item(thd);
|
||||||
|
|
||||||
if (register_tree_change && arena)
|
if (register_tree_change && arena)
|
||||||
thd->restore_active_arena(arena, &backup);
|
thd->restore_active_arena(arena, &backup);
|
||||||
|
|
||||||
@ -3619,7 +3557,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
|
|||||||
table table where to search for the field
|
table table where to search for the field
|
||||||
name name of field
|
name name of field
|
||||||
length length of name
|
length length of name
|
||||||
check_grants do check columns grants?
|
|
||||||
allow_rowid do allow finding of "_rowid" field?
|
allow_rowid do allow finding of "_rowid" field?
|
||||||
cached_field_index_ptr cached position in field list (used to speedup
|
cached_field_index_ptr cached position in field list (used to speedup
|
||||||
lookup for fields in prepared tables)
|
lookup for fields in prepared tables)
|
||||||
@ -3631,9 +3568,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
|
|||||||
|
|
||||||
Field *
|
Field *
|
||||||
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
||||||
bool check_grants, bool allow_rowid,
|
bool allow_rowid, uint *cached_field_index_ptr)
|
||||||
uint *cached_field_index_ptr,
|
|
||||||
Security_context *sctx)
|
|
||||||
{
|
{
|
||||||
Field **field_ptr, *field;
|
Field **field_ptr, *field;
|
||||||
uint cached_field_index= *cached_field_index_ptr;
|
uint cached_field_index= *cached_field_index_ptr;
|
||||||
@ -3683,13 +3618,6 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
|||||||
|
|
||||||
update_field_dependencies(thd, field, table);
|
update_field_dependencies(thd, field, table);
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
if (check_grant_column_in_sctx(thd, &table->grant,
|
|
||||||
table->s->db.str, table->s->table_name.str,
|
|
||||||
name, length,
|
|
||||||
check_grants, sctx))
|
|
||||||
field= WRONG_GRANT;
|
|
||||||
#endif
|
|
||||||
DBUG_RETURN(field);
|
DBUG_RETURN(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3702,14 +3630,13 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
|||||||
thd [in] thread handler
|
thd [in] thread handler
|
||||||
table_list [in] table reference to search
|
table_list [in] table reference to search
|
||||||
name [in] name of field
|
name [in] name of field
|
||||||
item_name [in] name of item if it will be created (VIEW)
|
|
||||||
table_name [in] optional table name that qualifies the field
|
|
||||||
db_name [in] optional database name that qualifies the
|
|
||||||
length [in] field length of name
|
length [in] field length of name
|
||||||
|
item_name [in] name of item if it will be created (VIEW)
|
||||||
|
db_name [in] optional database name that qualifies the
|
||||||
|
table_name [in] optional table name that qualifies the field
|
||||||
ref [in/out] if 'name' is resolved to a view field, ref
|
ref [in/out] if 'name' is resolved to a view field, ref
|
||||||
is set to point to the found view field
|
is set to point to the found view field
|
||||||
check_grants_table [in] do check columns grants for table?
|
check_privileges [in] check privileges
|
||||||
check_grants_view [in] do check columns grants for view?
|
|
||||||
allow_rowid [in] do allow finding of "_rowid" field?
|
allow_rowid [in] do allow finding of "_rowid" field?
|
||||||
cached_field_index_ptr [in] cached position in field list (used to
|
cached_field_index_ptr [in] cached position in field list (used to
|
||||||
speedup lookup for fields in prepared tables)
|
speedup lookup for fields in prepared tables)
|
||||||
@ -3739,11 +3666,11 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
|||||||
|
|
||||||
Field *
|
Field *
|
||||||
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
||||||
const char *name, const char *item_name,
|
const char *name, uint length,
|
||||||
const char *table_name, const char *db_name,
|
const char *item_name, const char *db_name,
|
||||||
uint length, Item **ref,
|
const char *table_name, Item **ref,
|
||||||
bool check_grants_table, bool check_grants_view,
|
bool check_privileges, bool allow_rowid,
|
||||||
bool allow_rowid, uint *cached_field_index_ptr,
|
uint *cached_field_index_ptr,
|
||||||
bool register_tree_change, TABLE_LIST **actual_table)
|
bool register_tree_change, TABLE_LIST **actual_table)
|
||||||
{
|
{
|
||||||
Field *fld;
|
Field *fld;
|
||||||
@ -3788,8 +3715,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||||||
if (table_list->field_translation)
|
if (table_list->field_translation)
|
||||||
{
|
{
|
||||||
/* 'table_list' is a view or an information schema table. */
|
/* 'table_list' is a view or an information schema table. */
|
||||||
if ((fld= find_field_in_view(thd, table_list, name, item_name, length,
|
if ((fld= find_field_in_view(thd, table_list, name, length, item_name, ref,
|
||||||
ref, check_grants_view,
|
|
||||||
register_tree_change)))
|
register_tree_change)))
|
||||||
*actual_table= table_list;
|
*actual_table= table_list;
|
||||||
}
|
}
|
||||||
@ -3798,20 +3724,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||||||
/* 'table_list' is a stored table. */
|
/* 'table_list' is a stored table. */
|
||||||
DBUG_ASSERT(table_list->table);
|
DBUG_ASSERT(table_list->table);
|
||||||
if ((fld= find_field_in_table(thd, table_list->table, name, length,
|
if ((fld= find_field_in_table(thd, table_list->table, name, length,
|
||||||
check_grants_table, allow_rowid,
|
allow_rowid,
|
||||||
cached_field_index_ptr,
|
cached_field_index_ptr)))
|
||||||
table_list->security_ctx)))
|
|
||||||
*actual_table= table_list;
|
*actual_table= table_list;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
/* check for views with temporary table algorithm */
|
|
||||||
if (check_grants_view && table_list->view &&
|
|
||||||
fld && fld != WRONG_GRANT &&
|
|
||||||
check_grant_column(thd, &table_list->grant,
|
|
||||||
table_list->view_db.str,
|
|
||||||
table_list->view_name.str,
|
|
||||||
name, length))
|
|
||||||
fld= WRONG_GRANT;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3828,11 +3743,10 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||||||
TABLE_LIST *table;
|
TABLE_LIST *table;
|
||||||
while ((table= it++))
|
while ((table= it++))
|
||||||
{
|
{
|
||||||
if ((fld= find_field_in_table_ref(thd, table, name, item_name,
|
if ((fld= find_field_in_table_ref(thd, table, name, length, item_name,
|
||||||
table_name, db_name, length, ref,
|
db_name, table_name, ref,
|
||||||
check_grants_table,
|
check_privileges, allow_rowid,
|
||||||
check_grants_view,
|
cached_field_index_ptr,
|
||||||
allow_rowid, cached_field_index_ptr,
|
|
||||||
register_tree_change, actual_table)))
|
register_tree_change, actual_table)))
|
||||||
DBUG_RETURN(fld);
|
DBUG_RETURN(fld);
|
||||||
}
|
}
|
||||||
@ -3845,11 +3759,16 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||||||
directly the top-most NATURAL/USING join.
|
directly the top-most NATURAL/USING join.
|
||||||
*/
|
*/
|
||||||
fld= find_field_in_natural_join(thd, table_list, name, length, ref,
|
fld= find_field_in_natural_join(thd, table_list, name, length, ref,
|
||||||
/* TIMOUR_TODO: check this with Sanja */
|
|
||||||
check_grants_table || check_grants_view,
|
|
||||||
register_tree_change, actual_table);
|
register_tree_change, actual_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
/* Check if there are sufficient access rights to the found field. */
|
||||||
|
if (fld && check_privileges &&
|
||||||
|
check_column_grant_in_table_ref(thd, *actual_table, name, length))
|
||||||
|
fld= WRONG_GRANT;
|
||||||
|
#endif
|
||||||
|
|
||||||
DBUG_RETURN(fld);
|
DBUG_RETURN(fld);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3967,21 +3886,11 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||||||
*/
|
*/
|
||||||
if (table_ref->table && !table_ref->view)
|
if (table_ref->table && !table_ref->view)
|
||||||
found= find_field_in_table(thd, table_ref->table, name, length,
|
found= find_field_in_table(thd, table_ref->table, name, length,
|
||||||
test(table_ref->table->
|
TRUE, &(item->cached_field_index));
|
||||||
grant.want_privilege) &&
|
|
||||||
check_privileges,
|
|
||||||
1, &(item->cached_field_index),
|
|
||||||
table_ref->security_ctx);
|
|
||||||
else
|
else
|
||||||
found= find_field_in_table_ref(thd, table_ref, name, item->name,
|
found= find_field_in_table_ref(thd, table_ref, name, length, item->name,
|
||||||
NULL, NULL, length, ref,
|
NULL, NULL, ref, check_privileges,
|
||||||
(table_ref->table &&
|
TRUE, &(item->cached_field_index),
|
||||||
test(table_ref->table->grant.
|
|
||||||
want_privilege) &&
|
|
||||||
check_privileges),
|
|
||||||
(test(table_ref->grant.want_privilege) &&
|
|
||||||
check_privileges),
|
|
||||||
1, &(item->cached_field_index),
|
|
||||||
register_tree_change,
|
register_tree_change,
|
||||||
&actual_table);
|
&actual_table);
|
||||||
if (found)
|
if (found)
|
||||||
@ -4021,17 +3930,9 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||||||
for (; cur_table != last_table ;
|
for (; cur_table != last_table ;
|
||||||
cur_table= cur_table->next_name_resolution_table)
|
cur_table= cur_table->next_name_resolution_table)
|
||||||
{
|
{
|
||||||
Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name,
|
Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length,
|
||||||
table_name, db,
|
item->name, db, table_name, ref,
|
||||||
length, ref,
|
check_privileges, allow_rowid,
|
||||||
(cur_table->table &&
|
|
||||||
test(cur_table->table->grant.
|
|
||||||
want_privilege) &&
|
|
||||||
check_privileges),
|
|
||||||
(test(cur_table->grant.
|
|
||||||
want_privilege)
|
|
||||||
&& check_privileges),
|
|
||||||
allow_rowid,
|
|
||||||
&(item->cached_field_index),
|
&(item->cached_field_index),
|
||||||
register_tree_change,
|
register_tree_change,
|
||||||
&actual_table);
|
&actual_table);
|
||||||
@ -4439,7 +4340,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
|
|||||||
{
|
{
|
||||||
bool is_created_1;
|
bool is_created_1;
|
||||||
bool found= FALSE;
|
bool found= FALSE;
|
||||||
if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created_1)))
|
if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
|
||||||
goto err;
|
goto err;
|
||||||
field_name_1= nj_col_1->name();
|
field_name_1= nj_col_1->name();
|
||||||
|
|
||||||
@ -4460,7 +4361,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
|
|||||||
bool is_created_2;
|
bool is_created_2;
|
||||||
Natural_join_column *cur_nj_col_2;
|
Natural_join_column *cur_nj_col_2;
|
||||||
const char *cur_field_name_2;
|
const char *cur_field_name_2;
|
||||||
if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, &is_created_2)))
|
if (!(cur_nj_col_2= it_2.get_or_create_column_ref(&is_created_2)))
|
||||||
goto err;
|
goto err;
|
||||||
cur_field_name_2= cur_nj_col_2->name();
|
cur_field_name_2= cur_nj_col_2->name();
|
||||||
|
|
||||||
@ -4656,13 +4557,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
|
|||||||
/* Append the columns of the first join operand. */
|
/* Append the columns of the first join operand. */
|
||||||
for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
|
for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
|
||||||
{
|
{
|
||||||
if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created)))
|
nj_col_1= it_1.get_natural_column_ref();
|
||||||
goto err;
|
|
||||||
/*
|
|
||||||
The following assert checks that mark_common_columns() was run and
|
|
||||||
we created the list table_ref_1->join_columns.
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(!is_created);
|
|
||||||
if (nj_col_1->is_common)
|
if (nj_col_1->is_common)
|
||||||
{
|
{
|
||||||
natural_using_join->join_columns->push_back(nj_col_1);
|
natural_using_join->join_columns->push_back(nj_col_1);
|
||||||
@ -4708,13 +4603,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
|
|||||||
/* Append the non-equi-join columns of the second join operand. */
|
/* Append the non-equi-join columns of the second join operand. */
|
||||||
for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
|
for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
|
||||||
{
|
{
|
||||||
if (!(nj_col_2= it_2.get_or_create_column_ref(thd, &is_created)))
|
nj_col_2= it_2.get_natural_column_ref();
|
||||||
goto err;
|
|
||||||
/*
|
|
||||||
The following assert checks that mark_common_columns() was run and
|
|
||||||
we created the list table_ref_2->join_columns.
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(!is_created);
|
|
||||||
if (!nj_col_2->is_common)
|
if (!nj_col_2->is_common)
|
||||||
non_join_columns->push_back(nj_col_2);
|
non_join_columns->push_back(nj_col_2);
|
||||||
else
|
else
|
||||||
@ -5449,8 +5338,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
|
|||||||
because it was already created and stored with the natural join.
|
because it was already created and stored with the natural join.
|
||||||
*/
|
*/
|
||||||
Natural_join_column *nj_col;
|
Natural_join_column *nj_col;
|
||||||
if (!(nj_col= field_iterator.get_or_create_column_ref(thd,
|
if (!(nj_col= field_iterator.get_or_create_column_ref(&is_created)))
|
||||||
&is_created)))
|
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
DBUG_ASSERT(nj_col->table_field && !is_created);
|
DBUG_ASSERT(nj_col->table_field && !is_created);
|
||||||
field_table= nj_col->table_ref->table;
|
field_table= nj_col->table_ref->table;
|
||||||
|
@ -113,11 +113,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
|
|||||||
{ // Part field list
|
{ // Part field list
|
||||||
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||||
Name_resolution_context *context= &select_lex->context;
|
Name_resolution_context *context= &select_lex->context;
|
||||||
TABLE_LIST *save_next_local;
|
Name_resolution_context_state ctx_state;
|
||||||
TABLE_LIST *save_table_list;
|
|
||||||
TABLE_LIST *save_first_name_resolution_table;
|
|
||||||
TABLE_LIST *save_next_name_resolution_table;
|
|
||||||
bool save_resolve_in_select_list;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (fields.elements != values.elements)
|
if (fields.elements != values.elements)
|
||||||
@ -130,14 +126,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
|
|||||||
select_lex->no_wrap_view_item= TRUE;
|
select_lex->no_wrap_view_item= TRUE;
|
||||||
|
|
||||||
/* Save the state of the current name resolution context. */
|
/* Save the state of the current name resolution context. */
|
||||||
save_table_list= context->table_list;
|
ctx_state.save_state(context, table_list);
|
||||||
save_first_name_resolution_table= context->first_name_resolution_table;
|
|
||||||
save_next_name_resolution_table= (context->first_name_resolution_table) ?
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table :
|
|
||||||
NULL;
|
|
||||||
save_resolve_in_select_list= context->resolve_in_select_list;
|
|
||||||
save_next_local= table_list->next_local;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Perform name resolution only in the first table - 'table_list',
|
Perform name resolution only in the first table - 'table_list',
|
||||||
@ -152,13 +141,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
|
|||||||
res= setup_fields(thd, 0, fields, 2, 0, 0);
|
res= setup_fields(thd, 0, fields, 2, 0, 0);
|
||||||
|
|
||||||
/* Restore the current context. */
|
/* Restore the current context. */
|
||||||
table_list->next_local= save_next_local;
|
ctx_state.restore_state(context, table_list);
|
||||||
context->table_list= save_table_list;
|
|
||||||
context->first_name_resolution_table= save_first_name_resolution_table;
|
|
||||||
if (context->first_name_resolution_table)
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table= save_next_name_resolution_table;
|
|
||||||
context->resolve_in_select_list= save_resolve_in_select_list;
|
|
||||||
thd->lex->select_lex.no_wrap_view_item= FALSE;
|
thd->lex->select_lex.no_wrap_view_item= FALSE;
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
@ -293,13 +276,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
ulonglong id;
|
ulonglong id;
|
||||||
COPY_INFO info;
|
COPY_INFO info;
|
||||||
TABLE *table= 0;
|
TABLE *table= 0;
|
||||||
TABLE_LIST *save_table_list;
|
|
||||||
TABLE_LIST *save_next_local;
|
|
||||||
TABLE_LIST *save_first_name_resolution_table;
|
|
||||||
TABLE_LIST *save_next_name_resolution_table;
|
|
||||||
List_iterator_fast<List_item> its(values_list);
|
List_iterator_fast<List_item> its(values_list);
|
||||||
List_item *values;
|
List_item *values;
|
||||||
Name_resolution_context *context;
|
Name_resolution_context *context;
|
||||||
|
Name_resolution_context_state ctx_state;
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
char *query= thd->query;
|
char *query= thd->query;
|
||||||
#endif
|
#endif
|
||||||
@ -380,13 +360,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
|
|
||||||
context= &thd->lex->select_lex.context;
|
context= &thd->lex->select_lex.context;
|
||||||
/* Save the state of the current name resolution context. */
|
/* Save the state of the current name resolution context. */
|
||||||
save_table_list= context->table_list;
|
ctx_state.save_state(context, table_list);
|
||||||
save_first_name_resolution_table= context->first_name_resolution_table;
|
|
||||||
save_next_name_resolution_table= (context->first_name_resolution_table) ?
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table :
|
|
||||||
NULL;
|
|
||||||
save_next_local= table_list->next_local;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Perform name resolution only in the first table - 'table_list',
|
Perform name resolution only in the first table - 'table_list',
|
||||||
@ -410,16 +384,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
its.rewind ();
|
its.rewind ();
|
||||||
|
|
||||||
/* Restore the current context. */
|
/* Restore the current context. */
|
||||||
table_list->next_local= save_next_local;
|
ctx_state.restore_state(context, table_list);
|
||||||
context->first_name_resolution_table= save_first_name_resolution_table;
|
|
||||||
if (context->first_name_resolution_table)
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table= save_next_name_resolution_table;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fill in the given fields and dump it to the table file
|
Fill in the given fields and dump it to the table file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
info.records= info.deleted= info.copied= info.updated= 0;
|
info.records= info.deleted= info.copied= info.updated= 0;
|
||||||
info.ignore= ignore;
|
info.ignore= ignore;
|
||||||
info.handle_duplicates=duplic;
|
info.handle_duplicates=duplic;
|
||||||
@ -827,11 +796,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
|||||||
{
|
{
|
||||||
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||||
Name_resolution_context *context= &select_lex->context;
|
Name_resolution_context *context= &select_lex->context;
|
||||||
TABLE_LIST *save_table_list;
|
Name_resolution_context_state ctx_state;
|
||||||
TABLE_LIST *save_next_local;
|
|
||||||
TABLE_LIST *save_first_name_resolution_table;
|
|
||||||
TABLE_LIST *save_next_name_resolution_table;
|
|
||||||
bool save_resolve_in_select_list;
|
|
||||||
bool insert_into_view= (table_list->view != 0);
|
bool insert_into_view= (table_list->view != 0);
|
||||||
bool res= 0;
|
bool res= 0;
|
||||||
DBUG_ENTER("mysql_prepare_insert");
|
DBUG_ENTER("mysql_prepare_insert");
|
||||||
@ -871,15 +836,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
/* Save the state of the current name resolution context. */
|
/* Save the state of the current name resolution context. */
|
||||||
save_table_list= context->table_list;
|
ctx_state.save_state(context, table_list);
|
||||||
/* Here first_name_resolution_table points to the first select table. */
|
|
||||||
save_first_name_resolution_table= context->first_name_resolution_table;
|
|
||||||
save_next_name_resolution_table= (context->first_name_resolution_table) ?
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table :
|
|
||||||
NULL;
|
|
||||||
save_resolve_in_select_list= context->resolve_in_select_list;
|
|
||||||
save_next_local= table_list->next_local;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Perform name resolution only in the first table - 'table_list',
|
Perform name resolution only in the first table - 'table_list',
|
||||||
@ -904,23 +861,17 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
|||||||
*/
|
*/
|
||||||
if (select_lex->group_list.elements == 0)
|
if (select_lex->group_list.elements == 0)
|
||||||
{
|
{
|
||||||
context->table_list->next_local= save_next_local;
|
context->table_list->next_local= ctx_state.save_next_local;
|
||||||
/* first_name_resolution_table was set by resolve_in_table_list_only() */
|
/* first_name_resolution_table was set by resolve_in_table_list_only() */
|
||||||
context->first_name_resolution_table->
|
context->first_name_resolution_table->
|
||||||
next_name_resolution_table= save_next_local;
|
next_name_resolution_table= ctx_state.save_next_local;
|
||||||
}
|
}
|
||||||
if (!res)
|
if (!res)
|
||||||
res= setup_fields(thd, 0, update_values, 1, 0, 0);
|
res= setup_fields(thd, 0, update_values, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the current context. */
|
/* Restore the current context. */
|
||||||
table_list->next_local= save_next_local;
|
ctx_state.restore_state(context, table_list);
|
||||||
context->table_list= save_table_list;
|
|
||||||
context->first_name_resolution_table= save_first_name_resolution_table;
|
|
||||||
if (context->first_name_resolution_table)
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table= save_next_name_resolution_table;
|
|
||||||
context->resolve_in_select_list= save_resolve_in_select_list;
|
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
@ -2187,17 +2138,10 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||||||
{
|
{
|
||||||
/* Save the state of the current name resolution context. */
|
/* Save the state of the current name resolution context. */
|
||||||
Name_resolution_context *context= &lex->select_lex.context;
|
Name_resolution_context *context= &lex->select_lex.context;
|
||||||
TABLE_LIST *save_table_list;
|
Name_resolution_context_state ctx_state;
|
||||||
TABLE_LIST *save_next_local;
|
|
||||||
TABLE_LIST *save_first_name_resolution_table;
|
/* Save the state of the current name resolution context. */
|
||||||
TABLE_LIST *save_next_name_resolution_table;
|
ctx_state.save_state(context, table_list);
|
||||||
save_table_list= context->table_list;
|
|
||||||
save_first_name_resolution_table= context->first_name_resolution_table;
|
|
||||||
save_next_name_resolution_table= (context->first_name_resolution_table) ?
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table :
|
|
||||||
NULL;
|
|
||||||
save_next_local= table_list->next_local;
|
|
||||||
|
|
||||||
/* Perform name resolution only in the first table - 'table_list'. */
|
/* Perform name resolution only in the first table - 'table_list'. */
|
||||||
table_list->next_local= 0;
|
table_list->next_local= 0;
|
||||||
@ -2213,20 +2157,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||||||
*/
|
*/
|
||||||
if (lex->select_lex.group_list.elements == 0)
|
if (lex->select_lex.group_list.elements == 0)
|
||||||
{
|
{
|
||||||
context->table_list->next_local= save_next_local;
|
context->table_list->next_local= ctx_state.save_next_local;
|
||||||
/* first_name_resolution_table was set by resolve_in_table_list_only() */
|
/* first_name_resolution_table was set by resolve_in_table_list_only() */
|
||||||
context->first_name_resolution_table->
|
context->first_name_resolution_table->
|
||||||
next_name_resolution_table= save_next_local;
|
next_name_resolution_table= ctx_state.save_next_local;
|
||||||
}
|
}
|
||||||
res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
|
res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
|
||||||
|
|
||||||
/* Restore the current context. */
|
/* Restore the current context. */
|
||||||
table_list->next_local= save_next_local;
|
ctx_state.restore_state(context, table_list);
|
||||||
context->first_name_resolution_table= save_first_name_resolution_table;
|
|
||||||
if (context->first_name_resolution_table)
|
|
||||||
context->first_name_resolution_table->
|
|
||||||
next_name_resolution_table= save_next_name_resolution_table;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lex->current_select= lex_current_select_save;
|
lex->current_select= lex_current_select_save;
|
||||||
|
@ -1130,6 +1130,11 @@ void st_select_lex::init_query()
|
|||||||
/*
|
/*
|
||||||
Add the name resolution context of the current (sub)query to the
|
Add the name resolution context of the current (sub)query to the
|
||||||
stack of contexts for the whole query.
|
stack of contexts for the whole query.
|
||||||
|
TODO:
|
||||||
|
push_context may return an error if there is no memory for a new
|
||||||
|
element in the stack, however this method has no return value,
|
||||||
|
thus push_context should be moved to a place where query
|
||||||
|
initialization is checked for failure.
|
||||||
*/
|
*/
|
||||||
parent_lex->push_context(&context);
|
parent_lex->push_context(&context);
|
||||||
cond_count= with_wild= 0;
|
cond_count= with_wild= 0;
|
||||||
|
@ -1024,9 +1024,9 @@ typedef struct st_lex
|
|||||||
}
|
}
|
||||||
void cleanup_after_one_table_open();
|
void cleanup_after_one_table_open();
|
||||||
|
|
||||||
void push_context(Name_resolution_context *context)
|
bool push_context(Name_resolution_context *context)
|
||||||
{
|
{
|
||||||
context_stack.push_front(context);
|
return context_stack.push_front(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_context()
|
void pop_context()
|
||||||
|
@ -266,10 +266,21 @@ protected:
|
|||||||
ls.elements= elm;
|
ls.elements= elm;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
base_list_iterator(base_list &list_par)
|
base_list_iterator()
|
||||||
:list(&list_par), el(&list_par.first), prev(0), current(0)
|
:list(0), el(0), prev(0), current(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
base_list_iterator(base_list &list_par)
|
||||||
|
{ init(list_par); }
|
||||||
|
|
||||||
|
inline void init(base_list &list_par)
|
||||||
|
{
|
||||||
|
list= &list_par;
|
||||||
|
el= &list_par.first;
|
||||||
|
prev= 0;
|
||||||
|
current= 0;
|
||||||
|
}
|
||||||
|
|
||||||
inline void *next(void)
|
inline void *next(void)
|
||||||
{
|
{
|
||||||
prev=el;
|
prev=el;
|
||||||
@ -364,6 +375,8 @@ template <class T> class List_iterator :public base_list_iterator
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
List_iterator(List<T> &a) : base_list_iterator(a) {}
|
List_iterator(List<T> &a) : base_list_iterator(a) {}
|
||||||
|
List_iterator() : base_list_iterator() {}
|
||||||
|
inline void init(List<T> &a) { base_list_iterator::init(a); }
|
||||||
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
||||||
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
||||||
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
|
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
|
||||||
@ -385,6 +398,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
|
inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
|
||||||
|
inline List_iterator_fast() : base_list_iterator() {}
|
||||||
|
inline void init(List<T> &a) { base_list_iterator::init(a); }
|
||||||
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
|
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
|
||||||
inline void rewind(void) { base_list_iterator::rewind(); }
|
inline void rewind(void) { base_list_iterator::rewind(); }
|
||||||
void sublist(List<T> &list_arg, uint el_arg)
|
void sublist(List<T> &list_arg, uint el_arg)
|
||||||
|
@ -6585,36 +6585,39 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create a new name resolution context for a JOIN ... ON clause.
|
Push a new name resolution context for a JOIN ... ON clause to the
|
||||||
|
context stack of a query block.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
make_join_on_context()
|
push_new_name_resolution_context()
|
||||||
thd pointer to current thread
|
thd pointer to current thread
|
||||||
left_op left operand of the JOIN
|
left_op left operand of the JOIN
|
||||||
right_op rigth operand of the JOIN
|
right_op rigth operand of the JOIN
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Create a new name resolution context for a JOIN ... ON clause,
|
Create a new name resolution context for a JOIN ... ON clause,
|
||||||
and set the first and last leaves of the list of table references
|
set the first and last leaves of the list of table references
|
||||||
to be used for name resolution.
|
to be used for name resolution, and push the newly created
|
||||||
|
context to the stack of contexts of the query.
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
A new context if all is OK
|
FALSE if all is OK
|
||||||
NULL - if a memory allocation error occured
|
TRUE if a memory allocation error occured
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Name_resolution_context *
|
bool
|
||||||
make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op)
|
push_new_name_resolution_context(THD *thd,
|
||||||
|
TABLE_LIST *left_op, TABLE_LIST *right_op)
|
||||||
{
|
{
|
||||||
Name_resolution_context *on_context;
|
Name_resolution_context *on_context;
|
||||||
if (!(on_context= new (thd->mem_root) Name_resolution_context))
|
if (!(on_context= new (thd->mem_root) Name_resolution_context))
|
||||||
return NULL;
|
return TRUE;
|
||||||
on_context->init();
|
on_context->init();
|
||||||
on_context->first_name_resolution_table=
|
on_context->first_name_resolution_table=
|
||||||
left_op->first_leaf_for_name_resolution();
|
left_op->first_leaf_for_name_resolution();
|
||||||
on_context->last_name_resolution_table=
|
on_context->last_name_resolution_table=
|
||||||
right_op->last_leaf_for_name_resolution();
|
right_op->last_leaf_for_name_resolution();
|
||||||
return on_context;
|
return thd->lex->push_context(on_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5808,10 +5808,8 @@ join_table:
|
|||||||
{
|
{
|
||||||
YYERROR_UNLESS($1 && ($$=$3));
|
YYERROR_UNLESS($1 && ($$=$3));
|
||||||
/* Change the current name resolution context to a local context. */
|
/* Change the current name resolution context to a local context. */
|
||||||
Name_resolution_context *on_context;
|
if (push_new_name_resolution_context(YYTHD, $1, $3))
|
||||||
if (!(on_context= make_join_on_context(YYTHD,$1,$3)))
|
|
||||||
YYABORT;
|
YYABORT;
|
||||||
Lex->push_context(on_context);
|
|
||||||
}
|
}
|
||||||
expr
|
expr
|
||||||
{
|
{
|
||||||
@ -5823,10 +5821,8 @@ join_table:
|
|||||||
{
|
{
|
||||||
YYERROR_UNLESS($1 && ($$=$3));
|
YYERROR_UNLESS($1 && ($$=$3));
|
||||||
/* Change the current name resolution context to a local context. */
|
/* Change the current name resolution context to a local context. */
|
||||||
Name_resolution_context *on_context;
|
if (push_new_name_resolution_context(YYTHD, $1, $3))
|
||||||
if (!(on_context= make_join_on_context(YYTHD,$1,$3)))
|
|
||||||
YYABORT;
|
YYABORT;
|
||||||
Lex->push_context(on_context);
|
|
||||||
}
|
}
|
||||||
expr
|
expr
|
||||||
{
|
{
|
||||||
@ -5853,10 +5849,8 @@ join_table:
|
|||||||
ON
|
ON
|
||||||
{
|
{
|
||||||
/* Change the current name resolution context to a local context. */
|
/* Change the current name resolution context to a local context. */
|
||||||
Name_resolution_context *on_context;
|
if (push_new_name_resolution_context(YYTHD, $1, $5))
|
||||||
if (!(on_context= make_join_on_context(YYTHD,$1,$5)))
|
|
||||||
YYABORT;
|
YYABORT;
|
||||||
Lex->push_context(on_context);
|
|
||||||
}
|
}
|
||||||
expr
|
expr
|
||||||
{
|
{
|
||||||
@ -5886,10 +5880,8 @@ join_table:
|
|||||||
ON
|
ON
|
||||||
{
|
{
|
||||||
/* Change the current name resolution context to a local context. */
|
/* Change the current name resolution context to a local context. */
|
||||||
Name_resolution_context *on_context;
|
if (push_new_name_resolution_context(YYTHD, $1, $5))
|
||||||
if (!(on_context= make_join_on_context(YYTHD,$1,$5)))
|
|
||||||
YYABORT;
|
YYABORT;
|
||||||
Lex->push_context(on_context);
|
|
||||||
}
|
}
|
||||||
expr
|
expr
|
||||||
{
|
{
|
||||||
@ -5950,10 +5942,9 @@ table_factor:
|
|||||||
ON
|
ON
|
||||||
{
|
{
|
||||||
/* Change the current name resolution context to a local context. */
|
/* Change the current name resolution context to a local context. */
|
||||||
Name_resolution_context *on_context;
|
if (push_new_name_resolution_context(YYTHD, $3, $7))
|
||||||
if (!(on_context= make_join_on_context(YYTHD,$3,$7)))
|
|
||||||
YYABORT;
|
YYABORT;
|
||||||
Lex->push_context(on_context);
|
|
||||||
}
|
}
|
||||||
expr '}'
|
expr '}'
|
||||||
{
|
{
|
||||||
|
110
sql/table.cc
110
sql/table.cc
@ -3080,60 +3080,6 @@ GRANT_INFO *Natural_join_column::grant()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
|
|
||||||
/*
|
|
||||||
Check the access rights for the current join column.
|
|
||||||
columns.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
Natural_join_column::check_grants()
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Check the access rights to a column from a natural join in a generic
|
|
||||||
way that hides the heterogeneity of the column representation - whether
|
|
||||||
it is a view or a stored table colum.
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
FALSE The column can be accessed
|
|
||||||
TRUE There are no access rights to all equivalent columns
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool
|
|
||||||
Natural_join_column::check_grants(THD *thd, const char *name, uint length)
|
|
||||||
{
|
|
||||||
GRANT_INFO *grant;
|
|
||||||
const char *db_name;
|
|
||||||
const char *table_name;
|
|
||||||
Security_context *save_security_ctx= thd->security_ctx;
|
|
||||||
Security_context *new_sctx= table_ref->security_ctx;
|
|
||||||
bool res;
|
|
||||||
|
|
||||||
if (view_field)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(table_field == NULL);
|
|
||||||
grant= &(table_ref->grant);
|
|
||||||
db_name= table_ref->view_db.str;
|
|
||||||
table_name= table_ref->view_name.str;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(table_field && view_field == NULL);
|
|
||||||
grant= &(table_ref->table->grant);
|
|
||||||
db_name= table_ref->table->s->db.str;
|
|
||||||
table_name= table_ref->table->s->table_name.str;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_sctx)
|
|
||||||
thd->security_ctx= new_sctx;
|
|
||||||
res= check_grant_column(thd, grant, db_name, table_name, name, length);
|
|
||||||
thd->security_ctx= save_security_ctx;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void Field_iterator_view::set(TABLE_LIST *table)
|
void Field_iterator_view::set(TABLE_LIST *table)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(table->field_translation);
|
DBUG_ASSERT(table->field_translation);
|
||||||
@ -3176,8 +3122,9 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
|
|||||||
if (view->schema_table_reformed)
|
if (view->schema_table_reformed)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
In case of SHOW command (schema_table_reformed set) all items are
|
Translation table items are always Item_fields and already fixed
|
||||||
fixed
|
('mysql_schema_table' function). So we can return directly the
|
||||||
|
field. This case happens only for 'show & where' commands.
|
||||||
*/
|
*/
|
||||||
DBUG_ASSERT(field && field->fixed);
|
DBUG_ASSERT(field && field->fixed);
|
||||||
DBUG_RETURN(field);
|
DBUG_RETURN(field);
|
||||||
@ -3209,21 +3156,14 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
|
|||||||
void Field_iterator_natural_join::set(TABLE_LIST *table_ref)
|
void Field_iterator_natural_join::set(TABLE_LIST *table_ref)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(table_ref->join_columns);
|
DBUG_ASSERT(table_ref->join_columns);
|
||||||
delete column_ref_it;
|
column_ref_it.init(*(table_ref->join_columns));
|
||||||
|
cur_column_ref= column_ref_it++;
|
||||||
/*
|
|
||||||
TODO: try not to allocate new iterator every time. If we have to,
|
|
||||||
then check for out of memory condition.
|
|
||||||
*/
|
|
||||||
column_ref_it= new List_iterator_fast<Natural_join_column>
|
|
||||||
(*(table_ref->join_columns));
|
|
||||||
cur_column_ref= (*column_ref_it)++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Field_iterator_natural_join::next()
|
void Field_iterator_natural_join::next()
|
||||||
{
|
{
|
||||||
cur_column_ref= (*column_ref_it)++;
|
cur_column_ref= column_ref_it++;
|
||||||
DBUG_ASSERT(!cur_column_ref || ! cur_column_ref->table_field ||
|
DBUG_ASSERT(!cur_column_ref || ! cur_column_ref->table_field ||
|
||||||
cur_column_ref->table_ref->table ==
|
cur_column_ref->table_ref->table ==
|
||||||
cur_column_ref->table_field->table);
|
cur_column_ref->table_field->table);
|
||||||
@ -3350,7 +3290,6 @@ GRANT_INFO *Field_iterator_table_ref::grant()
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Field_iterator_table_ref::get_or_create_column_ref()
|
Field_iterator_table_ref::get_or_create_column_ref()
|
||||||
thd [in] pointer to current thread
|
|
||||||
is_created [out] set to TRUE if the column was created,
|
is_created [out] set to TRUE if the column was created,
|
||||||
FALSE if we return an already created colum
|
FALSE if we return an already created colum
|
||||||
|
|
||||||
@ -3363,7 +3302,7 @@ GRANT_INFO *Field_iterator_table_ref::grant()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Natural_join_column *
|
Natural_join_column *
|
||||||
Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created)
|
Field_iterator_table_ref::get_or_create_column_ref(bool *is_created)
|
||||||
{
|
{
|
||||||
Natural_join_column *nj_col;
|
Natural_join_column *nj_col;
|
||||||
|
|
||||||
@ -3397,6 +3336,41 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return an existing reference to a column of a natural/using join.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Field_iterator_table_ref::get_natural_column_ref()
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The method should be called in contexts where it is expected that
|
||||||
|
all natural join columns are already created, and that the column
|
||||||
|
being retrieved is a Natural_join_column.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
# Pointer to a column of a natural join (or its operand)
|
||||||
|
NULL No memory to allocate the column
|
||||||
|
*/
|
||||||
|
|
||||||
|
Natural_join_column *
|
||||||
|
Field_iterator_table_ref::get_natural_column_ref()
|
||||||
|
{
|
||||||
|
Natural_join_column *nj_col;
|
||||||
|
|
||||||
|
DBUG_ASSERT(field_it == &natural_join_it);
|
||||||
|
/*
|
||||||
|
The field belongs to a NATURAL join, therefore the column reference was
|
||||||
|
already created via one of the two constructor calls above. In this case
|
||||||
|
we just return the already created column reference.
|
||||||
|
*/
|
||||||
|
nj_col= natural_join_it.column_ref();
|
||||||
|
DBUG_ASSERT(nj_col &&
|
||||||
|
(!nj_col->table_field ||
|
||||||
|
nj_col->table_ref->table == nj_col->table_field->table));
|
||||||
|
return nj_col;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
** Instansiate templates
|
** Instansiate templates
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
12
sql/table.h
12
sql/table.h
@ -432,9 +432,6 @@ public:
|
|||||||
const char *table_name();
|
const char *table_name();
|
||||||
const char *db_name();
|
const char *db_name();
|
||||||
GRANT_INFO *grant();
|
GRANT_INFO *grant();
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
bool check_grants(THD *thd, const char *name, uint length);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -760,11 +757,11 @@ public:
|
|||||||
|
|
||||||
class Field_iterator_natural_join: public Field_iterator
|
class Field_iterator_natural_join: public Field_iterator
|
||||||
{
|
{
|
||||||
List_iterator_fast<Natural_join_column> *column_ref_it;
|
List_iterator_fast<Natural_join_column> column_ref_it;
|
||||||
Natural_join_column *cur_column_ref;
|
Natural_join_column *cur_column_ref;
|
||||||
public:
|
public:
|
||||||
Field_iterator_natural_join() :column_ref_it(NULL), cur_column_ref(NULL) {}
|
Field_iterator_natural_join() :cur_column_ref(NULL) {}
|
||||||
~Field_iterator_natural_join() { delete column_ref_it; }
|
~Field_iterator_natural_join() {}
|
||||||
void set(TABLE_LIST *table);
|
void set(TABLE_LIST *table);
|
||||||
void next();
|
void next();
|
||||||
bool end_of_fields() { return !cur_column_ref; }
|
bool end_of_fields() { return !cur_column_ref; }
|
||||||
@ -811,7 +808,8 @@ public:
|
|||||||
GRANT_INFO *grant();
|
GRANT_INFO *grant();
|
||||||
Item *create_item(THD *thd) { return field_it->create_item(thd); }
|
Item *create_item(THD *thd) { return field_it->create_item(thd); }
|
||||||
Field *field() { return field_it->field(); }
|
Field *field() { return field_it->field(); }
|
||||||
Natural_join_column *get_or_create_column_ref(THD *thd, bool *is_created);
|
Natural_join_column *get_or_create_column_ref(bool *is_created);
|
||||||
|
Natural_join_column *get_natural_column_ref();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user