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:
unknown 2004-09-04 15:32:13 +03:00
commit d75ea9bcd6
27 changed files with 581 additions and 473 deletions

View File

@ -2384,7 +2384,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
char buff[4 /* size of stmt id */ + char buff[4 /* size of stmt id */ +
5 /* execution flags */]; 5 /* execution flags */];
DBUG_ENTER("execute"); DBUG_ENTER("execute");
DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); DBUG_DUMP("packet", packet, length);
mysql->last_used_con= mysql; mysql->last_used_con= mysql;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */ int4store(buff, stmt->stmt_id); /* Send stmt id to server */

View File

@ -1764,6 +1764,26 @@ call bug5251()|
Table Checksum Table Checksum
test.t1 0 test.t1 0
drop procedure bug5251| 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| drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)| create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned) create procedure ifac(n int unsigned)

View File

@ -1924,6 +1924,35 @@ call bug5251()|
call bug5251()| call bug5251()|
drop procedure 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 # Some "real" examples

View File

@ -1143,8 +1143,27 @@ bool Item_param::convert_str_value(THD *thd)
return rc; 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() void Item_copy_string::copy()
{ {

View File

@ -635,7 +635,7 @@ public:
*/ */
virtual table_map used_tables() const virtual table_map used_tables() const
{ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } { 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 */ /* parameter never equal to other parameter of other item */
bool eq(const Item *item, bool binary_cmp) const { return 0; } bool eq(const Item *item, bool binary_cmp) const { return 0; }
}; };

View File

@ -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) void Item_in_subselect::print(String *str)
{ {
if (transformed) if (transformed)

View File

@ -84,7 +84,6 @@ public:
null_value= 1; null_value= 1;
} }
virtual trans_res select_transformer(JOIN *join); virtual trans_res select_transformer(JOIN *join);
virtual trans_res no_select_transform() { return RES_OK; }
bool assigned() { return value_assigned; } bool assigned() { return value_assigned; }
void assigned(bool a) { value_assigned= a; } void assigned(bool a) { value_assigned= a; }
enum Type type() const; enum Type type() const;
@ -220,7 +219,6 @@ public:
was_null= 0; was_null= 0;
} }
trans_res select_transformer(JOIN *join); trans_res select_transformer(JOIN *join);
trans_res no_select_transform();
trans_res single_value_transformer(JOIN *join, trans_res single_value_transformer(JOIN *join,
Comp_creator *func); Comp_creator *func);
trans_res row_value_transformer(JOIN * join); trans_res row_value_transformer(JOIN * join);

View File

@ -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)) && while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!log_in_use(log_info.log_file_name)) !log_in_use(log_info.log_file_name))
{ {
ulong tmp; ulong file_size;
LINT_INIT(tmp); LINT_INIT(file_size);
if (decrease_log_space) //stat the file we want to delete if (decrease_log_space) //stat the file we want to delete
{ {
MY_STAT s; MY_STAT s;
if (my_stat(log_info.log_file_name,&s,MYF(0))) if (my_stat(log_info.log_file_name,&s,MYF(0)))
tmp= s.st_size; file_size= s.st_size;
else else
{ {
/* /*
@ -852,7 +852,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
of space that deletion will free. In most cases, of space that deletion will free. In most cases,
deletion won't work either, so it's not a problem. 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)); DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space) 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) if (find_next_log(&log_info, 0) || exit_loop)
break; break;
} }

View File

@ -398,8 +398,9 @@ void free_items(Item *item);
void cleanup_items(Item *item); void cleanup_items(Item *item);
class THD; class THD;
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0); 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); TABLE_LIST *tables);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db, bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list); TABLE_LIST *table_list);
int multi_update_precheck(THD *thd, TABLE_LIST *tables); 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); void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr); bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd); void close_temporary_tables(THD *thd);
TABLE_LIST * find_real_table_in_list(TABLE_LIST *table, TABLE_LIST *find_table_in_list(TABLE_LIST *table,
const char *db_name, uint offset_to_list,
const char *table_name); const char *db_name,
TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table, const char *table_name);
const char *db_name,
const char *table_name);
TABLE **find_temporary_table(THD *thd, const char *db, 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); bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1); 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); int fill_record(Field **field,List<Item> &values, bool ignore_errors);
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); 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 */ /* sql_calc.cc */
bool eval_const_cond(COND *cond); bool eval_const_cond(COND *cond);

View File

@ -288,6 +288,7 @@ void
sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
{ {
DBUG_ENTER("sp_head::init_strings"); DBUG_ENTER("sp_head::init_strings");
uint n; /* Counter for nul trimming */
/* During parsing, we must use thd->mem_root */ /* During parsing, we must use thd->mem_root */
MEM_ROOT *root= &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); (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_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); m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@ -28,7 +28,7 @@
sp_pcontext::sp_pcontext(sp_pcontext *prev) sp_pcontext::sp_pcontext(sp_pcontext *prev)
: Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0), : 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_pvar, sizeof(sp_pvar_t *), 16, 8));
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_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) while (pctx && pctx != ctx)
{ {
n+= pctx->max_handlers(); n+= pctx->m_handlers;
pctx= pctx->parent_context(); pctx= pctx->parent_context();
} }
if (pctx) if (pctx)
@ -109,12 +109,9 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx)
sp_pcontext *pctx= this; sp_pcontext *pctx= this;
while (pctx && pctx != ctx) while (pctx && pctx != ctx)
{
n+= pctx->max_cursors();
pctx= pctx->parent_context(); pctx= pctx->parent_context();
}
if (pctx) if (pctx)
return n; return ctx->current_cursors() - pctx->current_cursors();
return 0; // Didn't find ctx return 0; // Didn't find ctx
} }

View File

@ -275,6 +275,7 @@ protected:
uint m_psubsize; uint m_psubsize;
uint m_csubsize; uint m_csubsize;
uint m_hsubsize; uint m_hsubsize;
uint m_handlers; // No. of handlers in this context
private: private:
@ -282,7 +283,6 @@ private:
uint m_poffset; // Variable offset for this context uint m_poffset; // Variable offset for this context
uint m_coffset; // Cursor 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_pvar; // Parameters/variables
DYNAMIC_ARRAY m_cond; // Conditions DYNAMIC_ARRAY m_cond; // Conditions

View File

