Commit 7454087d authored by Monty's avatar Monty

Revert "bugfix: UPDATE and virtual BLOBs"

This reverts commit f73bdb68.
parent 1628a2ae
...@@ -3339,9 +3339,6 @@ class Field_blob :public Field_longstr { ...@@ -3339,9 +3339,6 @@ class Field_blob :public Field_longstr {
uint max_packed_col_length(uint max_length); uint max_packed_col_length(uint max_length);
void free() { value.free(); } void free() { value.free(); }
inline void clear_temporary() { bzero((uchar*) &value, sizeof(value)); } inline void clear_temporary() { bzero((uchar*) &value, sizeof(value)); }
inline bool owns_ptr(uchar* p) const { return p == (uchar*)value.ptr(); }
inline void own_value_ptr()
{ value.reset((char*)get_ptr(), get_length(), get_length(), value.charset()); }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
bool has_charset(void) const bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; } { return charset() == &my_charset_bin ? FALSE : TRUE; }
......
...@@ -201,99 +201,6 @@ typedef struct st_user_var_events ...@@ -201,99 +201,6 @@ typedef struct st_user_var_events
bool unsigned_flag; bool unsigned_flag;
} BINLOG_USER_VAR_EVENT; } BINLOG_USER_VAR_EVENT;
/*
When updating a table with virtual BLOB columns, the following might happen:
- an old record is read from the table, it has no vcol blob.
- update_virtual_fields() is run, vcol blob gets its value into the
record. But only a pointer to the value is in the table->record[0],
the value is in Field_blob::value String (or, it can be elsewhere!)
- store_record(table,record[1]), old record now is in record[1]
- fill_record() prepares new values in record[0], vcol blob is updated,
new value replaces the old one in the Field_blob::value
- now both record[1] and record[0] have a pointer that points to the
*new* vcol blob value. Or record[1] has a pointer to nowhere if
Field_blob::value had to realloc.
To resolve this we unlink vcol blobs from the pointer to the
data (in the record[1]). The orphan memory must be freed manually
(but, again, only if it was owned by Field_blob::value String).
With REPLACE and INSERT ... ON DUP KEY UPATE it's even more complex.
There is no store_record(table,record[1]), instead the row is read
directly into record[1].
*/
struct BLOB_VALUE_ORPHANAGE {
MY_BITMAP map;
TABLE *table;
BLOB_VALUE_ORPHANAGE() { map.bitmap= NULL; }
~BLOB_VALUE_ORPHANAGE() { free(); }
bool init(TABLE *table_arg)
{
table= table_arg;
if (table->s->virtual_fields && table->s->blob_fields)
return bitmap_init(&map, NULL, table->s->virtual_fields, FALSE);
map.bitmap= NULL;
return 0;
}
void free() { bitmap_free(&map); }
/** Remove blob's ownership from blob value memory
@note the memory becomes orphaned, it needs to be freed using
free_orphans() or re-attached back to blobs using adopt_orphans()
*/
void make_orphans()
{
DBUG_ASSERT(!table || !table->s->virtual_fields || !table->s->blob_fields || map.bitmap);
if (!map.bitmap)
return;
for (Field **ptr=table->vfield; *ptr; ptr++)
{
Field_blob *vb= (Field_blob*)(*ptr);
if (!(vb->flags & BLOB_FLAG) || !vb->owns_ptr(vb->get_ptr()))
continue;
bitmap_set_bit(&map, ptr - table->vfield);
vb->clear_temporary();
}
}
/** Frees orphaned blob values
@note It is assumed that value pointers are in table->record[1], while
Field_blob::ptr's point to table->record[0] as usual
*/
void free_orphans()
{
DBUG_ASSERT(!table || !table->s->virtual_fields || !table->s->blob_fields || map.bitmap);
if (!map.bitmap)
return;
for (Field **ptr=table->vfield; *ptr; ptr++)
{
Field_blob *vb= (Field_blob*)(*ptr);
if (vb->flags & BLOB_FLAG && bitmap_fast_test_and_clear(&map, ptr - table->vfield))
my_free(vb->get_ptr(table->s->rec_buff_length));
}
DBUG_ASSERT(bitmap_is_clear_all(&map));
}
/** Restores blob's ownership over previously orphaned values */
void adopt_orphans()
{
DBUG_ASSERT(!table || !table->s->virtual_fields || !table->s->blob_fields || map.bitmap);
if (!map.bitmap)
return;
for (Field **ptr=table->vfield; *ptr; ptr++)
{
Field_blob *vb= (Field_blob*)(*ptr);
if (vb->flags & BLOB_FLAG && bitmap_fast_test_and_clear(&map, ptr - table->vfield))
vb->own_value_ptr();
}
DBUG_ASSERT(bitmap_is_clear_all(&map));
}
};
/* /*
The COPY_INFO structure is used by INSERT/REPLACE code. The COPY_INFO structure is used by INSERT/REPLACE code.
The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY
...@@ -306,7 +213,7 @@ struct BLOB_VALUE_ORPHANAGE { ...@@ -306,7 +213,7 @@ struct BLOB_VALUE_ORPHANAGE {
of the INSERT ... ON DUPLICATE KEY UPDATE no matter whether the row of the INSERT ... ON DUPLICATE KEY UPDATE no matter whether the row
was actually changed or not. was actually changed or not.
*/ */
struct COPY_INFO { typedef struct st_copy_info {
ha_rows records; /**< Number of processed records */ ha_rows records; /**< Number of processed records */
ha_rows deleted; /**< Number of deleted records */ ha_rows deleted; /**< Number of deleted records */
ha_rows updated; /**< Number of updated records */ ha_rows updated; /**< Number of updated records */
...@@ -322,8 +229,7 @@ struct COPY_INFO { ...@@ -322,8 +229,7 @@ struct COPY_INFO {
/* for VIEW ... WITH CHECK OPTION */ /* for VIEW ... WITH CHECK OPTION */
TABLE_LIST *view; TABLE_LIST *view;
TABLE_LIST *table_list; /* Normal table */ TABLE_LIST *table_list; /* Normal table */
BLOB_VALUE_ORPHANAGE vblobs0, vblobs1; // vcol blobs of record[0] and record[1] } COPY_INFO;
};
class Key_part_spec :public Sql_alloc { class Key_part_spec :public Sql_alloc {
...@@ -5435,7 +5341,6 @@ class multi_update :public select_result_interceptor ...@@ -5435,7 +5341,6 @@ class multi_update :public select_result_interceptor
TABLE_LIST *update_tables, *table_being_updated; TABLE_LIST *update_tables, *table_being_updated;
TABLE **tmp_tables, *main_table, *table_to_update; TABLE **tmp_tables, *main_table, *table_to_update;
TMP_TABLE_PARAM *tmp_table_param; TMP_TABLE_PARAM *tmp_table_param;
BLOB_VALUE_ORPHANAGE *vblobs;
ha_rows updated, found; ha_rows updated, found;
List <Item> *fields, *values; List <Item> *fields, *values;
List <Item> **fields_for_table, **values_for_table; List <Item> **fields_for_table, **values_for_table;
......
...@@ -812,11 +812,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -812,11 +812,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
info.update_values= &update_values; info.update_values= &update_values;
info.view= (table_list->view ? table_list : 0); info.view= (table_list->view ? table_list : 0);
info.table_list= table_list; info.table_list= table_list;
if (duplic != DUP_ERROR)
{
info.vblobs0.init(table);
info.vblobs1.init(table);
}
/* /*
Count warnings for all inserts. Count warnings for all inserts.
...@@ -1184,6 +1179,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -1184,6 +1179,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->lex->current_select->save_leaf_tables(thd); thd->lex->current_select->save_leaf_tables(thd);
thd->lex->current_select->first_cond_optimization= 0; thd->lex->current_select->first_cond_optimization= 0;
} }
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
abort: abort:
...@@ -1695,12 +1691,9 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1695,12 +1691,9 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
} }
if (table->vfield) if (table->vfield)
{ {
info->vblobs0.make_orphans();
table->move_fields(table->field, table->record[1], table->record[0]); table->move_fields(table->field, table->record[1], table->record[0]);
table->update_virtual_fields(VCOL_UPDATE_INDEXED); table->update_virtual_fields(VCOL_UPDATE_INDEXED);
info->vblobs1.make_orphans();
table->move_fields(table->field, table->record[0], table->record[1]); table->move_fields(table->field, table->record[0], table->record[1]);
info->vblobs0.adopt_orphans();
} }
if (info->handle_duplicates == DUP_UPDATE) if (info->handle_duplicates == DUP_UPDATE)
{ {
...@@ -1861,7 +1854,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1861,7 +1854,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
trg_error= 1; trg_error= 1;
goto ok_or_after_trg_err; goto ok_or_after_trg_err;
} }
info->vblobs1.free_orphans();
/* Let us attempt do write_row() once more */ /* Let us attempt do write_row() once more */
} }
} }
...@@ -1912,7 +1904,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1912,7 +1904,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
my_safe_afree(key,table->s->max_unique_length); my_safe_afree(key,table->s->max_unique_length);
if (!table->file->has_transactions()) if (!table->file->has_transactions())
thd->transaction.stmt.modified_non_trans_table= TRUE; thd->transaction.stmt.modified_non_trans_table= TRUE;
info->vblobs1.free_orphans();
DBUG_RETURN(trg_error); DBUG_RETURN(trg_error);
err: err:
...@@ -1924,7 +1915,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1924,7 +1915,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (key) if (key)
my_safe_afree(key, table->s->max_unique_length); my_safe_afree(key, table->s->max_unique_length);
table->column_bitmaps_set(save_read_set, save_write_set); table->column_bitmaps_set(save_read_set, save_write_set);
info->vblobs1.free_orphans();
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -3106,14 +3096,10 @@ static void free_delayed_insert_blobs(register TABLE *table) ...@@ -3106,14 +3096,10 @@ static void free_delayed_insert_blobs(register TABLE *table)
{ {
for (Field **ptr=table->field ; *ptr ; ptr++) for (Field **ptr=table->field ; *ptr ; ptr++)
{ {
Field_blob *f= (Field_blob*)(*ptr); if ((*ptr)->flags & BLOB_FLAG)
if (f->flags & BLOB_FLAG)
{ {
if (f->vcol_info) my_free(((Field_blob *) (*ptr))->get_ptr());
f->free(); ((Field_blob *) (*ptr))->reset();
else
my_free(f->get_ptr());
f->reset();
} }
} }
} }
...@@ -3135,9 +3121,6 @@ bool Delayed_insert::handle_inserts(void) ...@@ -3135,9 +3121,6 @@ bool Delayed_insert::handle_inserts(void)
table->next_number_field=table->found_next_number_field; table->next_number_field=table->found_next_number_field;
table->use_all_columns(); table->use_all_columns();
info.vblobs0.init(table);
info.vblobs1.init(table);
THD_STAGE_INFO(&thd, stage_upgrading_lock); THD_STAGE_INFO(&thd, stage_upgrading_lock);
if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock, if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock,
thd.variables.lock_wait_timeout)) thd.variables.lock_wait_timeout))
...@@ -3244,8 +3227,6 @@ bool Delayed_insert::handle_inserts(void) ...@@ -3244,8 +3227,6 @@ bool Delayed_insert::handle_inserts(void)
if (info.handle_duplicates == DUP_UPDATE) if (info.handle_duplicates == DUP_UPDATE)
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE); table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
thd.clear_error(); // reset error for binlog thd.clear_error(); // reset error for binlog
if (table->vfield)
table->update_virtual_fields(VCOL_UPDATE_FOR_WRITE);
if (write_record(&thd, table, &info)) if (write_record(&thd, table, &info))
{ {
info.error_count++; // Ignore errors info.error_count++; // Ignore errors
...@@ -3352,8 +3333,6 @@ bool Delayed_insert::handle_inserts(void) ...@@ -3352,8 +3333,6 @@ bool Delayed_insert::handle_inserts(void)
DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop")); DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop"));
goto err; goto err;
} }
info.vblobs0.free();
info.vblobs1.free();
query_cache_invalidate3(&thd, table, 1); query_cache_invalidate3(&thd, table, 1);
mysql_mutex_lock(&mutex); mysql_mutex_lock(&mutex);
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -3362,8 +3341,6 @@ bool Delayed_insert::handle_inserts(void) ...@@ -3362,8 +3341,6 @@ bool Delayed_insert::handle_inserts(void)
#ifndef DBUG_OFF #ifndef DBUG_OFF
max_rows= 0; // For DBUG output max_rows= 0; // For DBUG output
#endif #endif
info.vblobs0.free();
info.vblobs1.free();
/* Remove all not used rows */ /* Remove all not used rows */
mysql_mutex_lock(&mutex); mysql_mutex_lock(&mutex);
while ((row=rows.get())) while ((row=rows.get()))
...@@ -3611,11 +3588,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -3611,11 +3588,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
restore_record(table,s->default_values); // Get empty record restore_record(table,s->default_values); // Get empty record
table->reset_default_fields(); table->reset_default_fields();
table->next_number_field=table->found_next_number_field; table->next_number_field=table->found_next_number_field;
if (info.handle_duplicates != DUP_ERROR)
{
info.vblobs0.init(table);
info.vblobs1.init(table);
}
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
if (thd->rgi_slave && if (thd->rgi_slave &&
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
/* Instead of including sql_lex.h we add this typedef here */ /* Instead of including sql_lex.h we add this typedef here */
typedef List<Item> List_item; typedef List<Item> List_item;
typedef struct st_copy_info COPY_INFO;
bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values, List<Item> &fields, List_item *values,
......
...@@ -537,12 +537,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -537,12 +537,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
!(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))) !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
? (*escaped)[0] : INT_MAX; ? (*escaped)[0] : INT_MAX;
if (handle_duplicates != DUP_ERROR)
{
info.vblobs0.init(table);
info.vblobs1.init(table);
}
READ_INFO read_info(thd, file, tot_length, READ_INFO read_info(thd, file, tot_length,
ex->cs ? ex->cs : thd->variables.collation_database, ex->cs ? ex->cs : thd->variables.collation_database,
*field_term,*ex->line_start, *ex->line_term, *enclosed, *field_term,*ex->line_start, *ex->line_term, *enclosed,
......
...@@ -273,7 +273,6 @@ int mysql_update(THD *thd, ...@@ -273,7 +273,6 @@ int mysql_update(THD *thd,
SORT_INFO *file_sort= 0; SORT_INFO *file_sort= 0;
READ_RECORD info; READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
BLOB_VALUE_ORPHANAGE vblobs;
ulonglong id; ulonglong id;
List<Item> all_fields; List<Item> all_fields;
killed_state killed_status= NOT_KILLED; killed_state killed_status= NOT_KILLED;
...@@ -725,8 +724,6 @@ int mysql_update(THD *thd, ...@@ -725,8 +724,6 @@ int mysql_update(THD *thd,
table->reset_default_fields(); table->reset_default_fields();
vblobs.init(table);
/* /*
We can use compare_record() to optimize away updates if We can use compare_record() to optimize away updates if
the table handler is returning all columns OR if the table handler is returning all columns OR if
...@@ -748,9 +745,6 @@ int mysql_update(THD *thd, ...@@ -748,9 +745,6 @@ int mysql_update(THD *thd,
explain->tracker.on_record_after_where(); explain->tracker.on_record_after_where();
store_record(table,record[1]); store_record(table,record[1]);
vblobs.make_orphans();
if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0, if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0,
TRG_EVENT_UPDATE)) TRG_EVENT_UPDATE))
break; /* purecov: inspected */ break; /* purecov: inspected */
...@@ -910,9 +904,7 @@ int mysql_update(THD *thd, ...@@ -910,9 +904,7 @@ int mysql_update(THD *thd,
error= 1; error= 1;
break; break;
} }
vblobs.free_orphans();
} }
vblobs.free_orphans();
ANALYZE_STOP_TRACKING(&explain->command_tracker); ANALYZE_STOP_TRACKING(&explain->command_tracker);
table->auto_increment_field_not_null= FALSE; table->auto_increment_field_not_null= FALSE;
dup_key_found= 0; dup_key_found= 0;
...@@ -1760,8 +1752,6 @@ int multi_update::prepare(List<Item> &not_used_values, ...@@ -1760,8 +1752,6 @@ int multi_update::prepare(List<Item> &not_used_values,
table_count); table_count);
values_for_table= (List_item **) thd->alloc(sizeof(List_item *) * values_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
table_count); table_count);
vblobs= (BLOB_VALUE_ORPHANAGE *)thd->calloc(sizeof(*vblobs) * table_count);
if (thd->is_fatal_error) if (thd->is_fatal_error)
DBUG_RETURN(1); DBUG_RETURN(1);
for (i=0 ; i < table_count ; i++) for (i=0 ; i < table_count ; i++)
...@@ -1794,7 +1784,6 @@ int multi_update::prepare(List<Item> &not_used_values, ...@@ -1794,7 +1784,6 @@ int multi_update::prepare(List<Item> &not_used_values,
TABLE *table= ((Item_field*)(fields_for_table[i]->head()))->field->table; TABLE *table= ((Item_field*)(fields_for_table[i]->head()))->field->table;
switch_to_nullable_trigger_fields(*fields_for_table[i], table); switch_to_nullable_trigger_fields(*fields_for_table[i], table);
switch_to_nullable_trigger_fields(*values_for_table[i], table); switch_to_nullable_trigger_fields(*values_for_table[i], table);
vblobs[i].init(table);
} }
} }
copy_field= new Copy_field[max_fields]; copy_field= new Copy_field[max_fields];
...@@ -2076,8 +2065,6 @@ multi_update::~multi_update() ...@@ -2076,8 +2065,6 @@ multi_update::~multi_update()
free_tmp_table(thd, tmp_tables[cnt]); free_tmp_table(thd, tmp_tables[cnt]);
tmp_table_param[cnt].cleanup(); tmp_table_param[cnt].cleanup();
} }
vblobs[cnt].free_orphans();
vblobs[cnt].free();
} }
} }
if (copy_field) if (copy_field)
...@@ -2123,9 +2110,7 @@ int multi_update::send_data(List<Item> &not_used_values) ...@@ -2123,9 +2110,7 @@ int multi_update::send_data(List<Item> &not_used_values)
can_compare_record= records_are_comparable(table); can_compare_record= records_are_comparable(table);
table->status|= STATUS_UPDATED; table->status|= STATUS_UPDATED;
vblobs[offset].free_orphans();
store_record(table,record[1]); store_record(table,record[1]);
vblobs[offset].make_orphans();
if (fill_record_n_invoke_before_triggers(thd, table, if (fill_record_n_invoke_before_triggers(thd, table,
*fields_for_table[offset], *fields_for_table[offset],
*values_for_table[offset], 0, *values_for_table[offset], 0,
...@@ -2342,7 +2327,6 @@ int multi_update::do_updates() ...@@ -2342,7 +2327,6 @@ int multi_update::do_updates()
goto err; goto err;
} }
table->file->extra(HA_EXTRA_NO_CACHE); table->file->extra(HA_EXTRA_NO_CACHE);
empty_record(table);
check_opt_it.rewind(); check_opt_it.rewind();
while(TABLE *tbl= check_opt_it++) while(TABLE *tbl= check_opt_it++)
...@@ -2416,9 +2400,7 @@ int multi_update::do_updates() ...@@ -2416,9 +2400,7 @@ int multi_update::do_updates()
goto err2; goto err2;
table->status|= STATUS_UPDATED; table->status|= STATUS_UPDATED;
vblobs[offset].free_orphans();
store_record(table,record[1]); store_record(table,record[1]);
vblobs[offset].make_orphans();
/* Copy data from temporary table to current table */ /* Copy data from temporary table to current table */
for (copy_field_ptr=copy_field; for (copy_field_ptr=copy_field;
......
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