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 */ +
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 */

View File

@ -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)

View File

@ -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

View File

@ -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()
{

View File

@ -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; }
};

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)
{
if (transformed)

View File

@ -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);

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)) &&
!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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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
}

View File

@ -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

View File

@ -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,

View File

@ -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= &current_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);

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");
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);

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)
{
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);
}

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)
{
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;

View File

@ -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);

View File

@ -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())
{

View File

@ -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) &&

View File

@ -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);

View File

@ -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> &not_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
}

View File

@ -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;
}

View File

@ -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 */ {}

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));
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)
*/

View File

@ -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; }

View File

@ -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);