summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/view.result2
-rw-r--r--sql/item_subselect.cc17
-rw-r--r--sql/item_subselect.h2
-rw-r--r--sql/mysql_priv.h30
-rw-r--r--sql/sql_acl.cc36
-rw-r--r--sql/sql_base.cc210
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_insert.cc158
-rw-r--r--sql/sql_lex.cc12
-rw-r--r--sql/sql_parse.cc68
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc65
-rw-r--r--sql/sql_show.cc6
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_view.cc278
-rw-r--r--sql/table.cc36
-rw-r--r--sql/table.h8
-rw-r--r--tests/client_test.c5
18 files changed, 487 insertions, 454 deletions
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 98c04b31e96..37e9c8fc2fa 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -138,7 +138,6 @@ v3 VIEW
v4 VIEW
v5 VIEW
v6 VIEW
-vt1 VIEW
show table status;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
t1 MyISAM 9 Fixed 5 9 45 38654705663 1024 0 NULL # # NULL latin1_swedish_ci NULL
@@ -148,7 +147,6 @@ v3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL vie
v4 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
v5 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
v6 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
-vt1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
drop view v1,v2,v3,v4,v5,v6;
create view v1 (c,d,e,f) as select a,b,
a in (select a+2 from t1), a = all (select a from t1) from t1;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 33e661ce46e..b1d6d7bbe35 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -990,23 +990,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)
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index d50688e0b58..1268b435816 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -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);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index ba19ee15ce6..ac0890c60df 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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);
@@ -764,12 +765,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);
@@ -785,6 +784,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);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 10a12ef6d04..394d7336c79 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2750,7 +2750,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,
@@ -2758,14 +2773,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)
{
/*
@@ -2775,10 +2793,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
@@ -2802,7 +2818,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);
@@ -2837,7 +2853,7 @@ err:
thd->host_or_ip,
table ? table->real_name : "unknown");
}
- return 1;
+ DBUG_RETURN(1);
}
@@ -2931,7 +2947,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,
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 781e7273e7a..6fdc8014db1 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -548,81 +548,37 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0;
}
-#ifdef UNUSED
-/*
- Find first suitable table by alias in given 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
-
- 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)
-{
- 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.
+ Find table in 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.
+ find_table_in_list()
+ table Pointer to table list
+ offset Offset to which list in table structure to use
+ db_name Data base name
+ table_name Table name
- SYNOPSIS
- find_real_table_in_local_list()
- table - pointer to table list
- 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_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,
+ 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;
}
@@ -1363,7 +1319,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
@@ -1403,10 +1359,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;
@@ -1603,7 +1559,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);
}
@@ -1671,7 +1627,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->proc_info="Opening table";
thd->current_tablenr= 0;
- while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) ;
+ while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh)
+ ;
if (table)
{
@@ -1900,7 +1857,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;
@@ -1979,6 +1936,7 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list,
return fld;
}
+
/*
Find field in table
@@ -2561,23 +2519,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))))
@@ -2588,36 +2570,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)
@@ -2648,7 +2620,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;
@@ -2699,9 +2671,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
@@ -2735,15 +2705,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);
}
@@ -2832,13 +2804,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();
@@ -2854,9 +2829,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;
@@ -3190,17 +3163,19 @@ 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, uint db_stat, uint prgflag,
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);
- 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))
{
@@ -3217,10 +3192,7 @@ open_new_frm(const char *path, const char *alias, uint db_stat, uint prgflag,
bzero(outparam, sizeof(outparam)); // do not run repair
DBUG_RETURN(1);
}
+ DBUG_RETURN(0);
}
- else
- {
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 910b673dc32..d9d60be162a 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -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);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 33b99d4ccf9..7d3479a18bb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -51,6 +51,8 @@ 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;
+ int error;
+
if (fields.elements == 0 && values.elements != 0)
{
if (values.elements != table->fields)
@@ -61,11 +63,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 +77,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;
if (fields.elements != values.elements)
{
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
@@ -84,14 +86,13 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1;
}
- table_list->next_local= 0;
thd->dupp_field=0;
- if (setup_fields(thd, 0, table_list, fields, 1, 0, 0))
- {
- table_list->next_local= save_next;
- return -1;
- }
+ save_next= table_list->next_local; // fields only from first table
+ table_list->next_local= 0;
+ error= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
table_list->next_local= save_next;
+ if (error)
+ return -1; // setup_fields failed
if (check_unique && thd->dupp_field)
{
@@ -407,7 +408,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
{
@@ -420,7 +421,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;
@@ -444,46 +445,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)
{
- DBUG_ENTER("check_key_in_view");
-
- uint i;
+ uint num= view->view->select_lex.item_list.elements;
TABLE *table= view->table;
- Item **trans= view->field_translation;
+ Item **trans_start= view->field_translation, **trans_end=trans_start+num;
+ Item **trans;
Field **field_ptr= table->field;
- uint num= view->view->select_lex.item_list.elements;
ulong other_query_id= query_id - 1;
+ DBUG_ENTER("check_key_in_view");
+
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->type() == 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 */
@@ -491,14 +504,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);
@@ -506,29 +518,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
-
- RETURN VALUE
- 0 - OK
- -1 - error (message is not sent to user)
+ 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
+ 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)
{
@@ -542,8 +553,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) ||
@@ -553,7 +593,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);
@@ -1555,27 +1595,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);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d96c6371ff1..aa5cb04f628 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1422,7 +1422,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();
@@ -1631,14 +1631,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)
@@ -1692,11 +1694,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;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index be063211a7d..0ba1789cfbf 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1905,7 +1905,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 &&
@@ -2381,8 +2381,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;
@@ -2752,7 +2752,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 */
@@ -3907,7 +3907,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))
@@ -3951,13 +3951,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
@@ -3965,8 +3965,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 */
}
@@ -3991,6 +3992,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,
@@ -4009,13 +4011,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,
@@ -4103,6 +4109,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)
{
@@ -4960,6 +5002,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)
@@ -5011,7 +5054,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,
@@ -5035,8 +5078,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);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 5214ae95b86..46d83e61e22 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1665,8 +1665,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())
{
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 328fd4f9976..10a4d551d32 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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);
@@ -11192,7 +11183,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
*/
@@ -11248,30 +11239,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)
+ else
{
- str->append(view_db.str, view_db.length);
- str->append('.');
- str->append(view_name.str, view_name.length);
- if (my_strcasecmp(table_alias_charset, view_name.str, alias))
+ const char *cmp_name; // Name to compare with alias
+ if (view_name.str)
{
- str->append(' ');
- str->append(alias);
+ str->append(view_db.str, view_db.length);
+ str->append('.');
+ str->append(view_name.str, view_name.length);
+ cmp_name= view_name.str;
}
- }
- else if (derived)
- {
- str->append('(');
- derived->print(str);
- str->append(") ", 2);
- str->append(alias);
- }
- else
- {
- str->append(db);
- str->append('.');
- str->append(real_name);
- if (my_strcasecmp(table_alias_charset, real_name, alias))
+ else if (derived)
+ {
+ str->append('(');
+ derived->print(str);
+ str->append(')');
+ cmp_name= ""; // Force printing of alias
+ }
+ else
+ {
+ str->append(db);
+ str->append('.');
+ str->append(real_name);
+ cmp_name= real_name;
+ }
+ if (my_strcasecmp(table_alias_charset, cmp_name, alias))
{
str->append(' ');
str->append(alias);
@@ -11279,6 +11271,7 @@ void st_table_list::print(THD *thd, String *str)
}
}
+
void st_select_lex::print(THD *thd, String *str)
{
if (!thd)
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index da0a6ed3d28..d9180df3791 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1551,11 +1551,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);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 7d49c422194..77d48dccb10 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -483,7 +483,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);
@@ -760,7 +760,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
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 5a16f0ff3fc..d8198f98a32 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -79,25 +79,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),
@@ -113,7 +96,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;
/*
@@ -166,7 +149,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;
@@ -189,19 +172,18 @@ int mysql_create_view(THD *thd,
/* view list (list of view fields names) */
if (lex->view_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));
- 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++))
+
+ if (lex->view_list.elements != select_lex->item_list.elements)
{
- item->set_name(name->str, name->length, system_charset_info);
+ my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0));
+ goto err;
}
+ while ((item= it++, name= nm++))
+ item->set_name(name->str, name->length, system_charset_info);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -214,7 +196,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) &
@@ -223,10 +205,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,
@@ -242,7 +224,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,
@@ -266,14 +248,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);
@@ -292,40 +271,36 @@ err:
// index of revision number in following table
static const int revision_number_position= 4;
-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),
+ {{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable),
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}};
@@ -368,16 +343,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);
@@ -390,34 +367,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= sql_parse_prepare(&path, &thd->mem_root, 0)))
+ DBUG_RETURN(1);
+
+ if (!parser->ok() ||
+ strncmp("VIEW", parser->type()->str, parser->type()->length))
{
- 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);
- }
+ my_error(ER_WRONG_OBJECT, MYF(0), (view->db ? view->db : thd->db),
+ view->real_name, "VIEW");
+ DBUG_RETURN(1);
}
- else
+
+ /*
+ 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);
+ DBUG_RETURN(1);
}
}
else
@@ -448,14 +418,14 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
}
view->algorithm= thd->lex->create_view_algorithm;
if ((view->updatable= (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)
+ if (tbl->view && !tbl->updatable)
{
view->updatable= 0;
break;
@@ -478,7 +448,13 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
mysql_make_view()
parser - parser object;
table - TABLE_LIST structure for filling
+
+ RETURN
+ 0 ok
+ 1 error
+
*/
+
my_bool
mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
@@ -487,7 +463,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);
}
@@ -507,13 +483,14 @@ 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
be used here
*/
- if (parser->parse((gptr)table, &thd->mem_root, view_parameters, 6))
+ if (parser->parse((gptr)table, &thd->mem_root, view_parameters,
+ required_view_parameters))
goto err;
/*
@@ -535,7 +512,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
*/
table->view= lex= thd->lex= (LEX*) new(&thd->mem_root) st_lex_local;
lex_start(thd, (uchar*)table->query.str, table->query.length);
- mysql_init_query(thd, true);
+ mysql_init_query(thd, TRUE);
lex->select_lex.select_number= ++thd->select_number;
old_lex->derived_tables|= DERIVED_VIEW;
{
@@ -613,7 +590,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()))
@@ -656,11 +633,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
goto ok;
}
- table->effective_algorithm= VIEW_ALGORITHM_TMEPTABLE;
+ table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
if (table->updatable)
{
- //TOTO: warning: can't be updateable, .frm edited by hand. version
- //downgrade?
+ /*
+ TODO: warning: can't be updateable, .frm edited by hand. version
+ downgrade?
+ */
table->updatable= 0;
}
@@ -672,7 +651,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;
}
@@ -720,6 +700,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");
@@ -729,8 +710,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)))
@@ -782,21 +763,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, header, 10, MYF(MY_WME)) == MY_FILE_ERROR)
- {
- my_close(file, MYF(MY_WME));
- DBUG_RETURN(FRMTYPE_ERROR);
- }
+ length= my_read(file, 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
}
@@ -815,72 +795,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);
}
}
}
@@ -899,18 +888,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;
}
diff --git a/sql/table.cc b/sql/table.cc
index 43b39ffb37e..8ac0f409e2f 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -88,6 +88,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
error=1;
+ disk_buff=NULL;
+ old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
if ((file=my_open(fn_format(index_file, name, "", reg_ext,
MY_UNPACK_FILENAME),
@@ -118,11 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
bzero((char*) outparam,sizeof(*outparam));
outparam->blob_ptr_size=sizeof(char*);
- disk_buff=NULL; record= NULL; keynames=NullS;
outparam->db_stat = db_stat;
-
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
- old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
outparam->real_name=strdup_root(&outparam->mem_root,
@@ -742,11 +741,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
DBUG_RETURN (0);
err_w_init:
- //awoid problem with uninitialized data
+ /* Avoid problem with uninitialized data */
bzero((char*) outparam,sizeof(*outparam));
outparam->real_name= (char*)name+dirname_length(name);
- old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
- disk_buff= 0;
err_not_open:
x_free((gptr) disk_buff);
@@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name)
st_table_list::calc_md5()
buffer buffer for md5 writing
*/
+
void st_table_list::calc_md5(char *buffer)
{
my_MD5_CTX context;
- unsigned char digest[16];
- my_MD5Init (&context);
- my_MD5Update (&context,(unsigned char *) query.str, query.length);
- my_MD5Final (digest, &context);
+ uchar digest[16];
+ my_MD5Init(&context);
+ my_MD5Update(&context,(uchar *) query.str, query.length);
+ my_MD5Final(digest, &context);
sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
@@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer)
SYNOPSIS
st_table_list::set_ancestor()
*/
+
void st_table_list::set_ancestor()
{
if (ancestor->ancestor)
@@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor()
(without fields) for name resolving, but substituted expressions will
return correct used tables mask.
*/
+
bool st_table_list::setup_ancestor(THD *thd, Item **conds)
{
Item **transl;
@@ -1515,13 +1515,13 @@ 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;
- 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;
}
@@ -1545,19 +1545,17 @@ 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;
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)
{
@@ -1566,12 +1564,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)
*/
diff --git a/sql/table.h b/sql/table.h
index 5e00820a6e5..02e470a69e0 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -172,7 +172,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;
@@ -255,7 +255,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;
@@ -270,7 +270,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; }
@@ -284,7 +284,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; }
diff --git a/tests/client_test.c b/tests/client_test.c
index 13f5a3ac852..e9adf40d8b6 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -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;
@@ -6818,13 +6819,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);