mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Merge 4.1 -> 5.0.
This commit is contained in:
@ -21,12 +21,14 @@
|
||||
#include "sql_acl.h"
|
||||
|
||||
static int check_null_fields(THD *thd,TABLE *entry);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
|
||||
static int write_delayed(THD *thd,TABLE *table, enum_duplicates dup,
|
||||
char *query, uint query_length, bool log_on);
|
||||
static void end_delayed_insert(THD *thd);
|
||||
extern "C" pthread_handler_decl(handle_delayed_insert,arg);
|
||||
static void unlink_blobs(register TABLE *table);
|
||||
#endif
|
||||
|
||||
/* Define to force use of my_malloc() if the allocated memory block is big */
|
||||
|
||||
@ -39,9 +41,9 @@ static void unlink_blobs(register TABLE *table);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Check if insert fields are correct
|
||||
Updates table->time_stamp to point to timestamp field or 0, depending on
|
||||
if timestamp should be updated or not.
|
||||
Check if insert fields are correct.
|
||||
Sets table->timestamp_default_now/on_update_now to 0 o leaves it to point
|
||||
to timestamp field, depending on if timestamp should be updated or not.
|
||||
*/
|
||||
|
||||
int
|
||||
@ -62,7 +64,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
||||
check_grant_all_columns(thd,INSERT_ACL,table))
|
||||
return -1;
|
||||
#endif
|
||||
table->time_stamp=0; // This is saved by caller
|
||||
table->timestamp_default_now= table->timestamp_on_update_now= 0;
|
||||
}
|
||||
else
|
||||
{ // Part field list
|
||||
@ -81,18 +83,18 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
||||
table_list.grant=table->grant;
|
||||
|
||||
thd->dupp_field=0;
|
||||
if (setup_tables(&table_list, 0) ||
|
||||
if (setup_tables(&table_list) ||
|
||||
setup_fields(thd, 0, &table_list,fields,1,0,0))
|
||||
return -1;
|
||||
|
||||
if (thd->dupp_field)
|
||||
{
|
||||
my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
|
||||
return -1;
|
||||
}
|
||||
table->time_stamp=0;
|
||||
if (table->timestamp_field && // Don't set timestamp if used
|
||||
table->timestamp_field->query_id != thd->query_id)
|
||||
table->time_stamp= table->timestamp_field->offset()+1;
|
||||
table->timestamp_field->query_id == thd->query_id)
|
||||
table->timestamp_default_now= table->timestamp_on_update_now= 0;
|
||||
}
|
||||
// For the values we need select_priv
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
@ -109,7 +111,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
List<Item> &update_values,
|
||||
enum_duplicates duplic)
|
||||
{
|
||||
int error;
|
||||
int error, res;
|
||||
/*
|
||||
log_on is about delayed inserts only.
|
||||
By default, both logs are enabled (this won't cause problems if the server
|
||||
@ -124,7 +126,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
TABLE *table;
|
||||
List_iterator_fast<List_item> its(values_list);
|
||||
List_item *values;
|
||||
char *query=thd->query;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
char *query= thd->query;
|
||||
#endif
|
||||
thr_lock_type lock_type = table_list->lock_type;
|
||||
TABLE_LIST *insert_table_list= (TABLE_LIST*)
|
||||
thd->lex->select_lex.table_list.first;
|
||||
@ -135,15 +139,20 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
if we are told to replace duplicates, the insert cannot be concurrent
|
||||
delayed insert changed to regular in slave thread
|
||||
*/
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
lock_type=TL_WRITE;
|
||||
#else
|
||||
if ((lock_type == TL_WRITE_DELAYED &&
|
||||
((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
|
||||
thd->slave_thread || !max_insert_delayed_threads)) ||
|
||||
thd->slave_thread || !thd->variables.max_insert_delayed_threads)) ||
|
||||
(lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) ||
|
||||
(duplic == DUP_UPDATE))
|
||||
lock_type=TL_WRITE;
|
||||
#endif
|
||||
table_list->lock_type= lock_type;
|
||||
|
||||
int res;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
{
|
||||
if (thd->locked_tables)
|
||||
@ -172,6 +181,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
res= open_and_lock_tables(thd, table_list);
|
||||
if (res)
|
||||
DBUG_RETURN(-1);
|
||||
@ -191,7 +201,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
}
|
||||
|
||||
if (check_insert_fields(thd,table,fields,*values,1) ||
|
||||
setup_tables(insert_table_list, 0) ||
|
||||
setup_tables(insert_table_list) ||
|
||||
setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
|
||||
(duplic == DUP_UPDATE &&
|
||||
(setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) ||
|
||||
@ -223,7 +233,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
Fill in the given fields and dump it to the table file
|
||||
*/
|
||||
|
||||
info.records=info.deleted=info.copied=0;
|
||||
info.records= info.deleted= info.copied= info.updated= 0;
|
||||
info.handle_duplicates=duplic;
|
||||
info.update_fields=&update_fields;
|
||||
info.update_values=&update_values;
|
||||
@ -289,12 +299,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
{
|
||||
error=write_delayed(thd,table,duplic,query, thd->query_length, log_on);
|
||||
query=0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
error=write_record(table,&info);
|
||||
if (error)
|
||||
break;
|
||||
@ -315,6 +327,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
Now all rows are inserted. Time to update logs and sends response to
|
||||
user
|
||||
*/
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
{
|
||||
if (!error)
|
||||
@ -326,6 +339,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
query_cache_invalidate3(thd, table_list, 1);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (bulk_insert)
|
||||
{
|
||||
@ -356,7 +370,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
For the transactional algorithm to work the invalidation must be
|
||||
before binlog writing and ha_autocommit_...
|
||||
*/
|
||||
if (info.copied || info.deleted)
|
||||
if (info.copied || info.deleted || info.updated)
|
||||
{
|
||||
query_cache_invalidate3(thd, table_list, 1);
|
||||
}
|
||||
@ -364,7 +378,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
transactional_table= table->file->has_transactions();
|
||||
|
||||
log_delayed= (transactional_table || table->tmp_table);
|
||||
if ((info.copied || info.deleted) && (error <= 0 || !transactional_table))
|
||||
if ((info.copied || info.deleted || info.updated) &&
|
||||
(error <= 0 || !transactional_table))
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
@ -404,7 +419,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
goto abort;
|
||||
if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) ||
|
||||
!thd->cuted_fields))
|
||||
send_ok(thd,info.copied+info.deleted,id);
|
||||
send_ok(thd,info.copied+info.deleted+info.updated,id);
|
||||
else
|
||||
{
|
||||
char buff[160];
|
||||
@ -414,16 +429,18 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
|
||||
else
|
||||
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
|
||||
(ulong) info.deleted, (ulong) thd->cuted_fields);
|
||||
::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff);
|
||||
(ulong) info.deleted+info.updated, (ulong) thd->cuted_fields);
|
||||
::send_ok(thd,info.copied+info.deleted+info.updated,(ulonglong)id,buff);
|
||||
}
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
abort:
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
end_delayed_insert(thd);
|
||||
#endif
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
DBUG_RETURN(-1);
|
||||
@ -517,12 +534,22 @@ int write_record(TABLE *table,COPY_INFO *info)
|
||||
goto err;
|
||||
if ((error=table->file->update_row(table->record[1],table->record[0])))
|
||||
goto err;
|
||||
info->deleted++;
|
||||
info->updated++;
|
||||
break;
|
||||
}
|
||||
else /* DUP_REPLACE */
|
||||
{
|
||||
if (last_uniq_key(table,key_nr))
|
||||
/*
|
||||
The manual defines the REPLACE semantics that it is either
|
||||
an INSERT or DELETE(s) + INSERT; FOREIGN KEY checks in
|
||||
InnoDB do not function in the defined way if we allow MySQL
|
||||
to convert the latter operation internally to an UPDATE.
|
||||
We also should not perform this conversion if we have
|
||||
timestamp field with ON UPDATE which is different from DEFAULT.
|
||||
*/
|
||||
if (last_uniq_key(table,key_nr) &&
|
||||
!table->file->referenced_by_foreign_key() &&
|
||||
table->timestamp_default_now == table->timestamp_on_update_now)
|
||||
{
|
||||
if ((error=table->file->update_row(table->record[1],
|
||||
table->record[0])))
|
||||
@ -588,6 +615,8 @@ static int check_null_fields(THD *thd __attribute__((unused)),
|
||||
A thread is created for each table that one uses with the DELAYED attribute.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
||||
class delayed_row :public ilink {
|
||||
public:
|
||||
char *record,*query;
|
||||
@ -595,7 +624,8 @@ public:
|
||||
time_t start_time;
|
||||
bool query_start_used,last_insert_id_used,insert_id_used, log_query;
|
||||
ulonglong last_insert_id;
|
||||
ulong time_stamp;
|
||||
ulong timestamp_default_now;
|
||||
ulong timestamp_on_update_now;
|
||||
uint query_length;
|
||||
|
||||
delayed_row(enum_duplicates dup_arg, bool log_query_arg)
|
||||
@ -729,7 +759,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
|
||||
if (!(tmp=find_handler(thd,table_list)))
|
||||
{
|
||||
/* Don't create more than max_insert_delayed_threads */
|
||||
if (delayed_insert_threads >= max_insert_delayed_threads)
|
||||
if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads)
|
||||
DBUG_RETURN(0);
|
||||
thd->proc_info="Creating delayed handler";
|
||||
pthread_mutex_lock(&LOCK_delayed_create);
|
||||
@ -875,6 +905,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
|
||||
{
|
||||
if (!(*field= (*org_field)->new_field(&client_thd->mem_root,copy)))
|
||||
return 0;
|
||||
(*field)->orig_table= copy; // Remove connection
|
||||
(*field)->move_field(adjust_ptrs); // Point at copy->record[0]
|
||||
if (*org_field == found_next_number_field)
|
||||
(*field)->table->found_next_number_field= *field;
|
||||
@ -885,9 +916,10 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
|
||||
if (table->timestamp_field)
|
||||
{
|
||||
/* Restore offset as this may have been reset in handle_inserts */
|
||||
copy->time_stamp=table->timestamp_field->offset()+1;
|
||||
copy->timestamp_field=
|
||||
(Field_timestamp*) copy->field[table->timestamp_field_offset];
|
||||
copy->timestamp_field->unireg_check= table->timestamp_field->unireg_check;
|
||||
copy->timestamp_field->set_timestamp_offsets();
|
||||
}
|
||||
|
||||
/* _rowid is not used with delayed insert */
|
||||
@ -938,7 +970,8 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic,
|
||||
row->last_insert_id_used= thd->last_insert_id_used;
|
||||
row->insert_id_used= thd->insert_id_used;
|
||||
row->last_insert_id= thd->last_insert_id;
|
||||
row->time_stamp= table->time_stamp;
|
||||
row->timestamp_default_now= table->timestamp_default_now;
|
||||
row->timestamp_on_update_now= table->timestamp_on_update_now;
|
||||
|
||||
di->rows.push_back(row);
|
||||
di->stacked_inserts++;
|
||||
@ -1277,7 +1310,8 @@ bool delayed_insert::handle_inserts(void)
|
||||
thd.last_insert_id=row->last_insert_id;
|
||||
thd.last_insert_id_used=row->last_insert_id_used;
|
||||
thd.insert_id_used=row->insert_id_used;
|
||||
table->time_stamp=row->time_stamp;
|
||||
table->timestamp_default_now= row->timestamp_default_now;
|
||||
table->timestamp_on_update_now= row->timestamp_on_update_now;
|
||||
|
||||
info.handle_duplicates= row->dup;
|
||||
if (info.handle_duplicates == DUP_IGNORE ||
|
||||
@ -1310,8 +1344,15 @@ bool delayed_insert::handle_inserts(void)
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
delete row;
|
||||
/* Let READ clients do something once in a while */
|
||||
if (group_count++ == max_rows)
|
||||
/*
|
||||
Let READ clients do something once in a while
|
||||
We should however not break in the middle of a multi-line insert
|
||||
if we have binary logging enabled as we don't want other commands
|
||||
on this table until all entries has been processed
|
||||
*/
|
||||
if (group_count++ >= max_rows && (row= rows.head()) &&
|
||||
(!(row->log_query & DELAYED_LOG_BIN && using_bin_log) ||
|
||||
row->query))
|
||||
{
|
||||
group_count=0;
|
||||
if (stacked_inserts || tables_in_use) // Let these wait a while
|
||||
@ -1368,8 +1409,7 @@ bool delayed_insert::handle_inserts(void)
|
||||
pthread_mutex_lock(&mutex);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
||||
/***************************************************************************
|
||||
Store records in INSERT ... SELECT *
|
||||
@ -1454,7 +1494,8 @@ void select_insert::send_error(uint errcode,const char *err)
|
||||
error while inserting into a MyISAM table) we must write to the binlog (and
|
||||
the error code will make the slave stop).
|
||||
*/
|
||||
if ((info.copied || info.deleted) && !table->file->has_transactions())
|
||||
if ((info.copied || info.deleted || info.updated) &&
|
||||
!table->file->has_transactions())
|
||||
{
|
||||
if (last_insert_id)
|
||||
thd->insert_id(last_insert_id); // For binary log
|
||||
@ -1467,7 +1508,7 @@ void select_insert::send_error(uint errcode,const char *err)
|
||||
if (!table->tmp_table)
|
||||
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
||||
}
|
||||
if (info.copied || info.deleted)
|
||||
if (info.copied || info.deleted || info.updated)
|
||||
{
|
||||
query_cache_invalidate3(thd, table, 1);
|
||||
}
|
||||
@ -1490,7 +1531,7 @@ bool select_insert::send_eof()
|
||||
and ha_autocommit_...
|
||||
*/
|
||||
|
||||
if (info.copied || info.deleted)
|
||||
if (info.copied || info.deleted || info.updated)
|
||||
{
|
||||
query_cache_invalidate3(thd, table, 1);
|
||||
if (!(table->file->has_transactions() || table->tmp_table))
|
||||
@ -1523,8 +1564,8 @@ bool select_insert::send_eof()
|
||||
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
|
||||
else
|
||||
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
|
||||
(ulong) info.deleted, (ulong) thd->cuted_fields);
|
||||
::send_ok(thd,info.copied+info.deleted,last_insert_id,buff);
|
||||
(ulong) info.deleted+info.updated, (ulong) thd->cuted_fields);
|
||||
::send_ok(thd,info.copied+info.deleted+info.updated,last_insert_id,buff);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -1539,8 +1580,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
DBUG_ENTER("select_create::prepare");
|
||||
|
||||
unit= u;
|
||||
table=create_table_from_items(thd, create_info, db, name,
|
||||
extra_fields, keys, &values, &lock);
|
||||
table= create_table_from_items(thd, create_info, db, name,
|
||||
extra_fields, keys, &values, &lock);
|
||||
if (!table)
|
||||
DBUG_RETURN(-1); // abort() deletes table
|
||||
|
||||
@ -1555,11 +1596,9 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
/* First field to copy */
|
||||
field=table->field+table->fields - values.elements;
|
||||
|
||||
if (table->timestamp_field) // Don't set timestamp if used
|
||||
{
|
||||
table->timestamp_field->set_time();
|
||||
table->time_stamp=0; // This should be saved
|
||||
}
|
||||
/* Don't set timestamp if used */
|
||||
table->timestamp_default_now= table->timestamp_on_update_now= 0;
|
||||
|
||||
table->next_number_field=table->found_next_number_field;
|
||||
|
||||
restore_record(table,default_values); // Get empty record
|
||||
@ -1645,7 +1684,9 @@ void select_create::abort()
|
||||
|
||||
#ifdef __GNUC__
|
||||
template class List_iterator_fast<List_item>;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
template class I_List<delayed_insert>;
|
||||
template class I_List_iterator<delayed_insert>;
|
||||
template class I_List<delayed_row>;
|
||||
#endif
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
#endif /* __GNUC__ */
|
||||
|
Reference in New Issue
Block a user