Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-5.0
into sanja.is.com.ua:/home/bell/mysql/bk/work-5.0 mysql-test/r/view.result: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/sp_head.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_view.cc: Auto merged sql/table.h: Auto merged
This commit is contained in:
commit
d75ea9bcd6
@ -2384,7 +2384,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
|
||||
char buff[4 /* size of stmt id */ +
|
||||
5 /* execution flags */];
|
||||
DBUG_ENTER("execute");
|
||||
DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length));
|
||||
DBUG_DUMP("packet", packet, length);
|
||||
|
||||
mysql->last_used_con= mysql;
|
||||
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
|
||||
|
@ -1764,6 +1764,26 @@ call bug5251()|
|
||||
Table Checksum
|
||||
test.t1 0
|
||||
drop procedure bug5251|
|
||||
create procedure bug5287(param1 int)
|
||||
label1:
|
||||
begin
|
||||
declare c cursor for select 5;
|
||||
loop
|
||||
if param1 >= 0 then
|
||||
leave label1;
|
||||
end if;
|
||||
end loop;
|
||||
end|
|
||||
call bug5287(1)|
|
||||
drop procedure bug5287|
|
||||
create procedure bug5307()
|
||||
begin
|
||||
end; set @x = 3|
|
||||
call bug5307()|
|
||||
select @x|
|
||||
@x
|
||||
3
|
||||
drop procedure bug5307|
|
||||
drop table if exists fac|
|
||||
create table fac (n int unsigned not null primary key, f bigint unsigned)|
|
||||
create procedure ifac(n int unsigned)
|
||||
|
@ -1924,6 +1924,35 @@ call bug5251()|
|
||||
call bug5251()|
|
||||
drop procedure bug5251|
|
||||
|
||||
#
|
||||
# BUG#5287: Stored procedure crash if leave outside loop
|
||||
#
|
||||
create procedure bug5287(param1 int)
|
||||
label1:
|
||||
begin
|
||||
declare c cursor for select 5;
|
||||
|
||||
loop
|
||||
if param1 >= 0 then
|
||||
leave label1;
|
||||
end if;
|
||||
end loop;
|
||||
end|
|
||||
call bug5287(1)|
|
||||
drop procedure bug5287|
|
||||
|
||||
|
||||
#
|
||||
# BUG#5307: Stored procedure allows statement after BEGIN ... END
|
||||
#
|
||||
create procedure bug5307()
|
||||
begin
|
||||
end; set @x = 3|
|
||||
|
||||
call bug5307()|
|
||||
select @x|
|
||||
drop procedure bug5307|
|
||||
|
||||
|
||||
#
|
||||
# Some "real" examples
|
||||
|
21
sql/item.cc
21
sql/item.cc
@ -1143,8 +1143,27 @@ bool Item_param::convert_str_value(THD *thd)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* End of Item_param related */
|
||||
|
||||
void Item_param::print(String *str)
|
||||
{
|
||||
if (state == NO_VALUE)
|
||||
{
|
||||
str->append('?');
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[80];
|
||||
String tmp(buffer, sizeof(buffer), &my_charset_bin);
|
||||
const String *res;
|
||||
res= query_val_str(&tmp);
|
||||
str->append(*res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Item_copy_string
|
||||
****************************************************************************/
|
||||
|
||||
void Item_copy_string::copy()
|
||||
{
|
||||
|
@ -635,7 +635,7 @@ public:
|
||||
*/
|
||||
virtual table_map used_tables() const
|
||||
{ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
|
||||
void print(String *str) { str->append('?'); }
|
||||
void print(String *str);
|
||||
/* parameter never equal to other parameter of other item */
|
||||
bool eq(const Item *item, bool binary_cmp) const { return 0; }
|
||||
};
|
||||
|
@ -995,23 +995,6 @@ Item_in_subselect::select_transformer(JOIN *join)
|
||||
}
|
||||
|
||||
|
||||
Item_subselect::trans_res
|
||||
Item_in_subselect::no_select_transform()
|
||||
{
|
||||
DBUG_ENTER("Item_in_subselect::no_select_transform");
|
||||
// We have execute fix_fields() for left expression
|
||||
SELECT_LEX *current= thd->lex->current_select, *up;
|
||||
thd->lex->current_select= up= current->return_after_parsing();
|
||||
if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
|
||||
{
|
||||
thd->lex->current_select= current;
|
||||
DBUG_RETURN(RES_ERROR);
|
||||
}
|
||||
thd->lex->current_select= current;
|
||||
DBUG_RETURN(RES_OK);
|
||||
}
|
||||
|
||||
|
||||
void Item_in_subselect::print(String *str)
|
||||
{
|
||||
if (transformed)
|
||||
|
@ -84,7 +84,6 @@ public:
|
||||
null_value= 1;
|
||||
}
|
||||
virtual trans_res select_transformer(JOIN *join);
|
||||
virtual trans_res no_select_transform() { return RES_OK; }
|
||||
bool assigned() { return value_assigned; }
|
||||
void assigned(bool a) { value_assigned= a; }
|
||||
enum Type type() const;
|
||||
@ -220,7 +219,6 @@ public:
|
||||
was_null= 0;
|
||||
}
|
||||
trans_res select_transformer(JOIN *join);
|
||||
trans_res no_select_transform();
|
||||
trans_res single_value_transformer(JOIN *join,
|
||||
Comp_creator *func);
|
||||
trans_res row_value_transformer(JOIN * join);
|
||||
|
10
sql/log.cc
10
sql/log.cc
@ -838,13 +838,13 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
||||
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
|
||||
!log_in_use(log_info.log_file_name))
|
||||
{
|
||||
ulong tmp;
|
||||
LINT_INIT(tmp);
|
||||
ulong file_size;
|
||||
LINT_INIT(file_size);
|
||||
if (decrease_log_space) //stat the file we want to delete
|
||||
{
|
||||
MY_STAT s;
|
||||
if (my_stat(log_info.log_file_name,&s,MYF(0)))
|
||||
tmp= s.st_size;
|
||||
file_size= s.st_size;
|
||||
else
|
||||
{
|
||||
/*
|
||||
@ -852,7 +852,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
||||
of space that deletion will free. In most cases,
|
||||
deletion won't work either, so it's not a problem.
|
||||
*/
|
||||
tmp= 0;
|
||||
file_size= 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -861,7 +861,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
||||
*/
|
||||
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
|
||||
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
|
||||
*decrease_log_space-= tmp;
|
||||
*decrease_log_space-= file_size;
|
||||
if (find_next_log(&log_info, 0) || exit_loop)
|
||||
break;
|
||||
}
|
||||
|
@ -398,8 +398,9 @@ void free_items(Item *item);
|
||||
void cleanup_items(Item *item);
|
||||
class THD;
|
||||
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
|
||||
int check_one_table_access(THD *thd, ulong privilege,
|
||||
bool check_one_table_access(THD *thd, ulong privilege,
|
||||
TABLE_LIST *tables);
|
||||
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
|
||||
bool check_merge_table_access(THD *thd, char *db,
|
||||
TABLE_LIST *table_list);
|
||||
int multi_update_precheck(THD *thd, TABLE_LIST *tables);
|
||||
@ -767,12 +768,10 @@ void free_io_cache(TABLE *entry);
|
||||
void intern_close_table(TABLE *entry);
|
||||
bool close_thread_table(THD *thd, TABLE **table_ptr);
|
||||
void close_temporary_tables(THD *thd);
|
||||
TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name);
|
||||
TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name);
|
||||
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
uint offset_to_list,
|
||||
const char *db_name,
|
||||
const char *table_name);
|
||||
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||
void close_temporary(TABLE *table, bool delete_table=1);
|
||||
@ -788,6 +787,23 @@ int fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors);
|
||||
int fill_record(Field **field,List<Item> &values, bool ignore_errors);
|
||||
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
|
||||
|
||||
inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name)
|
||||
{
|
||||
return find_table_in_list(table, offsetof(TABLE_LIST, next_global),
|
||||
db_name, table_name);
|
||||
}
|
||||
|
||||
inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name)
|
||||
{
|
||||
return find_table_in_list(table, offsetof(TABLE_LIST, next_local),
|
||||
db_name, table_name);
|
||||
}
|
||||
|
||||
|
||||
/* sql_calc.cc */
|
||||
bool eval_const_cond(COND *cond);
|
||||
|
||||
|
@ -288,6 +288,7 @@ void
|
||||
sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
|
||||
{
|
||||
DBUG_ENTER("sp_head::init_strings");
|
||||
uint n; /* Counter for nul trimming */
|
||||
/* During parsing, we must use thd->mem_root */
|
||||
MEM_ROOT *root= &thd->mem_root;
|
||||
|
||||
@ -351,9 +352,17 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
|
||||
(char *)m_returns_begin, m_retstr.length);
|
||||
}
|
||||
}
|
||||
m_body.length= lex->end_of_query - m_body_begin;
|
||||
m_body.length= lex->ptr - m_body_begin;
|
||||
/* Trim nuls at the end */
|
||||
n= 0;
|
||||
while (m_body.length && m_body_begin[m_body.length-1] == '\0')
|
||||
{
|
||||
m_body.length-= 1;
|
||||
n+= 1;
|
||||
}
|
||||
m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
|
||||
m_defstr.length= lex->end_of_query - lex->buf;
|
||||
m_defstr.length= lex->ptr - lex->buf;
|
||||
m_defstr.length-= n;
|
||||
m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
sp_pcontext::sp_pcontext(sp_pcontext *prev)
|
||||
: Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
|
||||
m_parent(prev), m_handlers(0)
|
||||
m_handlers(0), m_parent(prev)
|
||||
{
|
||||
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
|
||||
@ -94,7 +94,7 @@ sp_pcontext::diff_handlers(sp_pcontext *ctx)
|
||||
|
||||
while (pctx && pctx != ctx)
|
||||
{
|
||||
n+= pctx->max_handlers();
|
||||
n+= pctx->m_handlers;
|
||||
pctx= pctx->parent_context();
|
||||
}
|
||||
if (pctx)
|
||||
@ -109,12 +109,9 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx)
|
||||
sp_pcontext *pctx= this;
|
||||
|
||||
while (pctx && pctx != ctx)
|
||||
{
|
||||
n+= pctx->max_cursors();
|
||||
pctx= pctx->parent_context();
|
||||
}
|
||||
if (pctx)
|
||||
return n;
|
||||
return ctx->current_cursors() - pctx->current_cursors();
|
||||
return 0; // Didn't find ctx
|
||||
}
|
||||
|
||||
|
@ -275,6 +275,7 @@ protected:
|
||||
uint m_psubsize;
|
||||
uint m_csubsize;
|
||||
uint m_hsubsize;
|
||||
uint m_handlers; // No. of handlers in this context
|
||||
|
||||
private:
|
||||
|
||||
@ -282,7 +283,6 @@ private:
|
||||
|
||||
uint m_poffset; // Variable offset for this context
|
||||
uint m_coffset; // Cursor offset for this context
|
||||
uint m_handlers; // No. of handlers in this context
|
||||
|
||||
DYNAMIC_ARRAY m_pvar; // Parameters/variables
|
||||
DYNAMIC_ARRAY m_cond; // Conditions
|
||||
|
@ -2761,7 +2761,22 @@ void grant_reload(THD *thd)
|
||||
|
||||
/****************************************************************************
|
||||
Check table level grants
|
||||
All errors are written directly to the client if no_errors is given !
|
||||
|
||||
SYNPOSIS
|
||||
bool check_grant()
|
||||
thd Thread handler
|
||||
want_access Bits of privileges user needs to have
|
||||
tables List of tables to check. The user should have 'want_access'
|
||||
to all tables in list.
|
||||
show_table <> 0 if we are in show table. In this case it's enough to have
|
||||
any privilege for the table
|
||||
number Check at most this number of tables.
|
||||
no_errors If 0 then we write an error. The error is sent directly to
|
||||
the client
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error: User did not have the requested privielges
|
||||
****************************************************************************/
|
||||
|
||||
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||
@ -2769,14 +2784,17 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
char *user = thd->priv_user;
|
||||
DBUG_ENTER("check_grant");
|
||||
DBUG_ASSERT(number > 0);
|
||||
|
||||
want_access &= ~thd->master_access;
|
||||
want_access&= ~thd->master_access;
|
||||
if (!want_access)
|
||||
return 0; // ok
|
||||
DBUG_RETURN(0); // ok
|
||||
|
||||
rw_rdlock(&LOCK_grant);
|
||||
for (table= tables; table && number--; table= table->next_global)
|
||||
{
|
||||
GRANT_TABLE *grant_table;
|
||||
if (!(~table->grant.privilege & want_access) || table->derived)
|
||||
{
|
||||
/*
|
||||
@ -2786,10 +2804,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||
table->grant.want_privilege= 0;
|
||||
continue; // Already checked
|
||||
}
|
||||
GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
|
||||
table->db,user,
|
||||
table->real_name,0);
|
||||
if (!grant_table)
|
||||
if (!(grant_table= table_hash_search(thd->host,thd->ip,
|
||||
table->db,user, table->real_name,0)))
|
||||
{
|
||||
want_access &= ~table->grant.privilege;
|
||||
goto err; // No grants
|
||||
@ -2813,7 +2829,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||
}
|
||||
}
|
||||
rw_unlock(&LOCK_grant);
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
rw_unlock(&LOCK_grant);
|
||||
@ -2848,7 +2864,7 @@ err:
|
||||
thd->host_or_ip,
|
||||
table ? table->real_name : "unknown");
|
||||
}
|
||||
return 1;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
@ -2942,7 +2958,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
|
||||
if (!(grant_table= grant->grant_table))
|
||||
goto err; /* purecov: inspected */
|
||||
|
||||
for (; fields->end(); fields->next())
|
||||
for (; !fields->end_of_fields(); fields->next())
|
||||
{
|
||||
const char *field_name= fields->name();
|
||||
grant_column= column_hash_search(grant_table, field_name,
|
||||
|
212
sql/sql_base.cc
212
sql/sql_base.cc
@ -549,81 +549,37 @@ void close_temporary_tables(THD *thd)
|
||||
thd->temporary_tables=0;
|
||||
}
|
||||
|
||||
#ifdef UNUSED
|
||||
|
||||
/*
|
||||
Find first suitable table by alias in given list.
|
||||
Find table in list.
|
||||
|
||||
SYNOPSIS
|
||||
find_table_in_list()
|
||||
table - pointer to table list
|
||||
db_name - data base name or 0 for any
|
||||
table_name - table name or 0 for any
|
||||
table Pointer to table list
|
||||
offset Offset to which list in table structure to use
|
||||
db_name Data base name
|
||||
table_name Table name
|
||||
|
||||
NOTES:
|
||||
This is called by find_table_in_local_list() and
|
||||
find_table_in_global_list().
|
||||
|
||||
RETURN VALUES
|
||||
NULL Table not found
|
||||
# Pointer to found table.
|
||||
*/
|
||||
|
||||
TABLE_LIST * find_table_in_list(TABLE_LIST *table,
|
||||
const char *db_name, const char *table_name)
|
||||
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
uint offset,
|
||||
const char *db_name,
|
||||
const char *table_name)
|
||||
{
|
||||
for (; table; table= table->next)
|
||||
if ((!db_name || !strcmp(table->db, db_name)) &&
|
||||
(!table_name || !my_strcasecmp(table_alias_charset,
|
||||
table->alias, table_name)))
|
||||
break;
|
||||
return table;
|
||||
}
|
||||
#endif /*UNUSED*/
|
||||
|
||||
/*
|
||||
Find real table in given global list.
|
||||
|
||||
SYNOPSIS
|
||||
find_real_table_in_list()
|
||||
table - pointer to table list
|
||||
db_name - data base name
|
||||
table_name - table name
|
||||
|
||||
RETURN VALUES
|
||||
NULL Table not found
|
||||
# Pointer to found table.
|
||||
*/
|
||||
|
||||
TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name)
|
||||
{
|
||||
for (; table; table= table->next_global)
|
||||
if (!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name))
|
||||
break;
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find real table in given local list.
|
||||
|
||||
SYNOPSIS
|
||||
find_real_table_in_local_list()
|
||||
table - pointer to table list
|
||||
db_name - data base name
|
||||
table_name - table name
|
||||
|
||||
RETURN VALUES
|
||||
NULL Table not found
|
||||
# Pointer to found table.
|
||||
*/
|
||||
|
||||
TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name)
|
||||
{
|
||||
for (; table; table= table->next_local)
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if (!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name))
|
||||
break;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
@ -1364,7 +1320,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
|
||||
db Database name
|
||||
name Table name
|
||||
alias Alias name
|
||||
table_desc TABLE_LIST descriptor
|
||||
table_desc TABLE_LIST descriptor (used with views)
|
||||
mem_root temporary mem_root for parsing
|
||||
|
||||
NOTES
|
||||
@ -1402,10 +1358,10 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
||||
if (!entry->crashed)
|
||||
{
|
||||
/*
|
||||
Frm file could not be found on disk
|
||||
Since it does not exist, no one can be using it
|
||||
LOCK_open has been locked to protect from someone else
|
||||
trying to discover the table at the same time.
|
||||
Frm file could not be found on disk
|
||||
Since it does not exist, no one can be using it
|
||||
LOCK_open has been locked to protect from someone else
|
||||
trying to discover the table at the same time.
|
||||
*/
|
||||
if (discover_retry_count++ != 0)
|
||||
goto err;
|
||||
@ -1610,7 +1566,7 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
||||
tables->table->grant= tables->grant;
|
||||
}
|
||||
thd->proc_info=0;
|
||||
free_root(&new_frm_mem, MYF(0));
|
||||
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
@ -1680,7 +1636,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
|
||||
thd->current_tablenr= 0;
|
||||
/* open_ltable can be used only for BASIC TABLEs */
|
||||
table_list->required_type= FRMTYPE_TABLE;
|
||||
while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) ;
|
||||
while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh)
|
||||
;
|
||||
|
||||
if (table)
|
||||
{
|
||||
@ -1910,7 +1867,7 @@ bool rm_temporary_table(enum db_type base, char *path)
|
||||
** return unique field
|
||||
******************************************************************************/
|
||||
|
||||
// Special Field pointers for find_field_in_tables returning
|
||||
/* Special Field pointers for find_field_in_tables returning */
|
||||
const Field *not_found_field= (Field*) 0x1;
|
||||
const Field *view_ref_found= (Field*) 0x2;
|
||||
|
||||
@ -2006,6 +1963,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
return fld;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find field in table
|
||||
|
||||
@ -2595,23 +2553,47 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
This just drops in all fields instead of current '*' field
|
||||
Returns pointer to last inserted field if ok
|
||||
****************************************************************************/
|
||||
/*
|
||||
Drops in all fields instead of current '*' field
|
||||
|
||||
SYNOPSIS
|
||||
insert_fields()
|
||||
thd Thread handler
|
||||
tables List of tables
|
||||
db_name Database name in case of 'database_name.table_name.*'
|
||||
table_name Table name in case of 'table_name.*'
|
||||
it Pointer to '*'
|
||||
any_privileges 0 If we should ensure that we have SELECT privileges
|
||||
for all columns
|
||||
1 If any privilege is ok
|
||||
RETURN
|
||||
0 ok
|
||||
'it' is updated to point at last inserted
|
||||
1 error. The error message is sent to client
|
||||
*/
|
||||
|
||||
bool
|
||||
insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
const char *table_name, List_iterator<Item> *it,
|
||||
bool any_privileges)
|
||||
{
|
||||
/* allocate variables on stack to avoid pool alloaction */
|
||||
Field_iterator_table table_iter;
|
||||
Field_iterator_view view_iter;
|
||||
uint found;
|
||||
DBUG_ENTER("insert_fields");
|
||||
|
||||
found=0;
|
||||
found= 0;
|
||||
for (; tables; tables= tables->next_local)
|
||||
{
|
||||
TABLE *table=tables->table;
|
||||
Field_iterator *iterator;
|
||||
TABLE_LIST *natural_join_table;
|
||||
Field *field;
|
||||
TABLE_LIST *embedded;
|
||||
TABLE_LIST *last;
|
||||
TABLE_LIST *embedding;
|
||||
TABLE *table= tables->table;
|
||||
|
||||
if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
|
||||
tables->alias) &&
|
||||
(!db_name || !strcmp(tables->db,db_name))))
|
||||
@ -2622,36 +2604,26 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
{
|
||||
if (tables->view)
|
||||
{
|
||||
Field_iterator_view fields;
|
||||
fields.set(tables);
|
||||
view_iter.set(tables);
|
||||
if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant,
|
||||
tables->view_db.str,
|
||||
tables->view_name.str,
|
||||
&fields))
|
||||
DBUG_RETURN(1);
|
||||
&view_iter))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
Field_iterator_table fields;
|
||||
fields.set(tables);
|
||||
table_iter.set(tables);
|
||||
if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
|
||||
table->table_cache_key, table->real_name,
|
||||
&fields))
|
||||
DBUG_RETURN(1);
|
||||
&table_iter))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* allocate 2 variables on stack to avoid pool alloaction */
|
||||
Field_iterator_table table_iter;
|
||||
Field_iterator_view view_iter;
|
||||
Field_iterator *iterator;
|
||||
TABLE_LIST *natural_join_table= 0;
|
||||
Field *field;
|
||||
|
||||
thd->used_tables|=table->map;
|
||||
TABLE_LIST *embedded= tables;
|
||||
TABLE_LIST *last= embedded;
|
||||
TABLE_LIST *embedding;
|
||||
natural_join_table= 0;
|
||||
thd->used_tables|= table->map;
|
||||
last= embedded= tables;
|
||||
|
||||
while ((embedding= embedded->embedding) &&
|
||||
embedding->join_list->elements != 1)
|
||||
@ -2682,7 +2654,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
iterator= &table_iter;
|
||||
iterator->set(tables);
|
||||
|
||||
for (; iterator->end(); iterator->next())
|
||||
for (; !iterator->end_of_fields(); iterator->next())
|
||||
{
|
||||
Item *not_used_item;
|
||||
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
|
||||
@ -2734,9 +2706,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
thd->host_or_ip,
|
||||
fld->field_name,
|
||||
tab);
|
||||
/* TODO: should be removed to have only one send_error */
|
||||
send_error(thd);
|
||||
DBUG_RETURN(1);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2770,15 +2740,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
table->used_fields=table->fields;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (!table_name)
|
||||
my_error(ER_NO_TABLES_USED,MYF(0));
|
||||
else
|
||||
my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name);
|
||||
send_error(thd);
|
||||
}
|
||||
DBUG_RETURN(!found);
|
||||
if (found)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (!table_name)
|
||||
my_error(ER_NO_TABLES_USED, MYF(0));
|
||||
else
|
||||
my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
|
||||
|
||||
err:
|
||||
send_error(thd);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
@ -2867,13 +2839,16 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
|
||||
if (arena)
|
||||
thd->set_n_backup_item_arena(arena, &backup);
|
||||
|
||||
TABLE *t1=tab1->table;
|
||||
TABLE *t2=tab2->table;
|
||||
/* allocate 2 variables on stack to avoid pool alloaction */
|
||||
Field_iterator_table table_iter;
|
||||
Field_iterator_view view_iter;
|
||||
Field_iterator *iterator;
|
||||
Field *t1_field, *t2_field;
|
||||
Item *item_t2;
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
|
||||
if (!cond_and) // If not out of memory
|
||||
DBUG_RETURN(1);
|
||||
cond_and->top_level_item();
|
||||
@ -2889,9 +2864,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
table_iter.set(tab1);
|
||||
}
|
||||
|
||||
Field *t1_field, *t2_field;
|
||||
Item *item_t2;
|
||||
for (; iterator->end(); iterator->next())
|
||||
for (; !iterator->end_of_fields(); iterator->next())
|
||||
{
|
||||
const char *t1_field_name= iterator->name();
|
||||
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
|
||||
@ -3228,6 +3201,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
|
||||
table_desc TABLE_LIST descriptor
|
||||
mem_root temporary MEM_ROOT for parsing
|
||||
*/
|
||||
|
||||
static my_bool
|
||||
open_new_frm(const char *path, const char *alias,
|
||||
const char *db, const char *table_name,
|
||||
@ -3235,16 +3209,17 @@ open_new_frm(const char *path, const char *alias,
|
||||
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
|
||||
MEM_ROOT *mem_root)
|
||||
{
|
||||
DBUG_ENTER("open_new_frm");
|
||||
LEX_STRING pathstr;
|
||||
pathstr.str= (char *)path;
|
||||
File_parser *parser;
|
||||
DBUG_ENTER("open_new_frm");
|
||||
|
||||
pathstr.str= (char*) path;
|
||||
pathstr.length= strlen(path);
|
||||
|
||||
if (!mem_root)
|
||||
mem_root= ¤t_thd->mem_root;
|
||||
|
||||
File_parser *parser= sql_parse_prepare(&pathstr, mem_root, 1);
|
||||
if (parser)
|
||||
if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
|
||||
{
|
||||
if (!strncmp("VIEW", parser->type()->str, parser->type()->length))
|
||||
{
|
||||
@ -3262,12 +3237,9 @@ open_new_frm(const char *path, const char *alias,
|
||||
my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str);
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else
|
||||
goto err;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
|
||||
|
||||
err:
|
||||
bzero(outparam, sizeof(TABLE)); // do not run repair
|
||||
DBUG_RETURN(1);
|
||||
|
@ -282,7 +282,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (find_real_table_in_list(table_list->next_global,
|
||||
if (find_table_in_global_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
|
@ -51,6 +51,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
List<Item> &values, ulong counter, bool check_unique)
|
||||
{
|
||||
TABLE *table= table_list->table;
|
||||
|
||||
if (fields.elements == 0 && values.elements != 0)
|
||||
{
|
||||
if (values.elements != table->fields)
|
||||
@ -61,11 +62,11 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
return -1;
|
||||
}
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (grant_option)
|
||||
{
|
||||
Field_iterator_table fields;
|
||||
fields.set_table(table);
|
||||
if (grant_option &&
|
||||
check_grant_all_columns(thd, INSERT_ACL, &table->grant,
|
||||
if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
|
||||
table->table_cache_key, table->real_name,
|
||||
&fields))
|
||||
return -1;
|
||||
@ -75,7 +76,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
}
|
||||
else
|
||||
{ // Part field list
|
||||
TABLE_LIST *save_next= table_list->next_local;
|
||||
TABLE_LIST *save_next;
|
||||
int res;
|
||||
if (fields.elements != values.elements)
|
||||
{
|
||||
@ -85,16 +86,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
return -1;
|
||||
}
|
||||
|
||||
table_list->next_local= 0;
|
||||
thd->dupp_field=0;
|
||||
thd->lex->select_lex.no_wrap_view_item= 1;
|
||||
save_next= table_list->next_local; // fields only from first table
|
||||
table_list->next_local= 0;
|
||||
res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
|
||||
thd->lex->select_lex.no_wrap_view_item= 0;
|
||||
table_list->next_local= save_next;
|
||||
thd->lex->select_lex.no_wrap_view_item= 0;
|
||||
if (res)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (check_unique && thd->dupp_field)
|
||||
{
|
||||
@ -410,7 +410,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
!thd->cuted_fields))
|
||||
{
|
||||
thd->row_count_func= info.copied+info.deleted+info.updated;
|
||||
send_ok(thd, (ulong) (ulong) thd->row_count_func, id);
|
||||
send_ok(thd, (ulong) thd->row_count_func, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -423,7 +423,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
|
||||
(ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
|
||||
thd->row_count_func= info.copied+info.deleted+info.updated;
|
||||
::send_ok(thd, (ulong) thd->row_count_func, (ulonglong)id,buff);
|
||||
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
|
||||
}
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
@ -447,46 +447,58 @@ abort:
|
||||
check_view_insertability()
|
||||
view - reference on VIEW
|
||||
|
||||
IMPLEMENTATION
|
||||
A view is insertable if the folloings are true:
|
||||
- All columns in the view are columns from a table
|
||||
- All not used columns in table have a default values
|
||||
- All field in view are unique (not referring to the same column)
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
view->contain_auto_increment is 1 if and only if the view contains an
|
||||
auto_increment field
|
||||
|
||||
TRUE - can't be used for insert
|
||||
*/
|
||||
|
||||
static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
uint num= view->view->select_lex.item_list.elements;
|
||||
TABLE *table= view->table;
|
||||
Item **trans_start= view->field_translation, **trans_end=trans_start+num;
|
||||
Item **trans;
|
||||
Field **field_ptr= table->field;
|
||||
ulong other_query_id= query_id - 1;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
|
||||
uint i;
|
||||
TABLE *table= view->table;
|
||||
Item **trans= view->field_translation;
|
||||
Field **field_ptr= table->field;
|
||||
uint num= view->view->select_lex.item_list.elements;
|
||||
ulong other_query_id= query_id - 1;
|
||||
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
|
||||
|
||||
view->contain_auto_increment= 0;
|
||||
/* check simplicity and prepare unique test of view */
|
||||
for (i= 0; i < num; i++)
|
||||
for (trans= trans_start; trans != trans_end; trans++)
|
||||
{
|
||||
Item_field *field;
|
||||
/* simple SELECT list entry (field without expression) */
|
||||
if (trans[i]->type() != Item::FIELD_ITEM)
|
||||
if ((*trans)->type() != Item::FIELD_ITEM)
|
||||
DBUG_RETURN(TRUE);
|
||||
if (((Item_field *)trans[i])->field->unireg_check == Field::NEXT_NUMBER)
|
||||
field= (Item_field *)(*trans);
|
||||
if (field->field->unireg_check == Field::NEXT_NUMBER)
|
||||
view->contain_auto_increment= 1;
|
||||
/* prepare unique test */
|
||||
((Item_field *)trans[i])->field->query_id= other_query_id;
|
||||
field->field->query_id= other_query_id;
|
||||
}
|
||||
/* unique test */
|
||||
for (i= 0; i < num; i++)
|
||||
for (trans= trans_start; trans != trans_end; trans++)
|
||||
{
|
||||
Item_field *field= (Item_field *)trans[i];
|
||||
/* Thanks to test above, we know that all columns are of type Item_field */
|
||||
Item_field *field= (Item_field *)(*trans);
|
||||
if (field->field->query_id == query_id)
|
||||
DBUG_RETURN(TRUE);
|
||||
field->field->query_id= query_id;
|
||||
}
|
||||
|
||||
/* VIEW contain all fields without default value */
|
||||
for (; *field_ptr; ++field_ptr)
|
||||
for (; *field_ptr; field_ptr++)
|
||||
{
|
||||
Field *field= *field_ptr;
|
||||
/* field have not default value */
|
||||
@ -494,14 +506,13 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
(table->timestamp_field != field ||
|
||||
field->unireg_check == Field::TIMESTAMP_UN_FIELD))
|
||||
{
|
||||
uint i= 0;
|
||||
for (; i < num; i++)
|
||||
for (trans= trans_start; ; trans++)
|
||||
{
|
||||
if (((Item_field *)trans[i])->field == *field_ptr)
|
||||
break;
|
||||
if (trans == trans_end)
|
||||
DBUG_RETURN(TRUE); // Field was not part of view
|
||||
if (((Item_field *)(*trans))->field == *field_ptr)
|
||||
break; // ok
|
||||
}
|
||||
if (i >= num)
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
@ -509,29 +520,28 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
|
||||
|
||||
/*
|
||||
Prepare items in INSERT statement
|
||||
Check if table can be updated
|
||||
|
||||
SYNOPSIS
|
||||
mysql_prepare_insert()
|
||||
thd - thread handler
|
||||
table_list - global/local table list
|
||||
mysql_prepare_insert_check_table()
|
||||
thd Thread handle
|
||||
table_list Table list (only one table)
|
||||
fields List of fields to be updated
|
||||
where Pointer to where clause
|
||||
|
||||
RETURN VALUE
|
||||
0 - OK
|
||||
-1 - error (message is not sent to user)
|
||||
RETURN
|
||||
0 ok
|
||||
1 ERROR
|
||||
*/
|
||||
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
List<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields, List<Item> &update_values,
|
||||
enum_duplicates duplic)
|
||||
|
||||
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> &fields, COND **where)
|
||||
{
|
||||
bool insert_into_view= (table_list->view != 0);
|
||||
DBUG_ENTER("mysql_prepare_insert");
|
||||
DBUG_ENTER("mysql_prepare_insert_check_table");
|
||||
|
||||
/* TODO: use this condition for 'WHITH CHECK OPTION' */
|
||||
Item *unused_conds= 0;
|
||||
if (setup_tables(thd, table_list, &unused_conds))
|
||||
DBUG_RETURN(-1);
|
||||
if (setup_tables(thd, table_list, where))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (insert_into_view && !fields.elements)
|
||||
{
|
||||
@ -545,8 +555,37 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
check_view_insertability(table_list, thd->query_id)))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
|
||||
DBUG_RETURN(-1);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Prepare items in INSERT statement
|
||||
|
||||
SYNOPSIS
|
||||
mysql_prepare_insert()
|
||||
thd Thread handler
|
||||
table_list Global/local table list
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
-1 error (message is not sent to user)
|
||||
*/
|
||||
|
||||
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
List<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields, List<Item> &update_values,
|
||||
enum_duplicates duplic)
|
||||
{
|
||||
bool insert_into_view= (table_list->view != 0);
|
||||
/* TODO: use this condition for 'WITH CHECK OPTION' */
|
||||
Item *unused_conds= 0;
|
||||
DBUG_ENTER("mysql_prepare_insert");
|
||||
|
||||
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (check_insert_fields(thd, table_list, fields, *values, 1,
|
||||
!insert_into_view) ||
|
||||
@ -556,7 +595,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (find_real_table_in_list(table_list->next_global,
|
||||
if (find_table_in_global_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
@ -1558,27 +1597,11 @@ bool delayed_insert::handle_inserts(void)
|
||||
int mysql_insert_select_prepare(THD *thd)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
TABLE_LIST *table_list= lex->query_tables;
|
||||
bool insert_into_view= (table_list->view != 0);
|
||||
DBUG_ENTER("mysql_insert_select_prepare");
|
||||
|
||||
if (setup_tables(thd, table_list, &lex->select_lex.where))
|
||||
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
|
||||
lex->field_list,
|
||||
&lex->select_lex.where))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (insert_into_view && !lex->field_list.elements)
|
||||
{
|
||||
lex->empty_field_list_on_rset= 1;
|
||||
insert_view_fields(&lex->field_list, table_list);
|
||||
}
|
||||
|
||||
if (!table_list->updatable ||
|
||||
check_key_in_view(thd, table_list) ||
|
||||
(insert_into_view &&
|
||||
check_view_insertability(table_list, thd->query_id)))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -1421,7 +1421,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
|
||||
*/
|
||||
bool st_select_lex::check_updateable(char *db, char *table)
|
||||
{
|
||||
if (find_real_table_in_local_list(get_table_list(), db, table))
|
||||
if (find_table_in_local_list(get_table_list(), db, table))
|
||||
return 1;
|
||||
|
||||
for (SELECT_LEX_UNIT *un= first_inner_unit();
|
||||
@ -1662,14 +1662,16 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
|
||||
|
||||
SYNOPSIS
|
||||
unlink_first_table()
|
||||
link_to_local do we need link this table to local
|
||||
link_to_local Set to 1 if caller should link this table to local
|
||||
|
||||
NOTES
|
||||
We rely on fact that first table in both list are same or local list
|
||||
is empty
|
||||
|
||||
RETURN
|
||||
0 If 'query_tables' == 0
|
||||
unlinked table
|
||||
In this case link_to_local is set.
|
||||
|
||||
*/
|
||||
TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
|
||||
@ -1723,11 +1725,11 @@ void st_lex::first_lists_tables_same()
|
||||
TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
|
||||
if (query_tables != first_table && first_table != 0)
|
||||
{
|
||||
TABLE_LIST *next;
|
||||
if (query_tables_last == &first_table->next_global)
|
||||
query_tables_last= first_table->prev_global;
|
||||
TABLE_LIST *next= *first_table->prev_global= first_table->next_global;
|
||||
first_table->next_global= 0;
|
||||
if (next)
|
||||
|
||||
if ((next= *first_table->prev_global= first_table->next_global))
|
||||
next->prev_global= first_table->prev_global;
|
||||
/* include in new place */
|
||||
first_table->next_global= query_tables;
|
||||
|
@ -78,6 +78,7 @@ const char *command_name[]={
|
||||
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
|
||||
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
|
||||
"Prepare", "Prepare Execute", "Long Data", "Close stmt",
|
||||
"Reset stmt", "Set option", "Fetch",
|
||||
"Error" // Last command number
|
||||
};
|
||||
|
||||
@ -1910,7 +1911,7 @@ mysql_execute_command(THD *thd)
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
*/
|
||||
lex->first_lists_tables_same();
|
||||
/* should be assigned after making firts tables same */
|
||||
/* should be assigned after making first tables same */
|
||||
all_tables= lex->query_tables;
|
||||
|
||||
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
|
||||
@ -2386,8 +2387,8 @@ mysql_execute_command(THD *thd)
|
||||
of query
|
||||
*/
|
||||
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
|
||||
find_real_table_in_list(select_tables, create_table->db,
|
||||
create_table->real_name))
|
||||
find_table_in_global_list(select_tables, create_table->db,
|
||||
create_table->real_name))
|
||||
{
|
||||
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
|
||||
goto create_error;
|
||||
@ -2756,7 +2757,7 @@ unsent_create_error:
|
||||
unit->set_limit(select_lex, select_lex);
|
||||
|
||||
// is table which we are changing used somewhere in other parts of query
|
||||
if (find_real_table_in_list(all_tables->next_global,
|
||||
if (find_table_in_global_list(all_tables->next_global,
|
||||
first_table->db, first_table->real_name))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
@ -3915,7 +3916,7 @@ error:
|
||||
1 - access denied, error is sent to client
|
||||
*/
|
||||
|
||||
int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
|
||||
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
|
||||
{
|
||||
if (check_access(thd, privilege, all_tables->db,
|
||||
&all_tables->grant.privilege, 0, 0))
|
||||
@ -3959,13 +3960,13 @@ bool
|
||||
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
|
||||
bool dont_check_global_grants, bool no_errors)
|
||||
{
|
||||
DBUG_ENTER("check_access");
|
||||
DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access,
|
||||
thd->master_access));
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
ulong db_access;
|
||||
#endif
|
||||
ulong dummy;
|
||||
DBUG_ENTER("check_access");
|
||||
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
|
||||
db ? db : "", want_access, thd->master_access));
|
||||
if (save_priv)
|
||||
*save_priv=0;
|
||||
else
|
||||
@ -3973,8 +3974,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
|
||||
|
||||
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
|
||||
{
|
||||
DBUG_PRINT("error",("No database"));
|
||||
if (!no_errors)
|
||||
send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
|
||||
send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
|
||||
DBUG_RETURN(TRUE); /* purecov: tested */
|
||||
}
|
||||
|
||||
@ -3999,6 +4001,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
|
||||
if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
|
||||
! db && dont_check_global_grants)
|
||||
{ // We can never grant this
|
||||
DBUG_PRINT("error",("No possible access"));
|
||||
if (!no_errors)
|
||||
net_printf(thd,ER_ACCESS_DENIED_ERROR,
|
||||
thd->priv_user,
|
||||
@ -4017,13 +4020,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
|
||||
db_access=thd->db_access;
|
||||
/* Remove SHOW attribute and access rights we already have */
|
||||
want_access &= ~(thd->master_access | EXTRA_ACL);
|
||||
DBUG_PRINT("info",("db_access: %lu want_access: %lu",
|
||||
db_access, want_access));
|
||||
db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
|
||||
|
||||
/* grant_option is set if there exists a single table or column grant */
|
||||
if (db_access == want_access ||
|
||||
((grant_option && !dont_check_global_grants) &&
|
||||
(grant_option && !dont_check_global_grants &&
|
||||
!(want_access & ~(db_access | TABLE_ACLS))))
|
||||
DBUG_RETURN(FALSE); /* Ok */
|
||||
|
||||
DBUG_PRINT("error",("Access denied"));
|
||||
if (!no_errors)
|
||||
net_printf(thd,ER_DBACCESS_DENIED_ERROR,
|
||||
thd->priv_user,
|
||||
@ -4111,6 +4118,42 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if the given table has any of the asked privileges
|
||||
|
||||
SYNOPSIS
|
||||
check_some_access()
|
||||
thd Thread handler
|
||||
want_access Bitmap of possible privileges to check for
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error
|
||||
*/
|
||||
|
||||
|
||||
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
|
||||
{
|
||||
ulong access;
|
||||
DBUG_ENTER("check_some_access");
|
||||
|
||||
/* This loop will work as long as we have less than 32 privileges */
|
||||
for (access= 1; access < want_access ; access<<= 1)
|
||||
{
|
||||
if (access & want_access)
|
||||
{
|
||||
if (!check_access(thd, access, table->db,
|
||||
&table->grant.privilege, 0, 1) &&
|
||||
!grant_option || !check_grant(thd, access, table, 0, 1, 1))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
DBUG_PRINT("exit",("no matching access rights"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
bool check_merge_table_access(THD *thd, char *db,
|
||||
TABLE_LIST *table_list)
|
||||
{
|
||||
@ -4971,6 +5014,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
{
|
||||
register TABLE_LIST *ptr;
|
||||
char *alias_str;
|
||||
LEX *lex= thd->lex;
|
||||
DBUG_ENTER("add_table_to_list");
|
||||
|
||||
if (!table)
|
||||
@ -5022,7 +5066,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
|
||||
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
|
||||
ptr->derived= table->sel;
|
||||
ptr->select_lex= thd->lex->current_select;
|
||||
ptr->select_lex= lex->current_select;
|
||||
ptr->cacheable_table= 1;
|
||||
if (use_index_arg)
|
||||
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
|
||||
@ -5046,8 +5090,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Link table in local list (list for current select) */
|
||||
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
|
||||
LEX *lex= thd->lex;
|
||||
/* Link table in global list (all used tables) */
|
||||
*(ptr->prev_global= lex->query_tables_last)= ptr;
|
||||
lex->query_tables_last= &ptr->next_global;
|
||||
DBUG_RETURN(ptr);
|
||||
|
@ -1680,8 +1680,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
|
||||
|
||||
if (lex->empty_field_list_on_rset)
|
||||
{
|
||||
lex->field_list.empty();
|
||||
lex->empty_field_list_on_rset= 0;
|
||||
lex->field_list.empty();
|
||||
}
|
||||
for (; sl; sl= sl->next_select_in_list())
|
||||
{
|
||||
|
@ -225,25 +225,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
|
||||
thd->net.report_error));
|
||||
if (thd->net.report_error)
|
||||
res= 1;
|
||||
if (res > 0)
|
||||
if (unlikely(res))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
result->send_error(0, NullS);
|
||||
if (res > 0)
|
||||
result->send_error(0, NullS);
|
||||
result->abort();
|
||||
}
|
||||
else
|
||||
else if (res > 0)
|
||||
send_error(thd, 0, NullS);
|
||||
res= 1; // Error sent to client
|
||||
}
|
||||
if (res < 0)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
result->abort();
|
||||
}
|
||||
res= 1;
|
||||
}
|
||||
if (result != lex->result)
|
||||
delete result;
|
||||
DBUG_RETURN(res);
|
||||
@ -348,9 +341,7 @@ JOIN::prepare(Item ***rref_pointer_array,
|
||||
if ((subselect= select_lex->master_unit()->item))
|
||||
{
|
||||
Item_subselect::trans_res res;
|
||||
if ((res= ((!thd->lex->view_prepare_mode) ?
|
||||
subselect->select_transformer(this) :
|
||||
subselect->no_select_transform())) !=
|
||||
if ((res= subselect->select_transformer(this)) !=
|
||||
Item_subselect::RES_OK)
|
||||
{
|
||||
select_lex->fix_prepare_information(thd, &conds);
|
||||
@ -552,6 +543,7 @@ JOIN::optimize()
|
||||
if (cond_value == Item::COND_FALSE ||
|
||||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
|
||||
{ /* Impossible cond */
|
||||
DBUG_PRINT("info", ("Impossible WHERE"));
|
||||
zero_result_cause= "Impossible WHERE";
|
||||
error= 0;
|
||||
DBUG_RETURN(0);
|
||||
@ -569,20 +561,24 @@ JOIN::optimize()
|
||||
{
|
||||
if (res > 1)
|
||||
{
|
||||
DBUG_PRINT("error",("Error from opt_sum_query"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (res < 0)
|
||||
{
|
||||
DBUG_PRINT("info",("No matching min/max row"));
|
||||
zero_result_cause= "No matching min/max row";
|
||||
error=0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_PRINT("info",("Select tables optimized away"));
|
||||
zero_result_cause= "Select tables optimized away";
|
||||
tables_list= 0; // All tables resolved
|
||||
}
|
||||
}
|
||||
if (!tables_list)
|
||||
{
|
||||
DBUG_PRINT("info",("No tables"));
|
||||
error= 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -11570,7 +11566,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
|
||||
SYNOPSIS
|
||||
print_join()
|
||||
thd thread handler
|
||||
str string where table should bbe printed
|
||||
str string where table should be printed
|
||||
tables list of tables in join
|
||||
*/
|
||||
|
||||
@ -11626,30 +11622,31 @@ void st_table_list::print(THD *thd, String *str)
|
||||
print_join(thd, str, &nested_join->join_list);
|
||||
str->append(')');
|
||||
}
|
||||
else if (view_name.str)
|
||||
{
|
||||
append_identifier(thd, str, view_db.str, view_db.length);
|
||||
str->append('.');
|
||||
append_identifier(thd, str, view_name.str, view_name.length);
|
||||
if (my_strcasecmp(table_alias_charset, view_name.str, alias))
|
||||
{
|
||||
str->append(' ');
|
||||
append_identifier(thd, str, alias, strlen(alias));
|
||||
}
|
||||
}
|
||||
else if (derived)
|
||||
{
|
||||
str->append('(');
|
||||
derived->print(str);
|
||||
str->append(") ", 2);
|
||||
append_identifier(thd, str, alias, strlen(alias));
|
||||
}
|
||||
else
|
||||
{
|
||||
append_identifier(thd, str, db, db_length);
|
||||
str->append('.');
|
||||
append_identifier(thd, str, real_name, real_name_length);
|
||||
if (my_strcasecmp(table_alias_charset, real_name, alias))
|
||||
const char *cmp_name; // Name to compare with alias
|
||||
if (view_name.str)
|
||||
{
|
||||
append_identifier(thd, str, view_db.str, view_db.length);
|
||||
str->append('.');
|
||||
append_identifier(thd, str, view_name.str, view_name.length);
|
||||
cmp_name= view_name.str;
|
||||
}
|
||||
else if (derived)
|
||||
{
|
||||
str->append('(');
|
||||
derived->print(str);
|
||||
str->append(')');
|
||||
cmp_name= ""; // Force printing of alias
|
||||
}
|
||||
else
|
||||
{
|
||||
append_identifier(thd, str, db, db_length);
|
||||
str->append('.');
|
||||
append_identifier(thd, str, real_name, real_name_length);
|
||||
cmp_name= real_name;
|
||||
}
|
||||
if (my_strcasecmp(table_alias_charset, cmp_name, alias))
|
||||
{
|
||||
str->append(' ');
|
||||
append_identifier(thd, str, alias, strlen(alias));
|
||||
@ -11665,7 +11662,7 @@ void st_select_lex::print(THD *thd, String *str)
|
||||
|
||||
str->append("select ", 7);
|
||||
|
||||
//options
|
||||
/* First add options */
|
||||
if (options & SELECT_STRAIGHT_JOIN)
|
||||
str->append("straight_join ", 14);
|
||||
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
|
||||
|
@ -1575,11 +1575,11 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
|
||||
MODE_MAXDB |
|
||||
MODE_ANSI)) != 0;
|
||||
buff->append("CREATE ", 7);
|
||||
if(!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
|
||||
table->algorithm == VIEW_ALGORITHM_TMEPTABLE))
|
||||
if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
|
||||
table->algorithm == VIEW_ALGORITHM_TMPTABLE))
|
||||
{
|
||||
buff->append("ALGORITHM=", 10);
|
||||
if (table->algorithm == VIEW_ALGORITHM_TMEPTABLE)
|
||||
if (table->algorithm == VIEW_ALGORITHM_TMPTABLE)
|
||||
buff->append("TMPTABLE ", 9);
|
||||
else
|
||||
buff->append("MERGE ", 6);
|
||||
|
@ -496,7 +496,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/* Check that we are not using table that we are updating in a sub select */
|
||||
if (find_real_table_in_list(table_list->next_global,
|
||||
if (find_table_in_global_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
@ -788,7 +788,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (!(tables_to_update & table->map) &&
|
||||
find_real_table_in_list(update_tables, table_ref->db,
|
||||
find_table_in_global_list(update_tables, table_ref->db,
|
||||
table_ref->real_name))
|
||||
table->no_cache= 1; // Disable row cache
|
||||
}
|
||||
|
275
sql/sql_view.cc
275
sql/sql_view.cc
@ -90,25 +90,8 @@ int mysql_create_view(THD *thd,
|
||||
/*
|
||||
Ensure that we have some privilage on this table, more strict check
|
||||
will be done on column level after preparation,
|
||||
|
||||
SELECT_ACL will be checked for sure for all fields because it is
|
||||
listed first (if we have not rights to SELECT from whole table this
|
||||
right will be written as tbl->grant.want_privilege and will be checked
|
||||
later (except fields which need any privilege and can be updated).
|
||||
*/
|
||||
if ((check_access(thd, SELECT_ACL, tbl->db,
|
||||
&tbl->grant.privilege, 0, 1) ||
|
||||
grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 1)) &&
|
||||
(check_access(thd, INSERT_ACL, tbl->db,
|
||||
&tbl->grant.privilege, 0, 1) ||
|
||||
grant_option && check_grant(thd, INSERT_ACL, tbl, 0, 1, 1)) &&
|
||||
(check_access(thd, DELETE_ACL, tbl->db,
|
||||
&tbl->grant.privilege, 0, 1) ||
|
||||
grant_option && check_grant(thd, DELETE_ACL, tbl, 0, 1, 1)) &&
|
||||
(check_access(thd, UPDATE_ACL, tbl->db,
|
||||
&tbl->grant.privilege, 0, 1) ||
|
||||
grant_option && check_grant(thd, UPDATE_ACL, tbl, 0, 1, 1))
|
||||
)
|
||||
if (check_some_access(thd, VIEW_ANY_ACL, tbl))
|
||||
{
|
||||
my_printf_error(ER_TABLEACCESS_DENIED_ERROR,
|
||||
ER(ER_TABLEACCESS_DENIED_ERROR),
|
||||
@ -124,7 +107,7 @@ int mysql_create_view(THD *thd,
|
||||
|
||||
/*
|
||||
We need to check only SELECT_ACL for all normal fields, fields
|
||||
where we need any privilege will be pmarked later
|
||||
where we need any privilege will be marked later
|
||||
*/
|
||||
tbl->grant.want_privilege= SELECT_ACL;
|
||||
/*
|
||||
@ -176,7 +159,7 @@ int mysql_create_view(THD *thd,
|
||||
/* check that tables are not temporary */
|
||||
for (tbl= tables; tbl; tbl= tbl->next_global)
|
||||
{
|
||||
if (tbl->table->tmp_table != NO_TMP_TABLE && !test(tbl->view))
|
||||
if (tbl->table->tmp_table != NO_TMP_TABLE && !tbl->view)
|
||||
{
|
||||
my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias);
|
||||
res= -1;
|
||||
@ -206,19 +189,18 @@ int mysql_create_view(THD *thd,
|
||||
/* view list (list of view fields names) */
|
||||
if (lex->view_list.elements)
|
||||
{
|
||||
List_iterator_fast<Item> it(select_lex->item_list);
|
||||
List_iterator_fast<LEX_STRING> nm(lex->view_list);
|
||||
Item *item;
|
||||
LEX_STRING *name;
|
||||
|
||||
if (lex->view_list.elements != select_lex->item_list.elements)
|
||||
{
|
||||
my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0));
|
||||
goto err;
|
||||
}
|
||||
List_iterator_fast<Item> it(select_lex->item_list);
|
||||
List_iterator_fast<LEX_STRING> nm(lex->view_list);
|
||||
Item *item;
|
||||
LEX_STRING *name;
|
||||
while((item= it++, name= nm++))
|
||||
{
|
||||
while ((item= it++, name= nm++))
|
||||
item->set_name(name->str, name->length, system_charset_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test absence of duplicates names */
|
||||
@ -226,11 +208,11 @@ int mysql_create_view(THD *thd,
|
||||
Item *item;
|
||||
List_iterator_fast<Item> it(select_lex->item_list);
|
||||
it++;
|
||||
while((item= it++))
|
||||
while ((item= it++))
|
||||
{
|
||||
Item *check;
|
||||
List_iterator_fast<Item> itc(select_lex->item_list);
|
||||
while((check= itc++) && check != item)
|
||||
while ((check= itc++) && check != item)
|
||||
{
|
||||
if (strcmp(item->name, check->name) == 0)
|
||||
{
|
||||
@ -252,7 +234,7 @@ int mysql_create_view(THD *thd,
|
||||
Item *item;
|
||||
fill_effective_table_privileges(thd, &view->grant, db,
|
||||
view->real_name);
|
||||
while((item= it++))
|
||||
while ((item= it++))
|
||||
{
|
||||
uint priv= (get_column_grant(thd, &view->grant, db,
|
||||
view->real_name, item->name) &
|
||||
@ -261,10 +243,10 @@ int mysql_create_view(THD *thd,
|
||||
{
|
||||
Item_field *fld= (Item_field *)item;
|
||||
/*
|
||||
There are no any privileges on VIWE column or there are
|
||||
There are no any privileges on VIEW column or there are
|
||||
some other privileges then we have for underlaying table
|
||||
*/
|
||||
if (priv == 0 || test(~fld->have_privileges & priv))
|
||||
if (priv == 0 || (~fld->have_privileges & priv))
|
||||
{
|
||||
/* VIEW column has more privileges */
|
||||
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
|
||||
@ -280,7 +262,7 @@ int mysql_create_view(THD *thd,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!test(priv & SELECT_ACL))
|
||||
if (!(priv & SELECT_ACL))
|
||||
{
|
||||
/* user have not privilege to SELECT expression */
|
||||
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
|
||||
@ -304,14 +286,11 @@ int mysql_create_view(THD *thd,
|
||||
goto err;
|
||||
}
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if ((res= mysql_register_view(thd, view, mode)))
|
||||
{
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
start_waiting_global_read_lock(thd);
|
||||
goto err;
|
||||
}
|
||||
res= mysql_register_view(thd, view, mode);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
start_waiting_global_read_lock(thd);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
send_ok(thd);
|
||||
lex->link_first_table_back(view, link_to_local);
|
||||
@ -332,40 +311,36 @@ static const int revision_number_position= 5;
|
||||
/* index of last required parameter for making view */
|
||||
static const int required_view_parameters= 7;
|
||||
|
||||
static char *view_field_names[]=
|
||||
{
|
||||
(char*)"query",
|
||||
(char*)"md5",
|
||||
(char*)"updatable",
|
||||
(char*)"algorithm",
|
||||
(char*)"revision",
|
||||
(char*)"timestamp",
|
||||
(char*)"create-version",
|
||||
(char*)"source"
|
||||
};
|
||||
/*
|
||||
table of VIEW .frm field descriptors
|
||||
|
||||
Note that one should NOT change the order for this, as it's used by
|
||||
parse()
|
||||
*/
|
||||
|
||||
// table of VIEW .frm field descriprors
|
||||
static File_option view_parameters[]=
|
||||
{{{view_field_names[0], 5}, offsetof(TABLE_LIST, query),
|
||||
{{{(char*) "query", 5}, offsetof(TABLE_LIST, query),
|
||||
FILE_OPTIONS_STRING},
|
||||
{{view_field_names[1], 3}, offsetof(TABLE_LIST, md5),
|
||||
{{(char*) "md5", 3}, offsetof(TABLE_LIST, md5),
|
||||
FILE_OPTIONS_STRING},
|
||||
{{view_field_names[2], 9}, offsetof(TABLE_LIST, updatable_view),
|
||||
{{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable_view),
|
||||
FILE_OPTIONS_ULONGLONG},
|
||||
{{view_field_names[3], 9}, offsetof(TABLE_LIST, algorithm),
|
||||
{{(char*) "algorithm", 9}, offsetof(TABLE_LIST, algorithm),
|
||||
FILE_OPTIONS_ULONGLONG},
|
||||
{{view_field_names[4], 8}, offsetof(TABLE_LIST, revision),
|
||||
{{(char*) "revision", 8}, offsetof(TABLE_LIST, revision),
|
||||
FILE_OPTIONS_REV},
|
||||
{{view_field_names[5], 9}, offsetof(TABLE_LIST, timestamp),
|
||||
{{(char*) "timestamp", 9}, offsetof(TABLE_LIST, timestamp),
|
||||
FILE_OPTIONS_TIMESTAMP},
|
||||
{{view_field_names[6], 14}, offsetof(TABLE_LIST, file_version),
|
||||
{{(char*)"create-version", 14},offsetof(TABLE_LIST, file_version),
|
||||
FILE_OPTIONS_ULONGLONG},
|
||||
{{view_field_names[7], 6}, offsetof(TABLE_LIST, source),
|
||||
{{(char*) "source", 6}, offsetof(TABLE_LIST, source),
|
||||
FILE_OPTIONS_ESTRING},
|
||||
{{NULL, 0}, 0,
|
||||
FILE_OPTIONS_STRING}
|
||||
};
|
||||
|
||||
static const uint required_view_parameters= 6;
|
||||
|
||||
static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}};
|
||||
|
||||
|
||||
@ -413,16 +388,18 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
dir.length= strlen(dir_buff);
|
||||
|
||||
file.str= file_buff;
|
||||
file.length= my_snprintf(file_buff, FN_REFLEN, "%s%s",
|
||||
view->real_name, reg_ext);
|
||||
file.length= (strxnmov(file_buff, FN_REFLEN, view->real_name, reg_ext,
|
||||
NullS) - file_buff);
|
||||
/* init timestamp */
|
||||
if (!test(view->timestamp.str))
|
||||
if (!view->timestamp.str)
|
||||
view->timestamp.str= view->timestamp_buffer;
|
||||
|
||||
// check old .frm
|
||||
{
|
||||
char path_buff[FN_REFLEN];
|
||||
LEX_STRING path;
|
||||
File_parser *parser;
|
||||
|
||||
path.str= path_buff;
|
||||
fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
|
||||
path.length= strlen(path_buff);
|
||||
@ -435,34 +412,27 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
File_parser *parser= sql_parse_prepare(&path, &thd->mem_root, 0);
|
||||
if (parser)
|
||||
{
|
||||
if(parser->ok() &&
|
||||
!strncmp("VIEW", parser->type()->str, parser->type()->length))
|
||||
{
|
||||
/*
|
||||
read revision number
|
||||
|
||||
TODO: read dependense list, too, to process cascade/restrict
|
||||
TODO: special cascade/restrict procedure for alter?
|
||||
*/
|
||||
if (parser->parse((gptr)view, &thd->mem_root,
|
||||
view_parameters + revision_number_position, 1))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my_error(ER_WRONG_OBJECT, MYF(0), (view->db?view->db:thd->db),
|
||||
view->real_name, "VIEW");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(parser= sql_parse_prepare(&path, &thd->mem_root, 0)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!parser->ok() ||
|
||||
strncmp("VIEW", parser->type()->str, parser->type()->length))
|
||||
{
|
||||
my_error(ER_WRONG_OBJECT, MYF(0), (view->db ? view->db : thd->db),
|
||||
view->real_name, "VIEW");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
read revision number
|
||||
|
||||
TODO: read dependense list, too, to process cascade/restrict
|
||||
TODO: special cascade/restrict procedure for alter?
|
||||
*/
|
||||
if (parser->parse((gptr)view, &thd->mem_root,
|
||||
view_parameters + revision_number_position, 1))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -493,14 +463,14 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
}
|
||||
view->algorithm= thd->lex->create_view_algorithm;
|
||||
if ((view->updatable_view= (can_be_merged &&
|
||||
view->algorithm != VIEW_ALGORITHM_TMEPTABLE)))
|
||||
view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
|
||||
{
|
||||
// TODO: change here when we will support UNIONs
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->view != 0 && !tbl->updatable_view)
|
||||
if (tbl->view && !tbl->updatable_view)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
break;
|
||||
@ -525,9 +495,11 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
table - TABLE_LIST structure for filling
|
||||
|
||||
RETURN
|
||||
TRUE OK
|
||||
FALSE error
|
||||
0 ok
|
||||
1 error
|
||||
|
||||
*/
|
||||
|
||||
my_bool
|
||||
mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
{
|
||||
@ -537,7 +509,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
if (table->view)
|
||||
{
|
||||
DBUG_PRINT("info",
|
||||
("VIEW %s.%s is already processed on previos PS/SP execution",
|
||||
("VIEW %s.%s is already processed on previous PS/SP execution",
|
||||
table->view_db.str, table->view_name.str));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -557,7 +529,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
thd->set_n_backup_item_arena(arena, &backup);
|
||||
|
||||
/* init timestamp */
|
||||
if (!test(table->timestamp.str))
|
||||
if (!table->timestamp.str)
|
||||
table->timestamp.str= table->timestamp_buffer;
|
||||
/*
|
||||
TODO: when VIEWs will be stored in cache, table mem_root should
|
||||
@ -687,7 +659,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
- VIEW SELECT allow marging
|
||||
- VIEW used in subquery or command support MERGE algorithm
|
||||
*/
|
||||
if (table->algorithm != VIEW_ALGORITHM_TMEPTABLE &&
|
||||
if (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
|
||||
lex->can_be_merged() &&
|
||||
(table->select_lex->master_unit() != &old_lex->unit ||
|
||||
old_lex->can_use_merged()) &&
|
||||
@ -733,7 +705,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
goto ok;
|
||||
}
|
||||
|
||||
table->effective_algorithm= VIEW_ALGORITHM_TMEPTABLE;
|
||||
table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
|
||||
DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE"));
|
||||
lex->select_lex.linkage= DERIVED_TABLE_TYPE;
|
||||
table->updatable= 0;
|
||||
@ -746,7 +718,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
{
|
||||
if ((tbl_end= table->next_global))
|
||||
{
|
||||
for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next);
|
||||
for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next)
|
||||
;
|
||||
if ((tbl_end->next_global= old_next))
|
||||
tbl_end->next_global->prev_global= &tbl_end->next_global;
|
||||
}
|
||||
@ -810,6 +783,7 @@ err:
|
||||
-1 Error
|
||||
1 Error and error message given
|
||||
*/
|
||||
|
||||
int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
|
||||
{
|
||||
DBUG_ENTER("mysql_drop_view");
|
||||
@ -819,8 +793,8 @@ int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
|
||||
|
||||
for (view= views; view; view= view->next_local)
|
||||
{
|
||||
strxmov(path, mysql_data_home, "/", view->db, "/", view->real_name,
|
||||
reg_ext, NullS);
|
||||
strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
|
||||
view->real_name, reg_ext, NullS);
|
||||
(void) unpack_filename(path, path);
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW)))
|
||||
@ -872,21 +846,20 @@ frm_type_enum mysql_frm_type(char *path)
|
||||
{
|
||||
File file;
|
||||
char header[10]; //"TYPE=VIEW\n" it is 10 characters
|
||||
int length;
|
||||
DBUG_ENTER("mysql_frm_type");
|
||||
|
||||
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
|
||||
{
|
||||
DBUG_RETURN(FRMTYPE_ERROR);
|
||||
}
|
||||
if (my_read(file, (byte*) header, 10, MYF(MY_WME)) == MY_FILE_ERROR)
|
||||
{
|
||||
my_close(file, MYF(MY_WME));
|
||||
DBUG_RETURN(FRMTYPE_ERROR);
|
||||
}
|
||||
length= my_read(file, (byte*) header, 10, MYF(MY_WME));
|
||||
my_close(file, MYF(MY_WME));
|
||||
if (strncmp(header, "TYPE=VIEW\n", 10) != 0)
|
||||
DBUG_RETURN(FRMTYPE_TABLE);
|
||||
DBUG_RETURN(FRMTYPE_VIEW);
|
||||
if (length == (int) MY_FILE_ERROR)
|
||||
DBUG_RETURN(FRMTYPE_ERROR);
|
||||
if (!strncmp(header, "TYPE=VIEW\n", 10))
|
||||
DBUG_RETURN(FRMTYPE_VIEW);
|
||||
DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table
|
||||
}
|
||||
|
||||
|
||||
@ -905,72 +878,81 @@ frm_type_enum mysql_frm_type(char *path)
|
||||
|
||||
bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
{
|
||||
TABLE *table;
|
||||
Item **trans;
|
||||
KEY *key_info, *key_info_end;
|
||||
uint i, elements_in_view;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
|
||||
if (!view->view)
|
||||
DBUG_RETURN(FALSE); /* it is normal table */
|
||||
table= view->table;
|
||||
trans= view->field_translation;
|
||||
key_info_end= (key_info= table->key_info)+ table->keys;
|
||||
|
||||
TABLE *table= view->table;
|
||||
Item **trans= view->field_translation;
|
||||
KEY *key_info= table->key_info;
|
||||
uint primary_key= table->primary_key;
|
||||
uint num= view->view->select_lex.item_list.elements;
|
||||
elements_in_view= view->view->select_lex.item_list.elements;
|
||||
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
|
||||
|
||||
/* try to find key */
|
||||
for (uint i=0; i < table->keys; i++, key_info++)
|
||||
/* Loop over all keys to see if a unique-not-null key is used */
|
||||
for (;key_info != key_info_end ; key_info++)
|
||||
{
|
||||
if (i == primary_key && !strcmp(key_info->name, primary_key_name) ||
|
||||
key_info->flags & HA_NOSAME)
|
||||
if ((key_info->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
|
||||
{
|
||||
KEY_PART_INFO *key_part= key_info->key_part;
|
||||
bool found= 1;
|
||||
for (uint j=0; j < key_info->key_parts && found; j++, key_part++)
|
||||
KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
|
||||
|
||||
/* check that all key parts are used */
|
||||
for (;;)
|
||||
{
|
||||
found= 0;
|
||||
for (uint k= 0; k < num; k++)
|
||||
uint k;
|
||||
for (k= 0; k < elements_in_view; k++)
|
||||
{
|
||||
if (trans[k]->type() == Item::FIELD_ITEM &&
|
||||
((Item_field *)trans[k])->field == key_part->field &&
|
||||
(key_part->field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
found= 1;
|
||||
((Item_field *)trans[k])->field == key_part->field)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == elements_in_view)
|
||||
break; // Key is not possible
|
||||
if (++key_part == key_part_end)
|
||||
DBUG_RETURN(FALSE); // Found usable key
|
||||
}
|
||||
if (found)
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", ("checking if all fields of table are used"));
|
||||
/* check all fields presence */
|
||||
{
|
||||
Field **field_ptr= table->field;
|
||||
for (; *field_ptr; ++field_ptr)
|
||||
Field **field_ptr;
|
||||
for (field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
{
|
||||
uint i= 0;
|
||||
for (; i < num; i++)
|
||||
for (i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
if (trans[i]->type() == Item::FIELD_ITEM &&
|
||||
((Item_field *)trans[i])->field == *field_ptr)
|
||||
break;
|
||||
}
|
||||
if (i >= num)
|
||||
if (i == elements_in_view) // If field didn't exists
|
||||
{
|
||||
ulong mode= thd->variables.sql_updatable_view_key;
|
||||
/* 1 == YES, 2 == LIMIT1 */
|
||||
/*
|
||||
0 == NO ; Don't give any errors
|
||||
1 == YES ; Give always an error
|
||||
2 == LIMIT1 ; Give an error if this is used with LIMIT 1
|
||||
This is used to protect against gui programs that
|
||||
uses LIMIT 1 to update just the current row. This
|
||||
doesn't work reliable if the view doesn't have a
|
||||
unique key or if the view doesn't use all fields in
|
||||
table.
|
||||
*/
|
||||
if (mode == 1 ||
|
||||
(mode == 2 &&
|
||||
thd->lex->select_lex.select_limit == 1))
|
||||
thd->lex->unit.global_parameters->select_limit == 1))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -989,18 +971,17 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
|
||||
void insert_view_fields(List<Item> *list, TABLE_LIST *view)
|
||||
{
|
||||
uint num= view->view->select_lex.item_list.elements;
|
||||
Item **trans= view->field_translation;
|
||||
uint elements_in_view= view->view->select_lex.item_list.elements;
|
||||
Item **trans;
|
||||
DBUG_ENTER("insert_view_fields");
|
||||
if (!trans)
|
||||
|
||||
if (!(trans= view->field_translation))
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
for (uint i= 0; i < num; i++)
|
||||
for (uint i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
if (trans[i]->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
list->push_back(trans[i]);
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -7553,7 +7553,7 @@ algorithm:
|
||||
| ALGORITHM_SYM EQ MERGE_SYM
|
||||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; }
|
||||
| ALGORITHM_SYM EQ TEMPTABLE_SYM
|
||||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_TMEPTABLE; }
|
||||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; }
|
||||
;
|
||||
check_option:
|
||||
/* empty */ {}
|
||||
|
36
sql/table.cc
36
sql/table.cc
@ -88,6 +88,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
|
||||
DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
|
||||
|
||||
error=1;
|
||||
disk_buff=NULL;
|
||||
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
||||
|
||||
if ((file=my_open(fn_format(index_file, name, "", reg_ext,
|
||||
MY_UNPACK_FILENAME),
|
||||
@ -118,11 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
|
||||
|
||||
bzero((char*) outparam,sizeof(*outparam));
|
||||
outparam->blob_ptr_size=sizeof(char*);
|
||||
disk_buff=NULL; record= NULL; keynames=NullS;
|
||||
outparam->db_stat = db_stat;
|
||||
|
||||
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
|
||||
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
||||
my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
|
||||
|
||||
outparam->real_name=strdup_root(&outparam->mem_root,
|
||||
@ -742,11 +741,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
|
||||
DBUG_RETURN (0);
|
||||
|
||||
err_w_init:
|
||||
//awoid problem with uninitialized data
|
||||
/* Avoid problem with uninitialized data */
|
||||
bzero((char*) outparam,sizeof(*outparam));
|
||||
outparam->real_name= (char*)name+dirname_length(name);
|
||||
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
||||
disk_buff= 0;
|
||||
|
||||
err_not_open:
|
||||
x_free((gptr) disk_buff);
|
||||
@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name)
|
||||
st_table_list::calc_md5()
|
||||
buffer buffer for md5 writing
|
||||
*/
|
||||
|
||||
void st_table_list::calc_md5(char *buffer)
|
||||
{
|
||||
my_MD5_CTX context;
|
||||
unsigned char digest[16];
|
||||
my_MD5Init (&context);
|
||||
my_MD5Update (&context,(unsigned char *) query.str, query.length);
|
||||
my_MD5Final (digest, &context);
|
||||
uchar digest[16];
|
||||
my_MD5Init(&context);
|
||||
my_MD5Update(&context,(uchar *) query.str, query.length);
|
||||
my_MD5Final(digest, &context);
|
||||
sprintf((char *) buffer,
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
digest[0], digest[1], digest[2], digest[3],
|
||||
@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer)
|
||||
SYNOPSIS
|
||||
st_table_list::set_ancestor()
|
||||
*/
|
||||
|
||||
void st_table_list::set_ancestor()
|
||||
{
|
||||
if (ancestor->ancestor)
|
||||
@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor()
|
||||
(without fields) for name resolving, but substituted expressions will
|
||||
return correct used tables mask.
|
||||
*/
|
||||
|
||||
bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
{
|
||||
Item **transl;
|
||||
@ -1520,15 +1520,15 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
thd->set_query_id= 1;
|
||||
/* this view was prepared already on previous PS/SP execution */
|
||||
Item **end= field_translation + select->item_list.elements;
|
||||
for (Item **i= field_translation; i < end; i++)
|
||||
for (Item **item= field_translation; item < end; item++)
|
||||
{
|
||||
//TODO: fix for several tables in VIEW
|
||||
/* TODO: fix for several tables in VIEW */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
/* real rights will be checked in VIEW field */
|
||||
ancestor->table->grant.want_privilege= 0;
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
if (!(*i)->fixed && (*i)->fix_fields(thd, ancestor, i))
|
||||
if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
|
||||
goto err;
|
||||
ancestor->table->grant.want_privilege= want_privilege;
|
||||
}
|
||||
@ -1557,21 +1557,19 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
thd->set_query_id= 1;
|
||||
while ((item= it++))
|
||||
{
|
||||
//TODO: fix for several tables in VIEW
|
||||
/* TODO: fix for several tables in VIEW */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
/* real rights will be checked in VIEW field */
|
||||
ancestor->table->grant.want_privilege= 0;
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
if (!item->fixed && item->fix_fields(thd, ancestor, &item))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
ancestor->table->grant.want_privilege= want_privilege;
|
||||
transl[i++]= item;
|
||||
}
|
||||
field_translation= transl;
|
||||
//TODO: sort this list? Use hash for big number of fields
|
||||
/* TODO: sort this list? Use hash for big number of fields */
|
||||
|
||||
if (where)
|
||||
{
|
||||
@ -1580,12 +1578,12 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
goto err;
|
||||
|
||||
if (arena)
|
||||
thd->set_n_backup_item_arena(arena, &backup);
|
||||
thd->set_n_backup_item_arena(arena, &backup);
|
||||
if (outer_join)
|
||||
{
|
||||
/*
|
||||
Store WHERE condition to ON expression for outer join, because we
|
||||
can't use WHERE to correctly execute jeft joins on VIEWs and this
|
||||
can't use WHERE to correctly execute jeft joins on VIEWs and this
|
||||
expression will not be moved to WHERE condition (i.e. will be clean
|
||||
correctly for PS/SP)
|
||||
*/
|
||||
|
@ -182,7 +182,7 @@ struct st_table {
|
||||
#define JOIN_TYPE_RIGHT 2
|
||||
|
||||
#define VIEW_ALGORITHM_UNDEFINED 0
|
||||
#define VIEW_ALGORITHM_TMEPTABLE 1
|
||||
#define VIEW_ALGORITHM_TMPTABLE 1
|
||||
#define VIEW_ALGORITHM_MERGE 2
|
||||
|
||||
struct st_lex;
|
||||
@ -270,7 +270,7 @@ public:
|
||||
virtual ~Field_iterator() {}
|
||||
virtual void set(TABLE_LIST *)= 0;
|
||||
virtual void next()= 0;
|
||||
virtual bool end()= 0;
|
||||
virtual bool end_of_fields()= 0; /* Return 1 at end of list */
|
||||
virtual const char *name()= 0;
|
||||
virtual Item *item(THD *)= 0;
|
||||
virtual Field *field()= 0;
|
||||
@ -285,7 +285,7 @@ public:
|
||||
void set(TABLE_LIST *table) { ptr= table->table->field; }
|
||||
void set_table(TABLE *table) { ptr= table->field; }
|
||||
void next() { ptr++; }
|
||||
bool end() { return test(*ptr); }
|
||||
bool end_of_fields() { return *ptr == 0; }
|
||||
const char *name();
|
||||
Item *item(THD *thd);
|
||||
Field *field() { return *ptr; }
|
||||
@ -299,7 +299,7 @@ public:
|
||||
Field_iterator_view() :ptr(0), array_end(0) {}
|
||||
void set(TABLE_LIST *table);
|
||||
void next() { ptr++; }
|
||||
bool end() { return ptr < array_end; }
|
||||
bool end_of_fields() { return ptr == array_end; }
|
||||
const char *name();
|
||||
Item *item(THD *thd) { return *ptr; }
|
||||
Field *field() { return 0; }
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
|
||||
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
|
||||
#define MAX_KEY 64
|
||||
|
||||
/* set default options */
|
||||
static char *opt_db= 0;
|
||||
@ -5507,6 +5508,7 @@ static void test_subselect()
|
||||
MYSQL_STMT *stmt;
|
||||
int rc, id;
|
||||
MYSQL_BIND bind[1];
|
||||
DBUG_ENTER("test_subselect");
|
||||
|
||||
myheader("test_subselect");
|
||||
|
||||
@ -5608,6 +5610,7 @@ static void test_subselect()
|
||||
assert(rc == MYSQL_NO_DATA);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -7018,13 +7021,13 @@ static void test_explain_bug()
|
||||
"", "", "", 10, 0);
|
||||
|
||||
verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING,
|
||||
"", "", "", NAME_LEN*64, 0);
|
||||
"", "", "", NAME_LEN*MAX_KEY, 0);
|
||||
|
||||
verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING,
|
||||
"", "", "", NAME_LEN, 0);
|
||||
|
||||
verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING,
|
||||
"", "", "", NAME_LEN*64, 0);
|
||||
"", "", "", NAME_LEN*MAX_KEY, 0);
|
||||
|
||||
verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING,
|
||||
"", "", "", NAME_LEN*16, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user