Commit 161662ba authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-5.0

into sanja.is.com.ua:/home/bell/mysql/bk/work-5.0
parents 3cdb85a0 32594c99
......@@ -2384,7 +2384,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
char buff[4 /* size of stmt id */ +
5 /* execution flags */];
DBUG_ENTER("execute");
DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length));
DBUG_DUMP("packet", packet, length);
mysql->last_used_con= mysql;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
......
......@@ -1764,6 +1764,26 @@ call bug5251()|
Table Checksum
test.t1 0
drop procedure bug5251|
create procedure bug5287(param1 int)
label1:
begin
declare c cursor for select 5;
loop
if param1 >= 0 then
leave label1;
end if;
end loop;
end|
call bug5287(1)|
drop procedure bug5287|
create procedure bug5307()
begin
end; set @x = 3|
call bug5307()|
select @x|
@x
3
drop procedure bug5307|
drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned)
......
......@@ -1924,6 +1924,35 @@ call bug5251()|
call bug5251()|
drop procedure bug5251|
#
# BUG#5287: Stored procedure crash if leave outside loop
#
create procedure bug5287(param1 int)
label1:
begin
declare c cursor for select 5;
loop
if param1 >= 0 then
leave label1;
end if;
end loop;
end|
call bug5287(1)|
drop procedure bug5287|
#
# BUG#5307: Stored procedure allows statement after BEGIN ... END
#
create procedure bug5307()
begin
end; set @x = 3|
call bug5307()|
select @x|
drop procedure bug5307|
#
# Some "real" examples
......
......@@ -1143,8 +1143,27 @@ bool Item_param::convert_str_value(THD *thd)
return rc;
}
/* End of Item_param related */
void Item_param::print(String *str)
{
if (state == NO_VALUE)
{
str->append('?');
}
else
{
char buffer[80];
String tmp(buffer, sizeof(buffer), &my_charset_bin);
const String *res;
res= query_val_str(&tmp);
str->append(*res);
}
}
/****************************************************************************
Item_copy_string
****************************************************************************/
void Item_copy_string::copy()
{
......
......@@ -635,7 +635,7 @@ class Item_param :public Item
*/
virtual table_map used_tables() const
{ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
void print(String *str) { str->append('?'); }
void print(String *str);
/* parameter never equal to other parameter of other item */
bool eq(const Item *item, bool binary_cmp) const { return 0; }
};
......
......@@ -995,23 +995,6 @@ Item_in_subselect::select_transformer(JOIN *join)
}
Item_subselect::trans_res
Item_in_subselect::no_select_transform()
{
DBUG_ENTER("Item_in_subselect::no_select_transform");
// We have execute fix_fields() for left expression
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
}
thd->lex->current_select= current;
DBUG_RETURN(RES_OK);
}
void Item_in_subselect::print(String *str)
{
if (transformed)
......
......@@ -84,7 +84,6 @@ class Item_subselect :public Item_result_field
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 @@ class Item_in_subselect :public Item_exists_subselect
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);
......
......@@ -838,13 +838,13 @@ int MYSQL_LOG::purge_logs(const char *to_log,
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!log_in_use(log_info.log_file_name))
{
ulong tmp;
LINT_INIT(tmp);
ulong file_size;
LINT_INIT(file_size);
if (decrease_log_space) //stat the file we want to delete
{
MY_STAT s;
if (my_stat(log_info.log_file_name,&s,MYF(0)))
tmp= s.st_size;
file_size= s.st_size;
else
{
/*
......@@ -852,7 +852,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
of space that deletion will free. In most cases,
deletion won't work either, so it's not a problem.
*/
tmp= 0;
file_size= 0;
}
}
/*
......@@ -861,7 +861,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
*/
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
*decrease_log_space-= tmp;
*decrease_log_space-= file_size;
if (find_next_log(&log_info, 0) || exit_loop)
break;
}
......
......@@ -398,8 +398,9 @@ void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
int check_one_table_access(THD *thd, ulong privilege,
bool check_one_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
int multi_update_precheck(THD *thd, TABLE_LIST *tables);
......@@ -767,12 +768,10 @@ void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd);
TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
const char *db_name,
const char *table_name);
TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table,
const char *db_name,
const char *table_name);
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset_to_list,
const char *db_name,
const char *table_name);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1);
......@@ -788,6 +787,23 @@ int fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors);
int fill_record(Field **field,List<Item> &values, bool ignore_errors);
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
return find_table_in_list(table, offsetof(TABLE_LIST, next_global),
db_name, table_name);
}
inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
return find_table_in_list(table, offsetof(TABLE_LIST, next_local),
db_name, table_name);
}
/* sql_calc.cc */
bool eval_const_cond(COND *cond);
......
......@@ -288,6 +288,7 @@ void
sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
{
DBUG_ENTER("sp_head::init_strings");
uint n; /* Counter for nul trimming */
/* During parsing, we must use thd->mem_root */
MEM_ROOT *root= &thd->mem_root;
......@@ -351,9 +352,17 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
(char *)m_returns_begin, m_retstr.length);
}
}
m_body.length= lex->end_of_query - m_body_begin;
m_body.length= lex->ptr - m_body_begin;
/* Trim nuls at the end */
n= 0;
while (m_body.length && m_body_begin[m_body.length-1] == '\0')
{
m_body.length-= 1;
n+= 1;
}
m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
m_defstr.length= lex->end_of_query - lex->buf;
m_defstr.length= lex->ptr - lex->buf;
m_defstr.length-= n;
m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
DBUG_VOID_RETURN;
}
......
......@@ -28,7 +28,7 @@
sp_pcontext::sp_pcontext(sp_pcontext *prev)
: Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
m_parent(prev), m_handlers(0)
m_handlers(0), m_parent(prev)
{
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
......@@ -94,7 +94,7 @@ sp_pcontext::diff_handlers(sp_pcontext *ctx)
while (pctx && pctx != ctx)
{
n+= pctx->max_handlers();
n+= pctx->m_handlers;
pctx= pctx->parent_context();
}
if (pctx)
......@@ -109,12 +109,9 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx)
sp_pcontext *pctx= this;
while (pctx && pctx != ctx)
{
n+= pctx->max_cursors();
pctx= pctx->parent_context();
}
if (pctx)
return n;
return ctx->current_cursors() - pctx->current_cursors();
return 0; // Didn't find ctx
}
......
......@@ -275,6 +275,7 @@ class sp_pcontext : public Sql_alloc
uint m_psubsize;
uint m_csubsize;
uint m_hsubsize;
uint m_handlers; // No. of handlers in this context
private:
......@@ -282,7 +283,6 @@ class sp_pcontext : public Sql_alloc
uint m_poffset; // Variable offset for this context
uint m_coffset; // Cursor offset for this context
uint m_handlers; // No. of handlers in this context
DYNAMIC_ARRAY m_pvar; // Parameters/variables
DYNAMIC_ARRAY m_cond; // Conditions
......
......@@ -2761,7 +2761,22 @@ void grant_reload(THD *thd)
/****************************************************************************
Check table level grants
All errors are written directly to the client if no_errors is given !
SYNPOSIS
bool check_grant()
thd Thread handler
want_access Bits of privileges user needs to have
tables List of tables to check. The user should have 'want_access'
to all tables in list.
show_table <> 0 if we are in show table. In this case it's enough to have
any privilege for the table
number Check at most this number of tables.
no_errors If 0 then we write an error. The error is sent directly to
the client
RETURN
0 ok
1 Error: User did not have the requested privielges
****************************************************************************/
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
......@@ -2769,14 +2784,17 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
{
TABLE_LIST *table;
char *user = thd->priv_user;
DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0);
want_access &= ~thd->master_access;
want_access&= ~thd->master_access;
if (!want_access)
return 0; // ok
DBUG_RETURN(0); // ok
rw_rdlock(&LOCK_grant);
for (table= tables; table && number--; table= table->next_global)
{
GRANT_TABLE *grant_table;
if (!(~table->grant.privilege & want_access) || table->derived)
{
/*
......@@ -2786,10 +2804,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
table->grant.want_privilege= 0;
continue; // Already checked
}
GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
table->db,user,
table->real_name,0);
if (!grant_table)
if (!(grant_table= table_hash_search(thd->host,thd->ip,
table->db,user, table->real_name,0)))
{
want_access &= ~table->grant.privilege;
goto err; // No grants
......@@ -2813,7 +2829,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
}
}
rw_unlock(&LOCK_grant);
return 0;
DBUG_RETURN(0);
err:
rw_unlock(&LOCK_grant);
......@@ -2848,7 +2864,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
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,
......
This diff is collapsed.
......@@ -282,7 +282,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
DBUG_RETURN(-1);
}
if (find_real_table_in_list(table_list->next_global,
if (find_table_in_global_list(table_list->next_global,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
......
......@@ -51,6 +51,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
List<Item> &values, ulong counter, bool check_unique)
{
TABLE *table= table_list->table;
if (fields.elements == 0 && values.elements != 0)
{
if (values.elements != table->fields)
......@@ -61,11 +62,11 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{
Field_iterator_table fields;
fields.set_table(table);
if (grant_option &&
check_grant_all_columns(thd, INSERT_ACL, &table->grant,
if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
table->table_cache_key, table->real_name,
&fields))
return -1;
......@@ -75,7 +76,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
}
else
{ // Part field list
TABLE_LIST *save_next= table_list->next_local;
TABLE_LIST *save_next;
int res;
if (fields.elements != values.elements)
{
......@@ -85,16 +86,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1;
}
table_list->next_local= 0;
thd->dupp_field=0;
thd->lex->select_lex.no_wrap_view_item= 1;
save_next= table_list->next_local; // fields only from first table
table_list->next_local= 0;
res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
thd->lex->select_lex.no_wrap_view_item= 0;
table_list->next_local= save_next;
thd->lex->select_lex.no_wrap_view_item= 0;
if (res)
{
return -1;
}
if (check_unique && thd->dupp_field)
{
......@@ -410,7 +410,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
!thd->cuted_fields))
{
thd->row_count_func= info.copied+info.deleted+info.updated;
send_ok(thd, (ulong) (ulong) thd->row_count_func, id);
send_ok(thd, (ulong) thd->row_count_func, id);
}
else
{
......@@ -423,7 +423,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
thd->row_count_func= info.copied+info.deleted+info.updated;
::send_ok(thd, (ulong) thd->row_count_func, (ulonglong)id,buff);
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
}
free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0;
......@@ -447,46 +447,58 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
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->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
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)
{
......@@ -545,8 +555,37 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
DBUG_RETURN(-1);
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
/*
Prepare items in INSERT statement
SYNOPSIS
mysql_prepare_insert()
thd Thread handler
table_list Global/local table list
RETURN VALUE
0 OK
-1 error (message is not sent to user)
*/
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic)
{
bool insert_into_view= (table_list->view != 0);
/* TODO: use this condition for 'WITH CHECK OPTION' */
Item *unused_conds= 0;
DBUG_ENTER("mysql_prepare_insert");
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds))
DBUG_RETURN(-1);
if (check_insert_fields(thd, table_list, fields, *values, 1,
!insert_into_view) ||
......@@ -556,7 +595,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
DBUG_RETURN(-1);
if (find_real_table_in_list(table_list->next_global,
if (find_table_in_global_list(table_list->next_global,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
......@@ -1558,27 +1597,11 @@ bool delayed_insert::handle_inserts(void)
int mysql_insert_select_prepare(THD *thd)
{
LEX *lex= thd->lex;
TABLE_LIST *table_list= lex->query_tables;
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_insert_select_prepare");
if (setup_tables(thd, table_list, &lex->select_lex.where))
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
lex->field_list,
&lex->select_lex.where))
DBUG_RETURN(-1);
if (insert_into_view && !lex->field_list.elements)
{
lex->empty_field_list_on_rset= 1;
insert_view_fields(&lex->field_list, table_list);
}
if (!table_list->updatable ||
check_key_in_view(thd, table_list) ||
(insert_into_view &&
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
DBUG_RETURN(-1);
}
DBUG_RETURN(0);
}
......
......@@ -1421,7 +1421,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
*/
bool st_select_lex::check_updateable(char *db, char *table)
{
if (find_real_table_in_local_list(get_table_list(), db, table))
if (find_table_in_local_list(get_table_list(), db, table))
return 1;
for (SELECT_LEX_UNIT *un= first_inner_unit();
......@@ -1662,14 +1662,16 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
SYNOPSIS
unlink_first_table()
link_to_local do we need link this table to local
link_to_local Set to 1 if caller should link this table to local
NOTES
We rely on fact that first table in both list are same or local list
is empty
RETURN
0 If 'query_tables' == 0
unlinked table
In this case link_to_local is set.
*/
TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
......@@ -1723,11 +1725,11 @@ void st_lex::first_lists_tables_same()
TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
if (query_tables != first_table && first_table != 0)
{
TABLE_LIST *next;
if (query_tables_last == &first_table->next_global)
query_tables_last= first_table->prev_global;
TABLE_LIST *next= *first_table->prev_global= first_table->next_global;
first_table->next_global= 0;
if (next)
if ((next= *first_table->prev_global= first_table->next_global))
next->prev_global= first_table->prev_global;
/* include in new place */
first_table->next_global= query_tables;
......
......@@ -78,6 +78,7 @@ const char *command_name[]={
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
"Prepare", "Prepare Execute", "Long Data", "Close stmt",
"Reset stmt", "Set option", "Fetch",
"Error" // Last command number
};
......@@ -1910,7 +1911,7 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
*/
lex->first_lists_tables_same();
/* should be assigned after making firts tables same */
/* should be assigned after making first tables same */
all_tables= lex->query_tables;
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
......@@ -2386,8 +2387,8 @@ mysql_execute_command(THD *thd)
of query
*/
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
find_real_table_in_list(select_tables, create_table->db,
create_table->real_name))
find_table_in_global_list(select_tables, create_table->db,
create_table->real_name))
{
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
goto create_error;
......@@ -2756,7 +2757,7 @@ mysql_execute_command(THD *thd)
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 @@ purposes internal to the MySQL server", MYF(0));
1 - access denied, error is sent to client
*/
int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
if (check_access(thd, privilege, all_tables->db,
&all_tables->grant.privilege, 0, 0))
......@@ -3959,13 +3960,13 @@ bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors)
{
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access,
thd->master_access));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
#endif
ulong dummy;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
db ? db : "", want_access, thd->master_access));
if (save_priv)
*save_priv=0;
else
......@@ -3973,8 +3974,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
DBUG_PRINT("error",("No database"));
if (!no_errors)
send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
......@@ -3999,6 +4001,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
! db && dont_check_global_grants)
{ // We can never grant this
DBUG_PRINT("error",("No possible access"));
if (!no_errors)
net_printf(thd,ER_ACCESS_DENIED_ERROR,
thd->priv_user,
......@@ -4017,13 +4020,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
db_access=thd->db_access;
/* Remove SHOW attribute and access rights we already have */
want_access &= ~(thd->master_access | EXTRA_ACL);
DBUG_PRINT("info",("db_access: %lu want_access: %lu",
db_access, want_access));
db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
/* grant_option is set if there exists a single table or column grant */
if (db_access == want_access ||
((grant_option && !dont_check_global_grants) &&
(grant_option && !dont_check_global_grants &&
!(want_access & ~(db_access | TABLE_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
DBUG_PRINT("error",("Access denied"));
if (!no_errors)
net_printf(thd,ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
......@@ -4111,6 +4118,42 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
/*
Check if the given table has any of the asked privileges
SYNOPSIS
check_some_access()
thd Thread handler
want_access Bitmap of possible privileges to check for
RETURN
0 ok
1 error
*/
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
{
ulong access;
DBUG_ENTER("check_some_access");
/* This loop will work as long as we have less than 32 privileges */
for (access= 1; access < want_access ; access<<= 1)
{
if (access & want_access)
{
if (!check_access(thd, access, table->db,
&table->grant.privilege, 0, 1) &&
!grant_option || !check_grant(thd, access, table, 0, 1, 1))
DBUG_RETURN(0);
}
}
DBUG_PRINT("exit",("no matching access rights"));
DBUG_RETURN(1);
}
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list)
{
......@@ -4971,6 +5014,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
register TABLE_LIST *ptr;
char *alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
if (!table)
......@@ -5022,7 +5066,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
ptr->select_lex= thd->lex->current_select;
ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
......@@ -5046,8 +5090,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
}
}
/* Link table in local list (list for current select) */
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
LEX *lex= thd->lex;
/* Link table in global list (all used tables) */
*(ptr->prev_global= lex->query_tables_last)= ptr;
lex->query_tables_last= &ptr->next_global;
DBUG_RETURN(ptr);
......
......@@ -1680,8 +1680,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
if (lex->empty_field_list_on_rset)
{
lex->field_list.empty();
lex->empty_field_list_on_rset= 0;
lex->field_list.empty();
}
for (; sl; sl= sl->next_select_in_list())
{
......
......@@ -225,25 +225,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
thd->net.report_error));
if (thd->net.report_error)
res= 1;
if (res > 0)
if (unlikely(res))
{
if (result)
{
result->send_error(0, NullS);
if (res > 0)
result->send_error(0, NullS);
result->abort();
}
else
else if (res > 0)
send_error(thd, 0, NullS);
res= 1; // Error sent to client
}
if (res < 0)
{
if (result)
{
result->abort();
}
res= 1;
}
if (result != lex->result)
delete result;
DBUG_RETURN(res);
......@@ -348,9 +341,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= ((!thd->lex->view_prepare_mode) ?
subselect->select_transformer(this) :
subselect->no_select_transform())) !=
if ((res= subselect->select_transformer(this)) !=
Item_subselect::RES_OK)
{
select_lex->fix_prepare_information(thd, &conds);
......@@ -552,6 +543,7 @@ JOIN::optimize()
if (cond_value == Item::COND_FALSE ||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */
DBUG_PRINT("info", ("Impossible WHERE"));
zero_result_cause= "Impossible WHERE";
error= 0;
DBUG_RETURN(0);
......@@ -569,20 +561,24 @@ JOIN::optimize()
{
if (res > 1)
{
DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1);
}
if (res < 0)
{
DBUG_PRINT("info",("No matching min/max row"));
zero_result_cause= "No matching min/max row";
error=0;
DBUG_RETURN(0);
}
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
}
}
if (!tables_list)
{
DBUG_PRINT("info",("No tables"));
error= 0;
DBUG_RETURN(0);
}
......@@ -11570,7 +11566,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
SYNOPSIS
print_join()
thd thread handler
str string where table should bbe printed
str string where table should be printed
tables list of tables in join
*/
......@@ -11626,30 +11622,31 @@ void st_table_list::print(THD *thd, String *str)
print_join(thd, str, &nested_join->join_list);
str->append(')');
}
else if (view_name.str)
else
{
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))
const char *cmp_name; // Name to compare with alias
if (view_name.str)
{
str->append(' ');
append_identifier(thd, str, alias, strlen(alias));
append_identifier(thd, str, view_db.str, view_db.length);
str->append('.');
append_identifier(thd, str, view_name.str, view_name.length);
cmp_name= view_name.str;
}
}
else if (derived)
{
str->append('(');
derived->print(str);
str->append(") ", 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))
else if (derived)
{
str->append('(');
derived->print(str);
str->append(')');
cmp_name= ""; // Force printing of alias
}
else
{
append_identifier(thd, str, db, db_length);
str->append('.');
append_identifier(thd, str, real_name, real_name_length);
cmp_name= real_name;
}
if (my_strcasecmp(table_alias_charset, cmp_name, alias))
{
str->append(' ');
append_identifier(thd, str, alias, strlen(alias));
......@@ -11665,7 +11662,7 @@ void st_select_lex::print(THD *thd, String *str)
str->append("select ", 7);
//options
/* First add options */
if (options & SELECT_STRAIGHT_JOIN)
str->append("straight_join ", 14);
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
......
......@@ -1575,11 +1575,11 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
MODE_MAXDB |
MODE_ANSI)) != 0;
buff->append("CREATE ", 7);
if(!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
table->algorithm == VIEW_ALGORITHM_TMEPTABLE))
if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
table->algorithm == VIEW_ALGORITHM_TMPTABLE))
{
buff->append("ALGORITHM=", 10);
if (table->algorithm == VIEW_ALGORITHM_TMEPTABLE)
if (table->algorithm == VIEW_ALGORITHM_TMPTABLE)
buff->append("TMPTABLE ", 9);
else
buff->append("MERGE ", 6);
......
......@@ -496,7 +496,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1);
/* Check that we are not using table that we are updating in a sub select */
if (find_real_table_in_list(table_list->next_global,
if (find_table_in_global_list(table_list->next_global,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
......@@ -788,7 +788,7 @@ int multi_update::prepare(List<Item> &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
}
......
This diff is collapsed.
......@@ -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 */ {}
......
......@@ -88,6 +88,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
error=1;
disk_buff=NULL;
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
if ((file=my_open(fn_format(index_file, name, "", reg_ext,
MY_UNPACK_FILENAME),
......@@ -118,11 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
bzero((char*) outparam,sizeof(*outparam));
outparam->blob_ptr_size=sizeof(char*);
disk_buff=NULL; record= NULL; keynames=NullS;
outparam->db_stat = db_stat;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
outparam->real_name=strdup_root(&outparam->mem_root,
......@@ -742,11 +741,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
DBUG_RETURN (0);
err_w_init:
//awoid problem with uninitialized data
/* Avoid problem with uninitialized data */
bzero((char*) outparam,sizeof(*outparam));
outparam->real_name= (char*)name+dirname_length(name);
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
disk_buff= 0;
err_not_open:
x_free((gptr) disk_buff);
......@@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name)
st_table_list::calc_md5()
buffer buffer for md5 writing
*/
void st_table_list::calc_md5(char *buffer)
{
my_MD5_CTX context;
unsigned char digest[16];
my_MD5Init (&context);
my_MD5Update (&context,(unsigned char *) query.str, query.length);
my_MD5Final (digest, &context);
uchar digest[16];
my_MD5Init(&context);
my_MD5Update(&context,(uchar *) query.str, query.length);
my_MD5Final(digest, &context);
sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
......@@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer)
SYNOPSIS
st_table_list::set_ancestor()
*/
void st_table_list::set_ancestor()
{
if (ancestor->ancestor)
......@@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor()
(without fields) for name resolving, but substituted expressions will
return correct used tables mask.
*/
bool st_table_list::setup_ancestor(THD *thd, Item **conds)
{
Item **transl;
......@@ -1520,15 +1520,15 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->set_query_id= 1;
/* this view was prepared already on previous PS/SP execution */
Item **end= field_translation + select->item_list.elements;
for (Item **i= field_translation; i < end; i++)
for (Item **item= field_translation; item < end; item++)
{
//TODO: fix for several tables in VIEW
/* TODO: fix for several tables in VIEW */
uint want_privilege= ancestor->table->grant.want_privilege;
/* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0;
/* aggregate function are allowed */
thd->allow_sum_func= 1;
if (!(*i)->fixed && (*i)->fix_fields(thd, ancestor, i))
if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
goto err;
ancestor->table->grant.want_privilege= want_privilege;
}
......@@ -1557,21 +1557,19 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->set_query_id= 1;
while ((item= it++))
{
//TODO: fix for several tables in VIEW
/* TODO: fix for several tables in VIEW */
uint want_privilege= ancestor->table->grant.want_privilege;
/* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0;
/* aggregate function are allowed */
thd->allow_sum_func= 1;
if (!item->fixed && item->fix_fields(thd, ancestor, &item))
{
goto err;
}
ancestor->table->grant.want_privilege= want_privilege;
transl[i++]= item;
}
field_translation= transl;
//TODO: sort this list? Use hash for big number of fields
/* TODO: sort this list? Use hash for big number of fields */
if (where)
{
......@@ -1580,12 +1578,12 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
goto err;
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
thd->set_n_backup_item_arena(arena, &backup);
if (outer_join)
{
/*
Store WHERE condition to ON expression for outer join, because we
can't use WHERE to correctly execute jeft joins on VIEWs and this
can't use WHERE to correctly execute jeft joins on VIEWs and this
expression will not be moved to WHERE condition (i.e. will be clean
correctly for PS/SP)
*/
......
......@@ -182,7 +182,7 @@ struct st_table {
#define JOIN_TYPE_RIGHT 2
#define VIEW_ALGORITHM_UNDEFINED 0
#define VIEW_ALGORITHM_TMEPTABLE 1
#define VIEW_ALGORITHM_TMPTABLE 1
#define VIEW_ALGORITHM_MERGE 2
struct st_lex;
......@@ -270,7 +270,7 @@ class Field_iterator: public Sql_alloc
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 @@ class Field_iterator_table: public Field_iterator
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 @@ class Field_iterator_view: public Field_iterator
Field_iterator_view() :ptr(0), array_end(0) {}
void set(TABLE_LIST *table);
void next() { ptr++; }
bool end() { return ptr < array_end; }
bool end_of_fields() { return ptr == array_end; }
const char *name();
Item *item(THD *thd) { return *ptr; }
Field *field() { return 0; }
......
......@@ -30,6 +30,7 @@
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
#define MAX_KEY 64
/* set default options */
static char *opt_db= 0;
......@@ -5507,6 +5508,7 @@ static void test_subselect()
MYSQL_STMT *stmt;
int rc, id;
MYSQL_BIND bind[1];
DBUG_ENTER("test_subselect");
myheader("test_subselect");
......@@ -5608,6 +5610,7 @@ static void test_subselect()
assert(rc == MYSQL_NO_DATA);
mysql_stmt_close(stmt);
DBUG_VOID_RETURN;
}
......@@ -7018,13 +7021,13 @@ static void test_explain_bug()
"", "", "", 10, 0);
verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*64, 0);
"", "", "", NAME_LEN*MAX_KEY, 0);
verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN, 0);
verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*64, 0);
"", "", "", NAME_LEN*MAX_KEY, 0);
verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*16, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment