summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <kostja@bodhi.local>2006-07-08 21:45:02 +0400
committerunknown <kostja@bodhi.local>2006-07-08 21:45:02 +0400
commitcad24c097ebc348c1dcb1dd888a0fb89a3844cde (patch)
treeb6199047edbf5520736ded4cb1c19af19d49a477 /sql
parente1f3149c1685a9e186d67bc2f8024570ab1edb48 (diff)
parente6f010b63eb9d846810bff75352fa9aa5424426f (diff)
downloadmariadb-git-cad24c097ebc348c1dcb1dd888a0fb89a3844cde.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into bodhi.local:/opt/local/work/mysql-5.0-runtime-merge-41 myisam/mi_create.c: Auto merged mysql-test/r/myisam.result: Auto merged mysql-test/t/myisam.test: Auto merged sql/item_timefunc.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_trigger.cc: Auto merged support-files/mysql.spec.sh: Auto merged mysql-test/r/federated.result: Manual merge. mysql-test/t/federated.test: Manual merge.
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc31
-rw-r--r--sql/field.h7
-rw-r--r--sql/ha_federated.cc44
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_insert.cc79
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_trigger.cc3
-rw-r--r--sql/table.cc3
8 files changed, 111 insertions, 67 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 7c25e4ad9f7..946351efe36 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1515,7 +1515,8 @@ bool Field::optimize_range(uint idx, uint part)
}
-Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table)
+Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
+ bool keep_type __attribute__((unused)))
{
Field *tmp;
if (!(tmp= (Field*) memdup_root(root,(char*) this,size_of())))
@@ -1540,7 +1541,7 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
uint new_null_bit)
{
Field *tmp;
- if ((tmp= new_field(root, new_table)))
+ if ((tmp= new_field(root, new_table, table == new_table)))
{
tmp->ptr= new_ptr;
tmp->null_ptr= new_null_ptr;
@@ -6227,29 +6228,21 @@ uint Field_string::max_packed_col_length(uint max_length)
}
-Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table)
+Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
+ bool keep_type)
{
Field *new_field;
- if (type() != MYSQL_TYPE_VAR_STRING || table == new_table)
- return Field::new_field(root, new_table);
+ if (type() != MYSQL_TYPE_VAR_STRING || keep_type)
+ return Field::new_field(root, new_table, keep_type);
/*
Old VARCHAR field which should be modified to a VARCHAR on copy
This is done to ensure that ALTER TABLE will convert old VARCHAR fields
to now VARCHAR fields.
*/
- if ((new_field= new Field_varstring(field_length, maybe_null(),
- field_name, new_table, charset())))
- {
- /*
- delayed_insert::get_local_table() needs a ptr copied from old table.
- This is what other new_field() methods do too. The above method of
- Field_varstring sets ptr to NULL.
- */
- new_field->ptr= ptr;
- }
- return new_field;
+ return new Field_varstring(field_length, maybe_null(),
+ field_name, new_table, charset());
}
/****************************************************************************
@@ -6741,9 +6734,11 @@ int Field_varstring::cmp_binary(const char *a_ptr, const char *b_ptr,
}
-Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table)
+Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
+ bool keep_type)
{
- Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table);
+ Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table,
+ keep_type);
if (res)
res->length_bytes= length_bytes;
return res;
diff --git a/sql/field.h b/sql/field.h
index ed13372df71..3b33d3651e3 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -211,7 +211,8 @@ public:
*/
virtual bool can_be_compared_as_longlong() const { return FALSE; }
virtual void free() {}
- virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+ virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
+ bool keep_type);
virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
char *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
@@ -1033,7 +1034,7 @@ public:
enum_field_types real_type() const { return FIELD_TYPE_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
};
@@ -1105,7 +1106,7 @@ public:
enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
char *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 11f676d9cf6..e2988df1619 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -1810,19 +1810,13 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
/*
buffers for following strings
*/
- char old_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
- char new_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
+ char field_value_buffer[STRING_BUFFER_USUAL_SIZE];
char update_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char where_buffer[FEDERATED_QUERY_BUFFER_SIZE];
- /* stores the value to be replaced of the field were are updating */
- String old_field_value(old_field_value_buffer,
- sizeof(old_field_value_buffer),
- &my_charset_bin);
- /* stores the new value of the field */
- String new_field_value(new_field_value_buffer,
- sizeof(new_field_value_buffer),
- &my_charset_bin);
+ /* Work area for field values */
+ String field_value(field_value_buffer, sizeof(field_value_buffer),
+ &my_charset_bin);
/* stores the update query */
String update_string(update_buffer,
sizeof(update_buffer),
@@ -1835,8 +1829,7 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
/*
set string lengths to 0 to avoid misc chars in string
*/
- old_field_value.length(0);
- new_field_value.length(0);
+ field_value.length(0);
update_string.length(0);
where_string.length(0);
@@ -1850,8 +1843,8 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
In this loop, we want to match column names to values being inserted
(while building INSERT statement).
- Iterate through table->field (new data) and share->old_filed (old_data)
- using the same index to created an SQL UPDATE statement, new data is
+ Iterate through table->field (new data) and share->old_field (old_data)
+ using the same index to create an SQL UPDATE statement. New data is
used to create SET field=value and old data is used to create WHERE
field=oldvalue
*/
@@ -1863,30 +1856,28 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
update_string.append(FEDERATED_EQ);
if ((*field)->is_null())
- new_field_value.append(FEDERATED_NULL);
+ update_string.append(FEDERATED_NULL);
else
{
/* otherwise = */
- (*field)->val_str(&new_field_value);
- (*field)->quote_data(&new_field_value);
-
- if (!field_in_record_is_null(table, *field, (char*) old_data))
- where_string.append(FEDERATED_EQ);
+ (*field)->val_str(&field_value);
+ (*field)->quote_data(&field_value);
+ update_string.append(field_value);
+ field_value.length(0);
}
if (field_in_record_is_null(table, *field, (char*) old_data))
where_string.append(FEDERATED_ISNULL);
else
{
- (*field)->val_str(&old_field_value,
+ where_string.append(FEDERATED_EQ);
+ (*field)->val_str(&field_value,
(char*) (old_data + (*field)->offset()));
- (*field)->quote_data(&old_field_value);
- where_string.append(old_field_value);
+ (*field)->quote_data(&field_value);
+ where_string.append(field_value);
+ field_value.length(0);
}
- update_string.append(new_field_value);
- new_field_value.length(0);
-
/*
Only append conjunctions if we have another field in which
to iterate
@@ -1896,7 +1887,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
update_string.append(FEDERATED_COMMA);
where_string.append(FEDERATED_AND);
}
- old_field_value.length(0);
}
update_string.append(FEDERATED_WHERE);
update_string.append(where_string);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 41897a51bdd..5c8bd797e7c 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -931,7 +931,7 @@ bool select_send::send_data(List<Item> &items)
Protocol *protocol= thd->protocol;
char buff[MAX_FIELD_WIDTH];
String buffer(buff, sizeof(buff), &my_charset_bin);
- DBUG_ENTER("send_data");
+ DBUG_ENTER("select_send::send_data");
protocol->prepare_for_resend();
Item *item;
@@ -1141,7 +1141,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
bool select_export::send_data(List<Item> &items)
{
- DBUG_ENTER("send_data");
+ DBUG_ENTER("select_export::send_data");
char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
bool space_inited=0;
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
@@ -1298,7 +1298,7 @@ bool select_dump::send_data(List<Item> &items)
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
tmp.length(0);
Item *item;
- DBUG_ENTER("send_data");
+ DBUG_ENTER("select_dump::send_data");
if (unit->offset_limit_cnt)
{ // using limit offset,count
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index a2c967ba980..ab521e32be1 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -17,6 +17,44 @@
/* Insert of records */
+/*
+ INSERT DELAYED
+
+ Insert delayed is distinguished from a normal insert by lock_type ==
+ TL_WRITE_DELAYED instead of TL_WRITE. It first tries to open a
+ "delayed" table (delayed_get_table()), but falls back to
+ open_and_lock_tables() on error and proceeds as normal insert then.
+
+ Opening a "delayed" table means to find a delayed insert thread that
+ has the table open already. If this fails, a new thread is created and
+ waited for to open and lock the table.
+
+ If accessing the thread succeeded, in
+ delayed_insert::get_local_table() the table of the thread is copied
+ for local use. A copy is required because the normal insert logic
+ works on a target table, but the other threads table object must not
+ be used. The insert logic uses the record buffer to create a record.
+ And the delayed insert thread uses the record buffer to pass the
+ record to the table handler. So there must be different objects. Also
+ the copied table is not included in the lock, so that the statement
+ can proceed even if the real table cannot be accessed at this moment.
+
+ Copying a table object is not a trivial operation. Besides the TABLE
+ object there are the field pointer array, the field objects and the
+ record buffer. After copying the field objects, their pointers into
+ the record must be "moved" to point to the new record buffer.
+
+ After this setup the normal insert logic is used. Only that for
+ delayed inserts write_delayed() is called instead of write_record().
+ It inserts the rows into a queue and signals the delayed insert thread
+ instead of writing directly to the table.
+
+ The delayed insert thread awakes from the signal. It locks the table,
+ inserts the rows from the queue, unlocks the table, and waits for the
+ next signal. It does normally live until a FLUSH TABLES or SHUTDOWN.
+
+*/
+
#include "mysql_priv.h"
#include "sp_head.h"
#include "sql_trigger.h"
@@ -1484,6 +1522,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
my_ptrdiff_t adjust_ptrs;
Field **field,**org_field, *found_next_number_field;
TABLE *copy;
+ DBUG_ENTER("delayed_insert::get_local_table");
/* First request insert thread to get a lock */
status=1;
@@ -1507,31 +1546,47 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
}
}
+ /*
+ Allocate memory for the TABLE object, the field pointers array, and
+ one record buffer of reclength size. Normally a table has three
+ record buffers of rec_buff_length size, which includes alignment
+ bytes. Since the table copy is used for creating one record only,
+ the other record buffers and alignment are unnecessary.
+ */
client_thd->proc_info="allocating local table";
copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
(table->s->fields+1)*sizeof(Field**)+
table->s->reclength);
if (!copy)
goto error;
+
+ /* Copy the TABLE object. */
*copy= *table;
copy->s= &copy->share_not_to_be_used;
// No name hashing
bzero((char*) &copy->s->name_hash,sizeof(copy->s->name_hash));
/* We don't need to change the file handler here */
- field=copy->field=(Field**) (copy+1);
- copy->record[0]=(byte*) (field+table->s->fields+1);
- memcpy((char*) copy->record[0],(char*) table->record[0],table->s->reclength);
+ /* Assign the pointers for the field pointers array and the record. */
+ field= copy->field= (Field**) (copy + 1);
+ copy->record[0]= (byte*) (field + table->s->fields + 1);
+ memcpy((char*) copy->record[0], (char*) table->record[0],
+ table->s->reclength);
- /* Make a copy of all fields */
-
- adjust_ptrs=PTR_BYTE_DIFF(copy->record[0],table->record[0]);
+ /*
+ Make a copy of all fields.
+ The copied fields need to point into the copied record. This is done
+ by copying the field objects with their old pointer values and then
+ "move" the pointers by the distance between the original and copied
+ records. That way we preserve the relative positions in the records.
+ */
+ adjust_ptrs= PTR_BYTE_DIFF(copy->record[0], table->record[0]);
- found_next_number_field=table->found_next_number_field;
- for (org_field=table->field ; *org_field ; org_field++,field++)
+ found_next_number_field= table->found_next_number_field;
+ for (org_field= table->field; *org_field; org_field++, field++)
{
- if (!(*field= (*org_field)->new_field(client_thd->mem_root,copy)))
- return 0;
+ if (!(*field= (*org_field)->new_field(client_thd->mem_root, copy, 1)))
+ DBUG_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)
@@ -1558,14 +1613,14 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
/* Adjust lock_count. This table object is not part of a lock. */
copy->lock_count= 0;
- return copy;
+ DBUG_RETURN(copy);
/* Got fatal error */
error:
tables_in_use--;
status=1;
pthread_cond_signal(&cond); // Inform thread about abort
- return 0;
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 41ff9185cfb..400342854a6 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8017,7 +8017,8 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field,
org_field->field_name, table,
org_field->charset());
else
- new_field= org_field->new_field(thd->mem_root, table);
+ new_field= org_field->new_field(thd->mem_root, table,
+ table == org_field->table);
if (new_field)
{
if (item)
@@ -13062,7 +13063,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
saved value
*/
Field *field= item->field;
- item->result_field=field->new_field(thd->mem_root,field->table);
+ item->result_field=field->new_field(thd->mem_root,field->table, 1);
char *tmp=(char*) sql_alloc(field->pack_length()+1);
if (!tmp)
goto err;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 55744631210..66a16f16d8c 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -747,7 +747,8 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
QQ: it is supposed that it is ok to use this function for field
cloning...
*/
- if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
+ if (!(*old_fld= (*fld)->new_field(&table->mem_root, table,
+ table == (*fld)->table)))
return 1;
(*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
table->record[0]));
diff --git a/sql/table.cc b/sql/table.cc
index 83711577699..728b98b2d35 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -804,7 +804,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
if (!(field->flags & BLOB_FLAG))
{ // Create a new field
field=key_part->field=field->new_field(&outparam->mem_root,
- outparam);
+ outparam,
+ outparam == field->table);
field->field_length=key_part->length;
}
}