1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00
This commit is contained in:
tomas@poseidon.ndb.mysql.com
2005-07-12 20:01:22 +02:00
317 changed files with 12088 additions and 4363 deletions

View File

@ -31,7 +31,7 @@ static void end_delayed_insert(THD *thd);
extern "C" pthread_handler_decl(handle_delayed_insert,arg);
static void unlink_blobs(register TABLE *table);
#endif
static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id);
static bool check_view_insertability(THD *thd, TABLE_LIST *view);
/* Define to force use of my_malloc() if the allocated memory block is big */
@ -111,7 +111,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
else
{ // Part field list
TABLE_LIST *save_next;
Name_resolution_context *context= &thd->lex->select_lex.context;
TABLE_LIST *save_next= table_list->next_local,
*save_context= context->table_list;
bool save_resolve_in_select_list=
thd->lex->select_lex.context.resolve_in_select_list;
int res;
if (fields.elements != values.elements)
{
@ -120,16 +124,19 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
thd->dupp_field=0;
thd->lex->select_lex.no_wrap_view_item= 1;
save_next= table_list->next_local; // fields only from first table
thd->lex->select_lex.no_wrap_view_item= TRUE;
/* fields only from first table */
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
/*
Indicate fields in list is to be updated by setting set_query_id
parameter to 2. This sets the bit in the write_set for each field.
*/
res= setup_fields(thd, 0, table_list, fields, 2, 0, 0);
res= setup_fields(thd, 0, fields, 2, 0, 0);
table_list->next_local= save_next;
thd->lex->select_lex.no_wrap_view_item= 0;
thd->lex->select_lex.no_wrap_view_item= FALSE;
context->table_list= save_context;
context->resolve_in_select_list= save_resolve_in_select_list;
if (res)
return -1;
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
@ -168,7 +175,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (check_key_in_view(thd, table_list) ||
(table_list->view &&
check_view_insertability(table_list, thd->query_id)))
check_view_insertability(thd, table_list)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
@ -201,7 +208,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
List<Item> &update_fields)
{
TABLE *table= insert_table_list->table;
ulong timestamp_query_id;
query_id_t timestamp_query_id;
LINT_INIT(timestamp_query_id);
/*
@ -219,7 +226,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
of all used fields to the threads query_id. It will also set all
fields into the write set of this table.
*/
if (setup_fields(thd, 0, insert_table_list, update_fields, 2, 0, 0))
if (setup_fields(thd, 0, update_fields, 2, 0, 0))
return -1;
if (table->timestamp_field)
@ -260,6 +267,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
ulonglong id;
COPY_INFO info;
TABLE *table= 0;
TABLE_LIST *next_local;
List_iterator_fast<List_item> its(values_list);
List_item *values;
#ifndef EMBEDDED_LIBRARY
@ -340,7 +348,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/* mysql_prepare_insert set table_list->table if it was not set */
table= table_list->table;
// is table which we are changing used somewhere in other parts of query
next_local= table_list->next_local;
table_list->next_local= 0;
thd->lex->select_lex.context.resolve_in_table_list_only(table_list);
value_count= values->elements;
while ((values= its++))
{
@ -350,10 +360,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
if (setup_fields(thd, 0, *values, 0, 0, 0))
goto abort;
}
its.rewind ();
table_list->next_local= next_local;
/*
Fill in the given fields and dump it to the table file
*/
@ -400,12 +411,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
MODE_STRICT_ALL_TABLES)));
if ((fields.elements || !value_count) &&
check_that_all_fields_are_given_values(thd, table))
check_that_all_fields_are_given_values(thd, table, table_list))
{
/* thd->net.report_error is now set, which will abort the next loop */
error= 1;
}
if (table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd))
error= 1;
while ((values= its++))
{
if (fields.elements || !value_count)
@ -609,6 +624,7 @@ abort:
SYNOPSIS
check_view_insertability()
thd - thread handler
view - reference on VIEW
IMPLEMENTATION
@ -625,7 +641,7 @@ abort:
TRUE - can't be used for insert
*/
static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
static bool check_view_insertability(THD * thd, TABLE_LIST *view)
{
uint num= view->view->select_lex.item_list.elements;
TABLE *table= view->table;
@ -633,15 +649,25 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
*trans_end= trans_start + num;
Field_translator *trans;
Field **field_ptr= table->field;
query_id_t other_query_id= query_id - 1;
uint used_fields_buff_size= (table->s->fields + 7) / 8;
uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size);
MY_BITMAP used_fields;
DBUG_ENTER("check_key_in_view");
if (!used_fields_buff)
DBUG_RETURN(TRUE); // EOM
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0);
bitmap_clear_all(&used_fields);
view->contain_auto_increment= 0;
/* check simplicity and prepare unique test of view */
for (trans= trans_start; trans != trans_end; trans++)
{
if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item))
return TRUE;
Item_field *field;
/* simple SELECT list entry (field without expression) */
if (!(field= trans->item->filed_for_view_update()))
@ -649,7 +675,6 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
if (field->field->unireg_check == Field::NEXT_NUMBER)
view->contain_auto_increment= 1;
/* prepare unique test */
field->field->query_id= other_query_id;
/*
remove collation (or other transparent for update function) if we have
it
@ -661,29 +686,12 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
{
/* Thanks to test above, we know that all columns are of type Item_field */
Item_field *field= (Item_field *)trans->item;
if (field->field->query_id == query_id)
/* check fields belong to table in which we are inserting */
if (field->field->table == table &&
bitmap_fast_test_and_set(&used_fields, field->field->field_index))
DBUG_RETURN(TRUE);
field->field->query_id= query_id;
}
/* VIEW contain all fields without default value */
for (; *field_ptr; field_ptr++)
{
Field *field= *field_ptr;
/* field have not default value */
if ((field->type() == FIELD_TYPE_BLOB) &&
(table->timestamp_field != field ||
field->unireg_check == Field::TIMESTAMP_UN_FIELD))
{
for (trans= trans_start; ; trans++)
{
if (trans == trans_end)
DBUG_RETURN(TRUE); // Field was not part of view
if (((Item_field *)trans->item)->field == *field_ptr)
break; // ok
}
}
}
DBUG_RETURN(FALSE);
}
@ -711,7 +719,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_prepare_insert_check_table");
if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
if (setup_tables(thd, &thd->lex->select_lex.context,
table_list, where, &thd->lex->select_lex.leaf_tables,
select_insert))
DBUG_RETURN(TRUE);
@ -724,7 +733,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(TRUE);
}
DBUG_RETURN(insert_view_fields(&fields, table_list));
DBUG_RETURN(insert_view_fields(thd, &fields, table_list));
}
DBUG_RETURN(FALSE);
@ -738,31 +747,63 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
mysql_prepare_insert()
thd Thread handler
table_list Global/local table list
table Table to insert into (can be NULL if table should be taken from
table_list->table)
table Table to insert into (can be NULL if table should
be taken from table_list->table)
where Where clause (for insert ... select)
select_insert TRUE if INSERT ... SELECT statement
TODO (in far future)
In cases of:
INSERT INTO t1 SELECT a, sum(a) as sum1 from t2 GROUP BY a
ON DUPLICATE KEY ...
we should be able to refer to sum1 in the ON DUPLICATE KEY part
WARNING
You MUST set table->insert_values to 0 after calling this function
before releasing the table object.
RETURN VALUE
FALSE OK
TRUE error
*/
bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
bool 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,
COND **where, bool select_insert)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
TABLE_LIST *save_table_list;
TABLE_LIST *save_next_local;
bool insert_into_view= (table_list->view != 0);
/* TODO: use this condition for 'WITH CHECK OPTION' */
bool res;
TABLE_LIST *next_local;
bool save_resolve_in_select_list;
bool res= 0;
DBUG_ENTER("mysql_prepare_insert");
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
/*
For subqueries in VALUES() we should not see the table in which we are
inserting (for INSERT ... SELECT this is done by changing table_list,
because INSERT ... SELECT share SELECT_LEX it with SELECT.
*/
if (!select_insert)
{
for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit();
un;
un= un->next_unit())
{
for (SELECT_LEX *sl= un->first_select();
sl;
sl= sl->next_select())
{
sl->context.outer_context= 0;
}
}
}
if (duplic == DUP_UPDATE)
{
/* it should be allocated before Item::fix_fields() */
@ -774,31 +815,54 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
select_insert))
DBUG_RETURN(TRUE);
next_local= table_list->next_local;
save_table_list= select_lex->context.table_list;
save_resolve_in_select_list= select_lex->context.resolve_in_select_list;
save_next_local= table_list->next_local;
table_list->next_local= 0;
select_lex->context.resolve_in_table_list_only(table_list);
if ((values && check_insert_fields(thd, table_list, fields, *values,
!insert_into_view)) ||
(values && setup_fields(thd, 0, table_list, *values, 0, 0, 0)) ||
(duplic == DUP_UPDATE &&
((thd->lex->select_lex.no_wrap_view_item= 1,
(res= check_update_fields(thd, table_list, update_fields)),
thd->lex->select_lex.no_wrap_view_item= 0,
res) ||
setup_fields(thd, 0, table_list, update_values, 1, 0, 0))))
DBUG_RETURN(TRUE);
table_list->next_local= next_local;
(values && setup_fields(thd, 0, *values, 0, 0, 0)))
res= TRUE;
else if (duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
res= check_update_fields(thd, table_list, update_fields);
select_lex->no_wrap_view_item= FALSE;
if (select_lex->group_list.elements == 0)
{
/*
When we are not using GROUP BY we can refer to other tables in the
ON DUPLICATE KEY part
*/
table_list->next_local= save_next_local;
}
if (!res)
res= setup_fields(thd, 0, update_values, 1, 0, 0);
}
table_list->next_local= save_next_local;
select_lex->context.table_list= save_table_list;
select_lex->context.resolve_in_select_list= save_resolve_in_select_list;
if (res)
DBUG_RETURN(res);
if (!table)
table= table_list->table;
if (!select_insert && unique_table(table_list, table_list->next_global))
if (!select_insert)
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
Item *fake_conds= 0;
if (unique_table(table_list, table_list->next_global))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
}
select_lex->fix_prepare_information(thd, &fake_conds);
select_lex->first_execution= 0;
}
if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
table->file->ha_retrieve_all_pk();
thd->lex->select_lex.first_execution= 0;
DBUG_RETURN(FALSE);
}
@ -1051,7 +1115,8 @@ before_trg_err:
Check that all fields with arn't null_fields are used
******************************************************************************/
int check_that_all_fields_are_given_values(THD *thd, TABLE *entry)
int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list)
{
int err= 0;
for (Field **field=entry->field ; *field ; field++)
@ -1060,10 +1125,29 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry)
((*field)->flags & NO_DEFAULT_VALUE_FLAG) &&
((*field)->real_type() != FIELD_TYPE_ENUM))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NO_DEFAULT_FOR_FIELD,
ER(ER_NO_DEFAULT_FOR_FIELD),
(*field)->field_name);
bool view= FALSE;
if (table_list)
{
table_list= (table_list->belong_to_view ?
table_list->belong_to_view :
table_list);
view= (bool)(table_list->view);
}
if (view)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NO_DEFAULT_FOR_VIEW_FIELD,
ER(ER_NO_DEFAULT_FOR_VIEW_FIELD),
table_list->view_db.str,
table_list->view_name.str);
}
else
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NO_DEFAULT_FOR_FIELD,
ER(ER_NO_DEFAULT_FOR_FIELD),
(*field)->field_name);
}
err= 1;
}
}
@ -1945,35 +2029,37 @@ bool delayed_insert::handle_inserts(void)
bool mysql_insert_select_prepare(THD *thd)
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= &lex->select_lex;
TABLE_LIST *first_select_leaf_table;
DBUG_ENTER("mysql_insert_select_prepare");
/*
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
clause if table is VIEW
*/
lex->query_tables->no_where_clause= 1;
if (mysql_prepare_insert(thd, lex->query_tables,
lex->query_tables->table, lex->field_list, 0,
lex->update_list, lex->value_list,
lex->duplicates,
&lex->select_lex.where, TRUE))
&select_lex->where, TRUE))
DBUG_RETURN(TRUE);
/*
exclude first table from leaf tables list, because it belong to
INSERT
*/
DBUG_ASSERT(lex->select_lex.leaf_tables != 0);
lex->leaf_tables_insert= lex->select_lex.leaf_tables;
DBUG_ASSERT(select_lex->leaf_tables != 0);
lex->leaf_tables_insert= select_lex->leaf_tables;
/* skip all leaf tables belonged to view where we are insert */
for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf;
for (first_select_leaf_table= select_lex->leaf_tables->next_leaf;
first_select_leaf_table &&
first_select_leaf_table->belong_to_view &&
first_select_leaf_table->belong_to_view ==
lex->leaf_tables_insert->belong_to_view;
first_select_leaf_table= first_select_leaf_table->next_leaf)
{}
lex->select_lex.leaf_tables= first_select_leaf_table;
select_lex->leaf_tables= first_select_leaf_table;
DBUG_RETURN(FALSE);
}
@ -2001,8 +2087,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
int
select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
int res;
LEX *lex= thd->lex;
int res;
SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
@ -2056,8 +2142,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
DBUG_RETURN(fields->elements &&
check_that_all_fields_are_given_values(thd, table));
res= ((fields->elements &&
check_that_all_fields_are_given_values(thd, table, table_list)) ||
table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd));
DBUG_RETURN(res);
}
@ -2303,7 +2392,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
DBUG_RETURN(check_that_all_fields_are_given_values(thd, table));
DBUG_RETURN(check_that_all_fields_are_given_values(thd, table,
table_list));
}