@ -2761,7 +2761,22 @@ void grant_reload(THD *thd)
/**************************************************************************** /****************************************************************************
Check table level grants 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, 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; TABLE_LIST *table;
char *user = thd->priv_user; 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) if (!want_access)
return 0; // ok DBUG_RETURN(0); // ok
rw_rdlock(&LOCK_grant); rw_rdlock(&LOCK_grant);
for (table= tables; table && number--; table= table->next_global) for (table= tables; table && number--; table= table->next_global)
{ {
GRANT_TABLE *grant_table;
if (!(~table->grant.privilege & want_access) || table->derived) 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; table->grant.want_privilege= 0;
continue; // Already checked continue; // Already checked
} }
GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip, if (!(grant_table= table_hash_search(thd->host,thd->ip,
table->db,user, table->db,user, table->real_name,0)))
table->real_name,0);
if (!grant_table)
{ {
want_access &= ~table->grant.privilege; want_access &= ~table->grant.privilege;
goto err; // No grants goto err; // No grants
@ -2813,7 +2829,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
} }
} }
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
return 0; DBUG_RETURN(0);
err: err:
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
@ -2848,7 +2864,7 @@ err:
thd->host_or_ip, thd->host_or_ip,
table ? table->real_name : "unknown"); 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)) if (!(grant_table= grant->grant_table))
goto err; /* purecov: inspected */ goto err; /* purecov: inspected */
for (; fields->end(); fields->next()) for (; !fields->end_of_fields(); fields->next())
{ {
const char *field_name= fields->name(); const char *field_name= fields->name();
grant_column= column_hash_search(grant_table, field_name, grant_column= column_hash_search(grant_table, field_name,

View File

@ -549,81 +549,37 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0; thd->temporary_tables=0;
} }
#ifdef UNUSED
/* /*
Find first suitable table by alias in given list. Find table in list.
SYNOPSIS SYNOPSIS
find_table_in_list() find_table_in_list()
table - pointer to table list table Pointer to table list
db_name - data base name or 0 for any offset Offset to which list in table structure to use
table_name - table name or 0 for any 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 RETURN VALUES
NULL Table not found NULL Table not found
# Pointer to found table. # Pointer to found table.
*/ */
TABLE_LIST * find_table_in_list(TABLE_LIST *table, TABLE_LIST *find_table_in_list(TABLE_LIST *table,
const char *db_name, const char *table_name) uint offset,
const char *db_name,
const char *table_name)
{ {
for (; table; table= table->next) for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
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)
if (!strcmp(table->db, db_name) && if (!strcmp(table->db, db_name) &&
!strcmp(table->real_name, table_name)) !strcmp(table->real_name, table_name))
break; break;
}
return table; return table;
} }
@ -1364,7 +1320,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
db Database name db Database name
name Table name name Table name
alias Alias name alias Alias name
table_desc TABLE_LIST descriptor table_desc TABLE_LIST descriptor (used with views)
mem_root temporary mem_root for parsing mem_root temporary mem_root for parsing
NOTES NOTES
@ -1402,10 +1358,10 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (!entry->crashed) if (!entry->crashed)
{ {
/* /*
Frm file could not be found on disk Frm file could not be found on disk
Since it does not exist, no one can be using it Since it does not exist, no one can be using it
LOCK_open has been locked to protect from someone else LOCK_open has been locked to protect from someone else
trying to discover the table at the same time. trying to discover the table at the same time.
*/ */
if (discover_retry_count++ != 0) if (discover_retry_count++ != 0)
goto err; goto err;
@ -1610,7 +1566,7 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
tables->table->grant= tables->grant; tables->table->grant= tables->grant;
} }
thd->proc_info=0; 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); 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; thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */ /* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE; 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) if (table)
{ {
@ -1910,7 +1867,7 @@ bool rm_temporary_table(enum db_type base, char *path)
** return unique field ** 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 *not_found_field= (Field*) 0x1;
const Field *view_ref_found= (Field*) 0x2; const Field *view_ref_found= (Field*) 0x2;
@ -2006,6 +1963,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
return fld; return fld;
} }
/* /*
Find field in table 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 Drops in all fields instead of current '*' field
Returns pointer to last inserted field if ok
****************************************************************************/ 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 bool
insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
const char *table_name, List_iterator<Item> *it, const char *table_name, List_iterator<Item> *it,
bool any_privileges) bool any_privileges)
{ {
/* allocate variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
Field_iterator_view view_iter;
uint found; uint found;
DBUG_ENTER("insert_fields"); DBUG_ENTER("insert_fields");
found=0; found= 0;
for (; tables; tables= tables->next_local) 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, if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
tables->alias) && tables->alias) &&
(!db_name || !strcmp(tables->db,db_name)))) (!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) if (tables->view)
{ {
Field_iterator_view fields; view_iter.set(tables);
fields.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant, if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant,
tables->view_db.str, tables->view_db.str,
tables->view_name.str, tables->view_name.str,
&fields)) &view_iter))
DBUG_RETURN(1); goto err;
} }
else else
{ {
Field_iterator_table fields; table_iter.set(tables);
fields.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &table->grant, if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
table->table_cache_key, table->real_name, table->table_cache_key, table->real_name,
&fields)) &table_iter))
DBUG_RETURN(1); goto err;
} }
} }
#endif #endif
/* allocate 2 variables on stack to avoid pool alloaction */ natural_join_table= 0;
Field_iterator_table table_iter; thd->used_tables|= table->map;
Field_iterator_view view_iter; last= embedded= tables;
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;
while ((embedding= embedded->embedding) && while ((embedding= embedded->embedding) &&
embedding->join_list->elements != 1) embedding->join_list->elements != 1)
@ -2682,7 +2654,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
iterator= &table_iter; iterator= &table_iter;
iterator->set(tables); iterator->set(tables);
for (; iterator->end(); iterator->next()) for (; !iterator->end_of_fields(); iterator->next())
{ {
Item *not_used_item; Item *not_used_item;
uint not_used_field_index= NO_CACHED_FIELD_INDEX; 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, thd->host_or_ip,
fld->field_name, fld->field_name,
tab); tab);
/* TODO: should be removed to have only one send_error */ goto err;
send_error(thd);
DBUG_RETURN(1);
} }
} }
#endif #endif
@ -2770,15 +2740,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
table->used_fields=table->fields; table->used_fields=table->fields;
} }
} }
if (!found) if (found)
{ DBUG_RETURN(0);
if (!table_name)
my_error(ER_NO_TABLES_USED,MYF(0)); if (!table_name)
else my_error(ER_NO_TABLES_USED, MYF(0));
my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name); else
send_error(thd); my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
}
DBUG_RETURN(!found); err:
send_error(thd);
DBUG_RETURN(1);
} }
@ -2867,13 +2839,16 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
if (arena) if (arena)
thd->set_n_backup_item_arena(arena, &backup); thd->set_n_backup_item_arena(arena, &backup);
TABLE *t1=tab1->table; TABLE *t1=tab1->table;
TABLE *t2=tab2->table; TABLE *t2=tab2->table;
/* allocate 2 variables on stack to avoid pool alloaction */
Field_iterator_table table_iter; Field_iterator_table table_iter;
Field_iterator_view view_iter; Field_iterator_view view_iter;
Field_iterator *iterator; Field_iterator *iterator;
Field *t1_field, *t2_field;
Item *item_t2;
Item_cond_and *cond_and=new Item_cond_and(); Item_cond_and *cond_and=new Item_cond_and();
if (!cond_and) // If not out of memory if (!cond_and) // If not out of memory
DBUG_RETURN(1); DBUG_RETURN(1);
cond_and->top_level_item(); cond_and->top_level_item();
@ -2889,9 +2864,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
table_iter.set(tab1); table_iter.set(tab1);
} }
Field *t1_field, *t2_field; for (; !iterator->end_of_fields(); iterator->next())
Item *item_t2;
for (; iterator->end(); iterator->next())
{ {
const char *t1_field_name= iterator->name(); const char *t1_field_name= iterator->name();
uint not_used_field_index= NO_CACHED_FIELD_INDEX; 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 table_desc TABLE_LIST descriptor
mem_root temporary MEM_ROOT for parsing mem_root temporary MEM_ROOT for parsing
*/ */
static my_bool static my_bool
open_new_frm(const char *path, const char *alias, open_new_frm(const char *path, const char *alias,
const char *db, const char *table_name, 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, uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
MEM_ROOT *mem_root) MEM_ROOT *mem_root)
{ {
DBUG_ENTER("open_new_frm");
LEX_STRING pathstr; LEX_STRING pathstr;
pathstr.str= (char *)path; File_parser *parser;
DBUG_ENTER("open_new_frm");
pathstr.str= (char*) path;
pathstr.length= strlen(path); pathstr.length= strlen(path);
if (!mem_root) if (!mem_root)
mem_root= &current_thd->mem_root; mem_root= &current_thd->mem_root;
File_parser *parser= sql_parse_prepare(&pathstr, mem_root, 1); if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
if (parser)
{ {
if (!strncmp("VIEW", parser->type()->str, parser->type()->length)) if (!strncmp("VIEW", parser->type()->str, parser->type()->length))
{ {
@ -3262,11 +3237,8 @@ open_new_frm(const char *path, const char *alias,
my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str); my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str);
goto err; goto err;
} }
DBUG_RETURN(0);
} }
else
goto err;
DBUG_RETURN(0);
err: err:
bzero(outparam, sizeof(TABLE)); // do not run repair bzero(outparam, sizeof(TABLE)); // do not run repair

View File

@ -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"); my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
DBUG_RETURN(-1); 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)) table_list->db, table_list->real_name))
{ {
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);

View File

@ -51,6 +51,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
List<Item> &values, ulong counter, bool check_unique) List<Item> &values, ulong counter, bool check_unique)
{ {
TABLE *table= table_list->table; TABLE *table= table_list->table;
if (fields.elements == 0 && values.elements != 0) if (fields.elements == 0 && values.elements != 0)
{ {
if (values.elements != table->fields) if (values.elements != table->fields)
@ -61,11 +62,11 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1; return -1;
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{ {
Field_iterator_table fields; Field_iterator_table fields;
fields.set_table(table); fields.set_table(table);
if (grant_option && if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
check_grant_all_columns(thd, INSERT_ACL, &table->grant,
table->table_cache_key, table->real_name, table->table_cache_key, table->real_name,
&fields)) &fields))
return -1; return -1;
@ -75,7 +76,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
} }
else else
{ // Part field list { // Part field list
TABLE_LIST *save_next= table_list->next_local; TABLE_LIST *save_next;
int res; int res;
if (fields.elements != values.elements) if (fields.elements != values.elements)
{ {
@ -85,16 +86,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1; return -1;
} }
table_list->next_local= 0;
thd->dupp_field=0; thd->dupp_field=0;
thd->lex->select_lex.no_wrap_view_item= 1; 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); 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; table_list->next_local= save_next;
thd->lex->select_lex.no_wrap_view_item= 0;
if (res) if (res)
{
return -1; return -1;
}
if (check_unique && thd->dupp_field) if (check_unique && thd->dupp_field)
{ {
@ -410,7 +410,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
!thd->cuted_fields)) !thd->cuted_fields))
{ {
thd->row_count_func= info.copied+info.deleted+info.updated; 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 else
{ {
@ -423,7 +423,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields); (ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
thd->row_count_func= info.copied+info.deleted+info.updated; 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); free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0; table->insert_values=0;
@ -447,46 +447,58 @@ abort:
check_view_insertability() check_view_insertability()
view - reference on VIEW 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 RETURN
FALSE - OK 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 TRUE - can't be used for insert
*/ */
static bool check_view_insertability(TABLE_LIST *view, ulong query_id) 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"); 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); DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
view->contain_auto_increment= 0; view->contain_auto_increment= 0;
/* check simplicity and prepare unique test of view */ /* 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) */ /* simple SELECT list entry (field without expression) */
if (trans[i]->type() != Item::FIELD_ITEM) if ((*trans)->type() != Item::FIELD_ITEM)
DBUG_RETURN(TRUE); 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; view->contain_auto_increment= 1;
/* prepare unique test */ /* prepare unique test */
((Item_field *)trans[i])->field->query_id= other_query_id; field->field->query_id= other_query_id;
} }
/* unique test */ /* 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) if (field->field->query_id == query_id)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
field->field->query_id= query_id; field->field->query_id= query_id;
} }
/* VIEW contain all fields without default value */ /* VIEW contain all fields without default value */
for (; *field_ptr; ++field_ptr) for (; *field_ptr; field_ptr++)
{ {
Field *field= *field_ptr; Field *field= *field_ptr;
/* field have not default value */ /* field have not default value */
@ -494,14 +506,13 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
(table->timestamp_field != field || (table->timestamp_field != field ||
field->unireg_check == Field::TIMESTAMP_UN_FIELD)) field->unireg_check == Field::TIMESTAMP_UN_FIELD))
{ {
uint i= 0; for (trans= trans_start; ; trans++)
for (; i < num; i++)
{ {
if (((Item_field *)trans[i])->field == *field_ptr) if (trans == trans_end)
break; 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); 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 SYNOPSIS
mysql_prepare_insert() mysql_prepare_insert_check_table()
thd - thread handler thd Thread handle
table_list - global/local table list table_list Table list (only one table)
fields List of fields to be updated
where Pointer to where clause
RETURN VALUE RETURN
0 - OK 0 ok
-1 - error (message is not sent to user) 1 ERROR
*/ */
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values, static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
List<Item> &update_fields, List<Item> &update_values, List<Item> &fields, COND **where)
enum_duplicates duplic)
{ {
bool insert_into_view= (table_list->view != 0); 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' */ if (setup_tables(thd, table_list, where))
Item *unused_conds= 0; DBUG_RETURN(1);
if (setup_tables(thd, table_list, &unused_conds))
DBUG_RETURN(-1);
if (insert_into_view && !fields.elements) 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))) check_view_insertability(table_list, thd->query_id)))
{ {
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); 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, if (check_insert_fields(thd, table_list, fields, *values, 1,
!insert_into_view) || !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)))) setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
DBUG_RETURN(-1); 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)) table_list->db, table_list->real_name))
{ {
my_error(ER_UPDATE_TABLE_USED, MYF(0), 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) int mysql_insert_select_prepare(THD *thd)
{ {
LEX *lex= thd->lex; 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"); DBUG_ENTER("mysql_insert_select_prepare");
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
if (setup_tables(thd, table_list, &lex->select_lex.where)) lex->field_list,
&lex->select_lex.where))
DBUG_RETURN(-1); 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); DBUG_RETURN(0);
} }

View File

@ -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) 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; return 1;
for (SELECT_LEX_UNIT *un= first_inner_unit(); for (SELECT_LEX_UNIT *un= first_inner_unit();
@ -1662,14 +1662,16 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
SYNOPSIS SYNOPSIS
unlink_first_table() 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 NOTES
We rely on fact that first table in both list are same or local list We rely on fact that first table in both list are same or local list
is empty is empty
RETURN RETURN
0 If 'query_tables' == 0
unlinked table unlinked table
In this case link_to_local is set.
*/ */
TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) 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; TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
if (query_tables != first_table && first_table != 0) if (query_tables != first_table && first_table != 0)
{ {
TABLE_LIST *next;
if (query_tables_last == &first_table->next_global) if (query_tables_last == &first_table->next_global)
query_tables_last= first_table->prev_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= *first_table->prev_global= first_table->next_global))
if (next)
next->prev_global= first_table->prev_global; next->prev_global= first_table->prev_global;
/* include in new place */ /* include in new place */
first_table->next_global= query_tables; first_table->next_global= query_tables;

View File

@ -78,6 +78,7 @@ const char *command_name[]={
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave", "Binlog Dump","Table Dump", "Connect Out", "Register Slave",
"Prepare", "Prepare Execute", "Long Data", "Close stmt", "Prepare", "Prepare Execute", "Long Data", "Close stmt",
"Reset stmt", "Set option", "Fetch",
"Error" // Last command number "Error" // Last command number
}; };
@ -1910,7 +1911,7 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(first_table == all_tables && first_table != 0);
*/ */
lex->first_lists_tables_same(); 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; all_tables= lex->query_tables;
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE && if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
@ -2386,8 +2387,8 @@ mysql_execute_command(THD *thd)
of query of query
*/ */
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
find_real_table_in_list(select_tables, create_table->db, find_table_in_global_list(select_tables, create_table->db,
create_table->real_name)) create_table->real_name))
{ {
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name); net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
goto create_error; goto create_error;
@ -2756,7 +2757,7 @@ unsent_create_error:
unit->set_limit(select_lex, select_lex); unit->set_limit(select_lex, select_lex);
// is table which we are changing used somewhere in other parts of query // 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)) first_table->db, first_table->real_name))
{ {
/* Using same table for INSERT and SELECT */ /* Using same table for INSERT and SELECT */
@ -3915,7 +3916,7 @@ error:
1 - access denied, error is sent to client 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, if (check_access(thd, privilege, all_tables->db,
&all_tables->grant.privilege, 0, 0)) &all_tables->grant.privilege, 0, 0))
@ -3959,13 +3960,13 @@ bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors) 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 #ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access; ulong db_access;
#endif #endif
ulong dummy; 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) if (save_priv)
*save_priv=0; *save_priv=0;
else 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) if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{ {
DBUG_PRINT("error",("No database"));
if (!no_errors) 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 */ 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)) || if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
! db && dont_check_global_grants) ! db && dont_check_global_grants)
{ // We can never grant this { // We can never grant this
DBUG_PRINT("error",("No possible access"));
if (!no_errors) if (!no_errors)
net_printf(thd,ER_ACCESS_DENIED_ERROR, net_printf(thd,ER_ACCESS_DENIED_ERROR,
thd->priv_user, 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; db_access=thd->db_access;
/* Remove SHOW attribute and access rights we already have */ /* Remove SHOW attribute and access rights we already have */
want_access &= ~(thd->master_access | EXTRA_ACL); 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); db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
/* grant_option is set if there exists a single table or column grant */ /* grant_option is set if there exists a single table or column grant */
if (db_access == want_access || if (db_access == want_access ||
((grant_option && !dont_check_global_grants) && (grant_option && !dont_check_global_grants &&
!(want_access & ~(db_access | TABLE_ACLS)))) !(want_access & ~(db_access | TABLE_ACLS))))
DBUG_RETURN(FALSE); /* Ok */ DBUG_RETURN(FALSE); /* Ok */
DBUG_PRINT("error",("Access denied"));
if (!no_errors) if (!no_errors)
net_printf(thd,ER_DBACCESS_DENIED_ERROR, net_printf(thd,ER_DBACCESS_DENIED_ERROR,
thd->priv_user, thd->priv_user,
@ -4111,6 +4118,42 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE; 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, bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list) TABLE_LIST *table_list)
{ {
@ -4971,6 +5014,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{ {
register TABLE_LIST *ptr; register TABLE_LIST *ptr;
char *alias_str; char *alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list"); DBUG_ENTER("add_table_to_list");
if (!table) 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->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel; ptr->derived= table->sel;
ptr->select_lex= thd->lex->current_select; ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1; ptr->cacheable_table= 1;
if (use_index_arg) if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) 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); 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; *(ptr->prev_global= lex->query_tables_last)= ptr;
lex->query_tables_last= &ptr->next_global; lex->query_tables_last= &ptr->next_global;
DBUG_RETURN(ptr); DBUG_RETURN(ptr);

View File

@ -1680,8 +1680,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
if (lex->empty_field_list_on_rset) if (lex->empty_field_list_on_rset)
{ {
lex->field_list.empty();
lex->empty_field_list_on_rset= 0; lex->empty_field_list_on_rset= 0;
lex->field_list.empty();
} }
for (; sl; sl= sl->next_select_in_list()) for (; sl; sl= sl->next_select_in_list())
{ {

View File

@ -225,25 +225,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
thd->net.report_error)); thd->net.report_error));
if (thd->net.report_error) if (thd->net.report_error)
res= 1; res= 1;
if (res > 0) if (unlikely(res))
{ {
if (result) if (result)
{ {
result->send_error(0, NullS); if (res > 0)
result->send_error(0, NullS);
result->abort(); result->abort();
} }
else else if (res > 0)
send_error(thd, 0, NullS); send_error(thd, 0, NullS);
res= 1; // Error sent to client res= 1; // Error sent to client
} }
if (res < 0)
{
if (result)
{
result->abort();
}
res= 1;
}
if (result != lex->result) if (result != lex->result)
delete result; delete result;
DBUG_RETURN(res); DBUG_RETURN(res);
@ -348,9 +341,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if ((subselect= select_lex->master_unit()->item)) if ((subselect= select_lex->master_unit()->item))
{ {
Item_subselect::trans_res res; Item_subselect::trans_res res;
if ((res= ((!thd->lex->view_prepare_mode) ? if ((res= subselect->select_transformer(this)) !=
subselect->select_transformer(this) :
subselect->no_select_transform())) !=
Item_subselect::RES_OK) Item_subselect::RES_OK)
{ {
select_lex->fix_prepare_information(thd, &conds); select_lex->fix_prepare_information(thd, &conds);
@ -552,6 +543,7 @@ JOIN::optimize()
if (cond_value == Item::COND_FALSE || if (cond_value == Item::COND_FALSE ||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */ { /* Impossible cond */
DBUG_PRINT("info", ("Impossible WHERE"));
zero_result_cause= "Impossible WHERE"; zero_result_cause= "Impossible WHERE";
error= 0; error= 0;
DBUG_RETURN(0); DBUG_RETURN(0);
@ -569,20 +561,24 @@ JOIN::optimize()
{ {
if (res > 1) if (res > 1)
{ {
DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (res < 0) if (res < 0)
{ {
DBUG_PRINT("info",("No matching min/max row"));
zero_result_cause= "No matching min/max row"; zero_result_cause= "No matching min/max row";
error=0; error=0;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away"; zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved tables_list= 0; // All tables resolved
} }
} }
if (!tables_list) if (!tables_list)
{ {
DBUG_PRINT("info",("No tables"));
error= 0; error= 0;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -11570,7 +11566,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
SYNOPSIS SYNOPSIS
print_join() print_join()
thd thread handler thd thread handler
str string where table should bbe printed str string where table should be printed
tables list of tables in join 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); print_join(thd, str, &nested_join->join_list);
str->append(')'); 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 else
{ {
append_identifier(thd, str, db, db_length); const char *cmp_name; // Name to compare with alias
str->append('.'); if (view_name.str)
append_identifier(thd, str, real_name, real_name_length); {
if (my_strcasecmp(table_alias_charset, real_name, alias)) 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(' '); str->append(' ');
append_identifier(thd, str, alias, strlen(alias)); append_identifier(thd, str, alias, strlen(alias));
@ -11665,7 +11662,7 @@ void st_select_lex::print(THD *thd, String *str)
str->append("select ", 7); str->append("select ", 7);
//options /* First add options */
if (options & SELECT_STRAIGHT_JOIN) if (options & SELECT_STRAIGHT_JOIN)
str->append("straight_join ", 14); str->append("straight_join ", 14);
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) && if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&

View File

@ -1575,11 +1575,11 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
MODE_MAXDB | MODE_MAXDB |
MODE_ANSI)) != 0; MODE_ANSI)) != 0;
buff->append("CREATE ", 7); buff->append("CREATE ", 7);
if(!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE || if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
table->algorithm == VIEW_ALGORITHM_TMEPTABLE)) table->algorithm == VIEW_ALGORITHM_TMPTABLE))
{ {
buff->append("ALGORITHM=", 10); buff->append("ALGORITHM=", 10);
if (table->algorithm == VIEW_ALGORITHM_TMEPTABLE) if (table->algorithm == VIEW_ALGORITHM_TMPTABLE)
buff->append("TMPTABLE ", 9); buff->append("TMPTABLE ", 9);
else else
buff->append("MERGE ", 6); buff->append("MERGE ", 6);

View File

@ -496,7 +496,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1); DBUG_RETURN(-1);
/* Check that we are not using table that we are updating in a sub select */ /* 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)) table_list->db, table_list->real_name))
{ {
my_error(ER_UPDATE_TABLE_USED, MYF(0), 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> &not_used_values,
{ {
TABLE *table=table_ref->table; TABLE *table=table_ref->table;
if (!(tables_to_update & table->map) && 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_ref->real_name))
table->no_cache= 1; // Disable row cache table->no_cache= 1; // Disable row cache
} }

View File

@ -90,25 +90,8 @@ int mysql_create_view(THD *thd,
/* /*
Ensure that we have some privilage on this table, more strict check Ensure that we have some privilage on this table, more strict check
will be done on column level after preparation, 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, if (check_some_access(thd, VIEW_ANY_ACL, tbl))
&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))
)
{ {
my_printf_error(ER_TABLEACCESS_DENIED_ERROR, my_printf_error(ER_TABLEACCESS_DENIED_ERROR,
ER(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 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; tbl->grant.want_privilege= SELECT_ACL;
/* /*
@ -176,7 +159,7 @@ int mysql_create_view(THD *thd,
/* check that tables are not temporary */ /* check that tables are not temporary */
for (tbl= tables; tbl; tbl= tbl->next_global) 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); my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias);
res= -1; res= -1;
@ -206,19 +189,18 @@ int mysql_create_view(THD *thd,
/* view list (list of view fields names) */ /* view list (list of view fields names) */
if (lex->view_list.elements) 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) if (lex->view_list.elements != select_lex->item_list.elements)
{ {
my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0)); my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0));
goto err; goto err;
} }
List_iterator_fast<Item> it(select_lex->item_list); while ((item= it++, name= nm++))
List_iterator_fast<LEX_STRING> nm(lex->view_list);
Item *item;
LEX_STRING *name;
while((item= it++, name= nm++))
{
item->set_name(name->str, name->length, system_charset_info); item->set_name(name->str, name->length, system_charset_info);
}
} }
/* Test absence of duplicates names */ /* Test absence of duplicates names */
@ -226,11 +208,11 @@ int mysql_create_view(THD *thd,
Item *item; Item *item;
List_iterator_fast<Item> it(select_lex->item_list); List_iterator_fast<Item> it(select_lex->item_list);
it++; it++;
while((item= it++)) while ((item= it++))
{ {
Item *check; Item *check;
List_iterator_fast<Item> itc(select_lex->item_list); 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) if (strcmp(item->name, check->name) == 0)
{ {
@ -252,7 +234,7 @@ int mysql_create_view(THD *thd,
Item *item; Item *item;
fill_effective_table_privileges(thd, &view->grant, db, fill_effective_table_privileges(thd, &view->grant, db,
view->real_name); view->real_name);
while((item= it++)) while ((item= it++))
{ {
uint priv= (get_column_grant(thd, &view->grant, db, uint priv= (get_column_grant(thd, &view->grant, db,
view->real_name, item->name) & view->real_name, item->name) &
@ -261,10 +243,10 @@ int mysql_create_view(THD *thd,
{ {
Item_field *fld= (Item_field *)item; 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 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 */ /* VIEW column has more privileges */
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
@ -280,7 +262,7 @@ int mysql_create_view(THD *thd,
} }
else else
{ {
if (!test(priv & SELECT_ACL)) if (!(priv & SELECT_ACL))
{ {
/* user have not privilege to SELECT expression */ /* user have not privilege to SELECT expression */
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
@ -304,14 +286,11 @@ int mysql_create_view(THD *thd,
goto err; goto err;
} }
VOID(pthread_mutex_lock(&LOCK_open)); VOID(pthread_mutex_lock(&LOCK_open));
if ((res= mysql_register_view(thd, view, mode))) res= mysql_register_view(thd, view, mode);
{
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
goto err;
}
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd); start_waiting_global_read_lock(thd);
if (res)
goto err;
send_ok(thd); send_ok(thd);
lex->link_first_table_back(view, link_to_local); 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 */ /* index of last required parameter for making view */
static const int required_view_parameters= 7; static const int required_view_parameters= 7;
static char *view_field_names[]= /*
{ table of VIEW .frm field descriptors
(char*)"query",
(char*)"md5", Note that one should NOT change the order for this, as it's used by
(char*)"updatable", parse()
(char*)"algorithm", */
(char*)"revision",
(char*)"timestamp",
(char*)"create-version",
(char*)"source"
};
// table of VIEW .frm field descriprors
static File_option view_parameters[]= static File_option view_parameters[]=
{{{view_field_names[0], 5}, offsetof(TABLE_LIST, query), {{{(char*) "query", 5}, offsetof(TABLE_LIST, query),
FILE_OPTIONS_STRING}, FILE_OPTIONS_STRING},
{{view_field_names[1], 3}, offsetof(TABLE_LIST, md5), {{(char*) "md5", 3}, offsetof(TABLE_LIST, md5),
FILE_OPTIONS_STRING}, FILE_OPTIONS_STRING},
{{view_field_names[2], 9}, offsetof(TABLE_LIST, updatable_view), {{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable_view),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{view_field_names[3], 9}, offsetof(TABLE_LIST, algorithm), {{(char*) "algorithm", 9}, offsetof(TABLE_LIST, algorithm),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{view_field_names[4], 8}, offsetof(TABLE_LIST, revision), {{(char*) "revision", 8}, offsetof(TABLE_LIST, revision),
FILE_OPTIONS_REV}, FILE_OPTIONS_REV},
{{view_field_names[5], 9}, offsetof(TABLE_LIST, timestamp), {{(char*) "timestamp", 9}, offsetof(TABLE_LIST, timestamp),
FILE_OPTIONS_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}, FILE_OPTIONS_ULONGLONG},
{{view_field_names[7], 6}, offsetof(TABLE_LIST, source), {{(char*) "source", 6}, offsetof(TABLE_LIST, source),
FILE_OPTIONS_ESTRING}, FILE_OPTIONS_ESTRING},
{{NULL, 0}, 0, {{NULL, 0}, 0,
FILE_OPTIONS_STRING} FILE_OPTIONS_STRING}
}; };
static const uint required_view_parameters= 6;
static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}}; 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); dir.length= strlen(dir_buff);
file.str= file_buff; file.str= file_buff;
file.length= my_snprintf(file_buff, FN_REFLEN, "%s%s", file.length= (strxnmov(file_buff, FN_REFLEN, view->real_name, reg_ext,
view->real_name, reg_ext); NullS) - file_buff);
/* init timestamp */ /* init timestamp */
if (!test(view->timestamp.str)) if (!view->timestamp.str)
view->timestamp.str= view->timestamp_buffer; view->timestamp.str= view->timestamp_buffer;
// check old .frm // check old .frm
{ {
char path_buff[FN_REFLEN]; char path_buff[FN_REFLEN];
LEX_STRING path; LEX_STRING path;
File_parser *parser;
path.str= path_buff; path.str= path_buff;
fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME); fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
path.length= strlen(path_buff); path.length= strlen(path_buff);
@ -435,34 +412,27 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
File_parser *parser= sql_parse_prepare(&path, &thd->mem_root, 0); if (!(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
{
DBUG_RETURN(1); 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 else
@ -493,14 +463,14 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
} }
view->algorithm= thd->lex->create_view_algorithm; view->algorithm= thd->lex->create_view_algorithm;
if ((view->updatable_view= (can_be_merged && 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 // TODO: change here when we will support UNIONs
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first; for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
tbl; tbl;
tbl= tbl->next_local) tbl= tbl->next_local)
{ {
if (tbl->view != 0 && !tbl->updatable_view) if (tbl->view && !tbl->updatable_view)
{ {
view->updatable_view= 0; view->updatable_view= 0;
break; break;
@ -525,9 +495,11 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
table - TABLE_LIST structure for filling table - TABLE_LIST structure for filling
RETURN RETURN
TRUE OK 0 ok
FALSE error 1 error
*/ */
my_bool my_bool
mysql_make_view(File_parser *parser, TABLE_LIST *table) 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) if (table->view)
{ {
DBUG_PRINT("info", 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)); table->view_db.str, table->view_name.str));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -557,7 +529,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
thd->set_n_backup_item_arena(arena, &backup); thd->set_n_backup_item_arena(arena, &backup);
/* init timestamp */ /* init timestamp */
if (!test(table->timestamp.str)) if (!table->timestamp.str)
table->timestamp.str= table->timestamp_buffer; table->timestamp.str= table->timestamp_buffer;
/* /*
TODO: when VIEWs will be stored in cache, table mem_root should 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 SELECT allow marging
- VIEW used in subquery or command support MERGE algorithm - 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() && lex->can_be_merged() &&
(table->select_lex->master_unit() != &old_lex->unit || (table->select_lex->master_unit() != &old_lex->unit ||
old_lex->can_use_merged()) && old_lex->can_use_merged()) &&
@ -733,7 +705,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
goto ok; goto ok;
} }
table->effective_algorithm= VIEW_ALGORITHM_TMEPTABLE; table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE")); DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE"));
lex->select_lex.linkage= DERIVED_TABLE_TYPE; lex->select_lex.linkage= DERIVED_TABLE_TYPE;
table->updatable= 0; table->updatable= 0;
@ -746,7 +718,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
{ {
if ((tbl_end= table->next_global)) 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)) if ((tbl_end->next_global= old_next))
tbl_end->next_global->prev_global= &tbl_end->next_global; tbl_end->next_global->prev_global= &tbl_end->next_global;
} }
@ -810,6 +783,7 @@ err:
-1 Error -1 Error
1 Error and error message given 1 Error and error message given
*/ */
int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
{ {
DBUG_ENTER("mysql_drop_view"); 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) for (view= views; view; view= view->next_local)
{ {
strxmov(path, mysql_data_home, "/", view->db, "/", view->real_name, strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
reg_ext, NullS); view->real_name, reg_ext, NullS);
(void) unpack_filename(path, path); (void) unpack_filename(path, path);
VOID(pthread_mutex_lock(&LOCK_open)); VOID(pthread_mutex_lock(&LOCK_open));
if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW))) 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; File file;
char header[10]; //"TYPE=VIEW\n" it is 10 characters char header[10]; //"TYPE=VIEW\n" it is 10 characters
int length;
DBUG_ENTER("mysql_frm_type"); DBUG_ENTER("mysql_frm_type");
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0) if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
{ {
DBUG_RETURN(FRMTYPE_ERROR); DBUG_RETURN(FRMTYPE_ERROR);
} }
if (my_read(file, (byte*) header, 10, MYF(MY_WME)) == MY_FILE_ERROR) length= my_read(file, (byte*) header, 10, MYF(MY_WME));
{
my_close(file, MYF(MY_WME));
DBUG_RETURN(FRMTYPE_ERROR);
}
my_close(file, MYF(MY_WME)); my_close(file, MYF(MY_WME));
if (strncmp(header, "TYPE=VIEW\n", 10) != 0) if (length == (int) MY_FILE_ERROR)
DBUG_RETURN(FRMTYPE_TABLE); DBUG_RETURN(FRMTYPE_ERROR);
DBUG_RETURN(FRMTYPE_VIEW); 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) 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"); DBUG_ENTER("check_key_in_view");
if (!view->view) if (!view->view)
DBUG_RETURN(FALSE); /* it is normal table */ 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; elements_in_view= view->view->select_lex.item_list.elements;
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;
DBUG_ASSERT(view->table != 0 && view->field_translation != 0); DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
/* try to find key */ /* Loop over all keys to see if a unique-not-null key is used */
for (uint i=0; i < table->keys; i++, key_info++) for (;key_info != key_info_end ; key_info++)
{ {
if (i == primary_key && !strcmp(key_info->name, primary_key_name) || if ((key_info->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
key_info->flags & HA_NOSAME)
{ {
KEY_PART_INFO *key_part= key_info->key_part; KEY_PART_INFO *key_part= key_info->key_part;
bool found= 1; KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
for (uint j=0; j < key_info->key_parts && found; j++, key_part++)
/* check that all key parts are used */
for (;;)
{ {
found= 0; uint k;
for (uint k= 0; k < num; k++) for (k= 0; k < elements_in_view; k++)
{ {
if (trans[k]->type() == Item::FIELD_ITEM && if (trans[k]->type() == Item::FIELD_ITEM &&
((Item_field *)trans[k])->field == key_part->field && ((Item_field *)trans[k])->field == key_part->field)
(key_part->field->flags & NOT_NULL_FLAG))
{
found= 1;
break; 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 */ /* check all fields presence */
{ {
Field **field_ptr= table->field; Field **field_ptr;
for (; *field_ptr; ++field_ptr) for (field_ptr= table->field; *field_ptr; field_ptr++)
{ {
uint i= 0; for (i= 0; i < elements_in_view; i++)
for (; i < num; i++)
{ {
if (trans[i]->type() == Item::FIELD_ITEM && if (trans[i]->type() == Item::FIELD_ITEM &&
((Item_field *)trans[i])->field == *field_ptr) ((Item_field *)trans[i])->field == *field_ptr)
break; break;
} }
if (i >= num) if (i == elements_in_view) // If field didn't exists
{ {
ulong mode= thd->variables.sql_updatable_view_key; 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 || if (mode == 1 ||
(mode == 2 && (mode == 2 &&
thd->lex->select_lex.select_limit == 1)) thd->lex->unit.global_parameters->select_limit == 1))
{ {
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
else push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
{ ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY));
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, DBUG_RETURN(FALSE);
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) void insert_view_fields(List<Item> *list, TABLE_LIST *view)
{ {
uint num= view->view->select_lex.item_list.elements; uint elements_in_view= view->view->select_lex.item_list.elements;
Item **trans= view->field_translation; Item **trans;
DBUG_ENTER("insert_view_fields"); DBUG_ENTER("insert_view_fields");
if (!trans)
if (!(trans= view->field_translation))
DBUG_VOID_RETURN; 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) if (trans[i]->type() == Item::FIELD_ITEM)
{
list->push_back(trans[i]); list->push_back(trans[i]);
}
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@ -7553,7 +7553,7 @@ algorithm:
| ALGORITHM_SYM EQ MERGE_SYM | ALGORITHM_SYM EQ MERGE_SYM
{ Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; } { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; }
| ALGORITHM_SYM EQ TEMPTABLE_SYM | ALGORITHM_SYM EQ TEMPTABLE_SYM
{ Lex->create_view_algorithm= VIEW_ALGORITHM_TMEPTABLE; } { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; }
; ;
check_option: check_option:
/* empty */ {} /* empty */ {}

View File

@ -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)); DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
error=1; 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, if ((file=my_open(fn_format(index_file, name, "", reg_ext,
MY_UNPACK_FILENAME), 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)); bzero((char*) outparam,sizeof(*outparam));
outparam->blob_ptr_size=sizeof(char*); outparam->blob_ptr_size=sizeof(char*);
disk_buff=NULL; record= NULL; keynames=NullS;
outparam->db_stat = db_stat; outparam->db_stat = db_stat;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); 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); my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
outparam->real_name=strdup_root(&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); DBUG_RETURN (0);
err_w_init: err_w_init:
//awoid problem with uninitialized data /* Avoid problem with uninitialized data */
bzero((char*) outparam,sizeof(*outparam)); bzero((char*) outparam,sizeof(*outparam));
outparam->real_name= (char*)name+dirname_length(name); outparam->real_name= (char*)name+dirname_length(name);
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
disk_buff= 0;
err_not_open: err_not_open:
x_free((gptr) disk_buff); x_free((gptr) disk_buff);
@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name)
st_table_list::calc_md5() st_table_list::calc_md5()
buffer buffer for md5 writing buffer buffer for md5 writing
*/ */
void st_table_list::calc_md5(char *buffer) void st_table_list::calc_md5(char *buffer)
{ {
my_MD5_CTX context; my_MD5_CTX context;
unsigned char digest[16]; uchar digest[16];
my_MD5Init (&context); my_MD5Init(&context);
my_MD5Update (&context,(unsigned char *) query.str, query.length); my_MD5Update(&context,(uchar *) query.str, query.length);
my_MD5Final (digest, &context); my_MD5Final(digest, &context);
sprintf((char *) buffer, sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3], digest[0], digest[1], digest[2], digest[3],
@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer)
SYNOPSIS SYNOPSIS
st_table_list::set_ancestor() st_table_list::set_ancestor()
*/ */
void st_table_list::set_ancestor() void st_table_list::set_ancestor()
{ {
if (ancestor->ancestor) if (ancestor->ancestor)
@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor()
(without fields) for name resolving, but substituted expressions will (without fields) for name resolving, but substituted expressions will
return correct used tables mask. return correct used tables mask.
*/ */
bool st_table_list::setup_ancestor(THD *thd, Item **conds) bool st_table_list::setup_ancestor(THD *thd, Item **conds)
{ {
Item **transl; Item **transl;
@ -1520,15 +1520,15 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->set_query_id= 1; thd->set_query_id= 1;
/* this view was prepared already on previous PS/SP execution */ /* this view was prepared already on previous PS/SP execution */
Item **end= field_translation + select->item_list.elements; 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; uint want_privilege= ancestor->table->grant.want_privilege;
/* real rights will be checked in VIEW field */ /* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0; ancestor->table->grant.want_privilege= 0;
/* aggregate function are allowed */ /* aggregate function are allowed */
thd->allow_sum_func= 1; 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; goto err;
ancestor->table->grant.want_privilege= want_privilege; 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; thd->set_query_id= 1;
while ((item= it++)) 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; uint want_privilege= ancestor->table->grant.want_privilege;
/* real rights will be checked in VIEW field */ /* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0; ancestor->table->grant.want_privilege= 0;
/* aggregate function are allowed */ /* aggregate function are allowed */
thd->allow_sum_func= 1; thd->allow_sum_func= 1;
if (!item->fixed && item->fix_fields(thd, ancestor, &item)) if (!item->fixed && item->fix_fields(thd, ancestor, &item))
{
goto err; goto err;
}
ancestor->table->grant.want_privilege= want_privilege; ancestor->table->grant.want_privilege= want_privilege;
transl[i++]= item; transl[i++]= item;
} }
field_translation= transl; 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) if (where)
{ {
@ -1580,12 +1578,12 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
goto err; goto err;
if (arena) if (arena)
thd->set_n_backup_item_arena(arena, &backup); thd->set_n_backup_item_arena(arena, &backup);
if (outer_join) if (outer_join)
{ {
/* /*
Store WHERE condition to ON expression for outer join, because we 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 expression will not be moved to WHERE condition (i.e. will be clean
correctly for PS/SP) correctly for PS/SP)
*/ */

View File

@ -182,7 +182,7 @@ struct st_table {
#define JOIN_TYPE_RIGHT 2 #define JOIN_TYPE_RIGHT 2
#define VIEW_ALGORITHM_UNDEFINED 0 #define VIEW_ALGORITHM_UNDEFINED 0
#define VIEW_ALGORITHM_TMEPTABLE 1 #define VIEW_ALGORITHM_TMPTABLE 1
#define VIEW_ALGORITHM_MERGE 2 #define VIEW_ALGORITHM_MERGE 2
struct st_lex; struct st_lex;
@ -270,7 +270,7 @@ public:
virtual ~Field_iterator() {} virtual ~Field_iterator() {}
virtual void set(TABLE_LIST *)= 0; virtual void set(TABLE_LIST *)= 0;
virtual void next()= 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 const char *name()= 0;
virtual Item *item(THD *)= 0; virtual Item *item(THD *)= 0;
virtual Field *field()= 0; virtual Field *field()= 0;
@ -285,7 +285,7 @@ public:
void set(TABLE_LIST *table) { ptr= table->table->field; } void set(TABLE_LIST *table) { ptr= table->table->field; }
void set_table(TABLE *table) { ptr= table->field; } void set_table(TABLE *table) { ptr= table->field; }
void next() { ptr++; } void next() { ptr++; }
bool end() { return test(*ptr); } bool end_of_fields() { return *ptr == 0; }
const char *name(); const char *name();
Item *item(THD *thd); Item *item(THD *thd);
Field *field() { return *ptr; } Field *field() { return *ptr; }
@ -299,7 +299,7 @@ public:
Field_iterator_view() :ptr(0), array_end(0) {} Field_iterator_view() :ptr(0), array_end(0) {}
void set(TABLE_LIST *table); void set(TABLE_LIST *table);
void next() { ptr++; } void next() { ptr++; }
bool end() { return ptr < array_end; } bool end_of_fields() { return ptr == array_end; }
const char *name(); const char *name();
Item *item(THD *thd) { return *ptr; } Item *item(THD *thd) { return *ptr; }
Field *field() { return 0; } Field *field() { return 0; }

View File

@ -30,6 +30,7 @@
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
#define MAX_KEY 64
/* set default options */ /* set default options */
static char *opt_db= 0; static char *opt_db= 0;
@ -5507,6 +5508,7 @@ static void test_subselect()
MYSQL_STMT *stmt; MYSQL_STMT *stmt;
int rc, id; int rc, id;
MYSQL_BIND bind[1]; MYSQL_BIND bind[1];
DBUG_ENTER("test_subselect");
myheader("test_subselect"); myheader("test_subselect");
@ -5608,6 +5610,7 @@ static void test_subselect()
assert(rc == MYSQL_NO_DATA); assert(rc == MYSQL_NO_DATA);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
DBUG_VOID_RETURN;
} }
@ -7018,13 +7021,13 @@ static void test_explain_bug()
"", "", "", 10, 0); "", "", "", 10, 0);
verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, 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, verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN, 0); "", "", "", NAME_LEN, 0);
verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, 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, verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*16, 0); "", "", "", NAME_LEN*16, 0);