summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2004-11-09 21:47:46 +0200
committerunknown <monty@mysql.com>2004-11-09 21:47:46 +0200
commit96bd70c7750aa2a9e39eaeb1da917f89f04173b9 (patch)
tree50aeda8eac9d7305cd0eb80d8479f992cd179e02 /sql
parent591feb1fbc3632da62620e81ac39e8a0e307aa84 (diff)
parentcd16e4c9c750a5bddfcecaa849dc277445aeaa5b (diff)
downloadmariadb-git-96bd70c7750aa2a9e39eaeb1da917f89f04173b9.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/my/mysql-5.0 BitKeeper/etc/ignore: auto-union sql/item_subselect.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_view.cc: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc19
-rw-r--r--sql/ha_berkeley.cc10
-rw-r--r--sql/ha_innodb.cc30
-rw-r--r--sql/ha_innodb.h4
-rw-r--r--sql/ha_ndbcluster.cc177
-rw-r--r--sql/ha_ndbcluster.h24
-rw-r--r--sql/item.cc137
-rw-r--r--sql/item.h29
-rw-r--r--sql/item_cmpfunc.cc98
-rw-r--r--sql/item_create.cc5
-rw-r--r--sql/item_func.cc138
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_geofunc.cc6
-rw-r--r--sql/item_strfunc.cc74
-rw-r--r--sql/item_subselect.cc35
-rw-r--r--sql/item_sum.cc32
-rw-r--r--sql/item_timefunc.cc10
-rw-r--r--sql/log_event.cc8
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/mysqld.cc11
-rw-r--r--sql/net_serv.cc12
-rw-r--r--sql/opt_range.cc53
-rw-r--r--sql/parse_file.cc26
-rw-r--r--sql/protocol.cc12
-rw-r--r--sql/protocol.h1
-rw-r--r--sql/repl_failsafe.cc2
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/sp.cc22
-rw-r--r--sql/sp_head.cc28
-rw-r--r--sql/sp_head.h2
-rw-r--r--sql/spatial.cc4
-rw-r--r--sql/sql_acl.cc10
-rw-r--r--sql/sql_base.cc31
-rw-r--r--sql/sql_class.cc24
-rw-r--r--sql/sql_class.h32
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_error.cc6
-rw-r--r--sql/sql_help.cc14
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_lex.cc7
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_list.h12
-rw-r--r--sql/sql_parse.cc40
-rw-r--r--sql/sql_prepare.cc31
-rw-r--r--sql/sql_select.cc40
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_show.cc12
-rw-r--r--sql/sql_string.cc28
-rw-r--r--sql/sql_string.h4
-rw-r--r--sql/sql_table.cc22
-rw-r--r--sql/sql_trigger.cc22
-rw-r--r--sql/sql_union.cc17
-rw-r--r--sql/sql_view.cc8
-rw-r--r--sql/sql_yacc.yy18
-rw-r--r--sql/table.cc15
-rw-r--r--sql/thr_malloc.cc7
56 files changed, 869 insertions, 562 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 7a8f59c25fe..1275e1bbb8e 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -547,7 +547,8 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
/* Convert character set if the old one is multi byte */
if (cs->mbmaxlen > 1)
{
- tmp.copy(from, len, cs, &my_charset_bin);
+ uint dummy_errors;
+ tmp.copy(from, len, cs, &my_charset_bin, &dummy_errors);
from= tmp.ptr();
len= tmp.length();
}
@@ -4444,6 +4445,7 @@ void Field_string::sort_string(char *to,uint length)
void Field_string::sql_type(String &res) const
{
+ THD *thd= table->in_use;
CHARSET_INFO *cs=res.charset();
ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
res.alloced_length(), "%s(%d)",
@@ -4454,6 +4456,9 @@ void Field_string::sql_type(String &res) const
(has_charset() ? "char" : "binary")),
(int) field_length / charset()->mbmaxlen);
res.length(length);
+ if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
+ has_charset() && (charset()->state & MY_CS_BINSORT))
+ res.append(" binary");
}
char *Field_string::pack(char *to, const char *from, uint max_length)
@@ -5530,7 +5535,8 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
/* Convert character set if nesessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
- tmpstr.copy(from, length, cs, field_charset);
+ uint dummy_errors;
+ tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
from= tmpstr.ptr();
length= tmpstr.length();
}
@@ -5678,10 +5684,11 @@ void Field_enum::sql_type(String &res) const
bool flag=0;
for (const char **pos= typelib->type_names; *pos; pos++)
{
+ uint dummy_errors;
if (flag)
res.append(',');
/* convert to res.charset() == utf8, then quote */
- enum_item.copy(*pos, strlen(*pos), charset(), res.charset());
+ enum_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors);
append_unescaped(&res, enum_item.ptr(), enum_item.length());
flag= 1;
}
@@ -5712,7 +5719,8 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
/* Convert character set if nesessary */
if (String::needs_conversion(length, cs, field_charset, &not_used_offset))
{
- tmpstr.copy(from, length, cs, field_charset);
+ uint dummy_errors;
+ tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
from= tmpstr.ptr();
length= tmpstr.length();
}
@@ -5788,10 +5796,11 @@ void Field_set::sql_type(String &res) const
bool flag=0;
for (const char **pos= typelib->type_names; *pos; pos++)
{
+ uint dummy_errors;
if (flag)
res.append(',');
/* convert to res.charset() == utf8, then quote */
- set_item.copy(*pos, strlen(*pos), charset(), res.charset());
+ set_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors);
append_unescaped(&res, set_item.ptr(), set_item.length());
flag= 1;
}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index a5d0023b875..ff6b10fe504 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -234,13 +234,13 @@ int berkeley_show_logs(Protocol *protocol)
{
char **all_logs, **free_logs, **a, **f;
int error=1;
- MEM_ROOT show_logs_root;
- MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ MEM_ROOT **root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,THR_MALLOC);
+ MEM_ROOT show_logs_root, *old_mem_root= *root_ptr;
DBUG_ENTER("berkeley_show_logs");
init_sql_alloc(&show_logs_root, BDB_LOG_ALLOC_BLOCK_SIZE,
BDB_LOG_ALLOC_BLOCK_SIZE);
- my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root);
+ *root_ptr= &show_logs_root;
if ((error= db_env->log_archive(db_env, &all_logs,
DB_ARCH_ABS | DB_ARCH_LOG)) ||
@@ -277,15 +277,17 @@ int berkeley_show_logs(Protocol *protocol)
}
err:
free_root(&show_logs_root,MYF(0));
- my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ *root_ptr= old_mem_root;
DBUG_RETURN(error);
}
+
static void berkeley_print_error(const char *db_errpfx, char *buffer)
{
sql_print_error("%s: %s",db_errpfx,buffer); /* purecov: tested */
}
+
static void berkeley_noticecall(DB_ENV *db_env, db_notices notice)
{
switch (notice)
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 722a6259d3d..370458c6e01 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2318,6 +2318,34 @@ ha_innobase::write_row(
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
+ if (user_thd->lex->sql_command == SQLCOM_ALTER_TABLE
+ && num_write_row >= 10000) {
+ /* ALTER TABLE is COMMITted at every 10000 copied rows.
+ The IX table lock for the original table has to be re-issued.
+ As this method will be called on a temporary table where the
+ contents of the original table is being copied to, it is
+ a bit tricky to determine the source table. The cursor
+ position in the source table need not be adjusted after the
+ intermediate COMMIT, since writes by other transactions are
+ being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
+ ut_a(prebuilt->trx->mysql_n_tables_locked == 2);
+ ut_a(UT_LIST_GET_LEN(prebuilt->trx->trx_locks) >= 2);
+ dict_table_t* table = lock_get_ix_table(
+ UT_LIST_GET_FIRST(prebuilt->trx->trx_locks));
+ num_write_row = 0;
+ /* Commit the transaction. This will release the table
+ locks, so they have to be acquired again. */
+ innobase_commit(user_thd, prebuilt->trx);
+ /* Note that this transaction is still active. */
+ user_thd->transaction.all.innodb_active_trans = 1;
+ /* Re-acquire the IX table lock on the source table. */
+ row_lock_table_for_mysql(prebuilt, table);
+ /* We will need an IX lock on the destination table. */
+ prebuilt->sql_stat_start = TRUE;
+ }
+
+ num_write_row++;
+
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
last_query_id = user_thd->query_id;
@@ -4939,7 +4967,7 @@ ha_innobase::external_lock(
if (thd->in_lock_tables &&
thd->variables.innodb_table_locks) {
ulint error;
- error = row_lock_table_for_mysql(prebuilt);
+ error = row_lock_table_for_mysql(prebuilt, 0);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index b74af1db90b..7e337afed0e 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -64,6 +64,7 @@ class ha_innobase: public handler
uint last_match_mode;/* match mode of the latest search:
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
or undefined */
+ uint num_write_row; /* number of write_row() calls */
longlong auto_inc_counter_for_this_stat;
ulong max_supported_row_length(const byte *buf);
@@ -85,7 +86,8 @@ class ha_innobase: public handler
HA_PRIMARY_KEY_IN_READ_INDEX |
HA_TABLE_SCAN_ON_INDEX),
last_dup_key((uint) -1),
- start_of_scan(0)
+ start_of_scan(0),
+ num_write_row(0)
{
}
~ha_innobase() {}
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 7878684718c..b2e115e9779 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -324,7 +324,7 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans)
DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
err.code, res));
if (res == HA_ERR_FOUND_DUPP_KEY)
- dupkey= table->primary_key;
+ m_dupkey= table->primary_key;
DBUG_RETURN(res);
}
@@ -551,7 +551,7 @@ int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob)
blob_size+= 8 - blob_size % 8;
if (loop == 1)
{
- char *buf= blobs_buffer + offset;
+ char *buf= m_blobs_buffer + offset;
uint32 len= 0xffffffff; // Max uint32
DBUG_PRINT("value", ("read blob ptr=%x len=%u",
(uint)buf, (uint)blob_len));
@@ -563,15 +563,15 @@ int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob)
offset+= blob_size;
}
}
- if (loop == 0 && offset > blobs_buffer_size)
+ if (loop == 0 && offset > m_blobs_buffer_size)
{
- my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
- blobs_buffer_size= 0;
+ my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ m_blobs_buffer_size= 0;
DBUG_PRINT("value", ("allocate blobs buffer size %u", offset));
- blobs_buffer= my_malloc(offset, MYF(MY_WME));
- if (blobs_buffer == NULL)
+ m_blobs_buffer= my_malloc(offset, MYF(MY_WME));
+ if (m_blobs_buffer == NULL)
DBUG_RETURN(-1);
- blobs_buffer_size= offset;
+ m_blobs_buffer_size= offset;
}
}
DBUG_RETURN(0);
@@ -854,7 +854,7 @@ int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type)
{
if (type >= TL_WRITE_ALLOW_WRITE)
return NdbOperation::LM_Exclusive;
- else if (uses_blob_value(retrieve_all_fields))
+ else if (uses_blob_value(m_retrieve_all_fields))
return NdbOperation::LM_Read;
else
return NdbOperation::LM_CommittedRead;
@@ -1018,7 +1018,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
{
Field *field= table->field[i];
if ((thd->query_id == field->query_id) ||
- retrieve_all_fields)
+ m_retrieve_all_fields)
{
if (get_ndb_value(op, field, i, buf))
ERR_RETURN(trans->getNdbError());
@@ -1055,7 +1055,7 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
THD *thd= current_thd;
DBUG_ENTER("complemented_pk_read");
- if (retrieve_all_fields)
+ if (m_retrieve_all_fields)
// We have allready retrieved all fields, nothing to complement
DBUG_RETURN(0);
@@ -1192,12 +1192,12 @@ inline int ha_ndbcluster::next_result(byte *buf)
/*
We can only handle one tuple with blobs at a time.
*/
- if (ops_pending && blobs_pending)
+ if (m_ops_pending && m_blobs_pending)
{
if (execute_no_commit(this,trans) != 0)
DBUG_RETURN(ndb_err(trans));
- ops_pending= 0;
- blobs_pending= FALSE;
+ m_ops_pending= 0;
+ m_blobs_pending= FALSE;
}
check= cursor->nextResult(contact_ndb);
if (check == 0)
@@ -1219,8 +1219,8 @@ inline int ha_ndbcluster::next_result(byte *buf)
all pending update or delete operations should
be sent to NDB
*/
- DBUG_PRINT("info", ("ops_pending: %d", ops_pending));
- if (ops_pending)
+ DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending));
+ if (m_ops_pending)
{
if (current_thd->transaction.on)
{
@@ -1234,7 +1234,7 @@ inline int ha_ndbcluster::next_result(byte *buf)
int res= trans->restart();
DBUG_ASSERT(res == 0);
}
- ops_pending= 0;
+ m_ops_pending= 0;
}
contact_ndb= (check == 2);
@@ -1393,8 +1393,13 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
// Set bound if not cancelled via type -1
if (p.bound_type != -1)
- if (op->setBound(field->field_name, p.bound_type, p.bound_ptr))
+ {
+ char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE];
+ strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name));
+ truncated_field_name[sizeof(truncated_field_name)-1]= '\0';
+ if (op->setBound(truncated_field_name, p.bound_type, p.bound_ptr))
ERR_RETURN(op->getNdbError());
+ }
}
}
@@ -1418,7 +1423,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
Field *field= table->field[i];
if ((thd->query_id == field->query_id) ||
(field->flags & PRI_KEY_FLAG) ||
- retrieve_all_fields)
+ m_retrieve_all_fields)
{
if (get_ndb_value(op, field, i, buf))
ERR_RETURN(op->getNdbError());
@@ -1663,9 +1668,9 @@ int ha_ndbcluster::write_row(byte *record)
if (has_auto_increment)
{
- skip_auto_increment= FALSE;
+ m_skip_auto_increment= FALSE;
update_auto_increment();
- skip_auto_increment= !auto_increment_column_changed;
+ m_skip_auto_increment= !auto_increment_column_changed;
}
if ((res= set_primary_key(op)))
@@ -1680,7 +1685,7 @@ int ha_ndbcluster::write_row(byte *record)
if (!(field->flags & PRI_KEY_FLAG) &&
set_ndb_value(op, field, i, &set_blob_value))
{
- skip_auto_increment= TRUE;
+ m_skip_auto_increment= TRUE;
ERR_RETURN(op->getNdbError());
}
}
@@ -1692,25 +1697,25 @@ int ha_ndbcluster::write_row(byte *record)
to NoCommit the transaction between each row.
Find out how this is detected!
*/
- rows_inserted++;
+ m_rows_inserted++;
no_uncommitted_rows_update(1);
- bulk_insert_not_flushed= TRUE;
- if ((rows_to_insert == 1) ||
- ((rows_inserted % bulk_insert_rows) == 0) ||
+ m_bulk_insert_not_flushed= TRUE;
+ if ((m_rows_to_insert == 1) ||
+ ((m_rows_inserted % m_bulk_insert_rows) == 0) ||
set_blob_value)
{
THD *thd= current_thd;
// Send rows to NDB
DBUG_PRINT("info", ("Sending inserts to NDB, "\
"rows_inserted:%d, bulk_insert_rows: %d",
- (int)rows_inserted, (int)bulk_insert_rows));
+ (int)m_rows_inserted, (int)m_bulk_insert_rows));
- bulk_insert_not_flushed= FALSE;
+ m_bulk_insert_not_flushed= FALSE;
if (thd->transaction.on)
{
if (execute_no_commit(this,trans) != 0)
{
- skip_auto_increment= TRUE;
+ m_skip_auto_increment= TRUE;
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -1719,7 +1724,7 @@ int ha_ndbcluster::write_row(byte *record)
{
if (execute_commit(this,trans) != 0)
{
- skip_auto_increment= TRUE;
+ m_skip_auto_increment= TRUE;
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -1727,7 +1732,7 @@ int ha_ndbcluster::write_row(byte *record)
DBUG_ASSERT(res == 0);
}
}
- if ((has_auto_increment) && (skip_auto_increment))
+ if ((has_auto_increment) && (m_skip_auto_increment))
{
Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
DBUG_PRINT("info",
@@ -1737,7 +1742,7 @@ int ha_ndbcluster::write_row(byte *record)
DBUG_PRINT("info",
("Setting next auto increment value to %u", next_val));
}
- skip_auto_increment= TRUE;
+ m_skip_auto_increment= TRUE;
DBUG_RETURN(0);
}
@@ -1817,7 +1822,9 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
}
// Delete old row
DBUG_PRINT("info", ("insert succeded"));
+ m_primary_key_update= TRUE;
delete_res= delete_row(old_data);
+ m_primary_key_update= FALSE;
if (delete_res)
{
DBUG_PRINT("info", ("delete failed"));
@@ -1840,9 +1847,9 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_PRINT("info", ("Calling updateTuple on cursor"));
if (!(op= cursor->updateTuple()))
ERR_RETURN(trans->getNdbError());
- ops_pending++;
+ m_ops_pending++;
if (uses_blob_value(FALSE))
- blobs_pending= TRUE;
+ m_blobs_pending= TRUE;
}
else
{
@@ -1919,7 +1926,7 @@ int ha_ndbcluster::delete_row(const byte *record)
DBUG_PRINT("info", ("Calling deleteTuple on cursor"));
if (cursor->deleteTuple() != 0)
ERR_RETURN(trans->getNdbError());
- ops_pending++;
+ m_ops_pending++;
no_uncommitted_rows_update(-1);
@@ -1949,8 +1956,10 @@ int ha_ndbcluster::delete_row(const byte *record)
else
{
int res;
- if ((res= set_primary_key(op)))
- return res;
+ if ((res= (m_primary_key_update ?
+ set_primary_key_from_old_data(op, record)
+ : set_primary_key(op))))
+ return res;
}
}
@@ -2412,18 +2421,18 @@ int ha_ndbcluster::close_scan()
DBUG_RETURN(1);
- if (ops_pending)
+ if (m_ops_pending)
{
/*
Take over any pending transactions to the
deleteing/updating transaction before closing the scan
*/
- DBUG_PRINT("info", ("ops_pending: %d", ops_pending));
+ DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending));
if (execute_no_commit(this,trans) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
- ops_pending= 0;
+ m_ops_pending= 0;
}
cursor->close();
@@ -2558,7 +2567,7 @@ void ha_ndbcluster::info(uint flag)
if (flag & HA_STATUS_ERRKEY)
{
DBUG_PRINT("info", ("HA_STATUS_ERRKEY"));
- errkey= dupkey;
+ errkey= m_dupkey;
}
if (flag & HA_STATUS_AUTO)
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
@@ -2653,7 +2662,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
m_use_write= TRUE;
} else
{
- m_ignore_dup_key_not_supported= TRUE;
+ if (table->keys)
+ m_ignore_dup_key_not_supported= TRUE;
}
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
@@ -2666,7 +2676,7 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
where field->query_id is the same as
the current query id */
DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_ALL_COLS"));
- retrieve_all_fields= TRUE;
+ m_retrieve_all_fields= TRUE;
break;
case HA_EXTRA_PREPARE_FOR_DELETE:
DBUG_PRINT("info", ("HA_EXTRA_PREPARE_FOR_DELETE"));
@@ -2712,8 +2722,8 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
DBUG_ENTER("start_bulk_insert");
DBUG_PRINT("enter", ("rows: %d", (int)rows));
- rows_inserted= 0;
- rows_to_insert= rows;
+ m_rows_inserted= 0;
+ m_rows_to_insert= rows;
/*
Calculate how many rows that should be inserted
@@ -2727,7 +2737,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
batch= bytesperbatch/bytes;
batch= batch == 0 ? 1 : batch;
DBUG_PRINT("info", ("batch: %d, bytes: %d", batch, bytes));
- bulk_insert_rows= batch;
+ m_bulk_insert_rows= batch;
DBUG_VOID_RETURN;
}
@@ -2741,22 +2751,22 @@ int ha_ndbcluster::end_bulk_insert()
DBUG_ENTER("end_bulk_insert");
// Check if last inserts need to be flushed
- if (bulk_insert_not_flushed)
+ if (m_bulk_insert_not_flushed)
{
NdbConnection *trans= m_active_trans;
// Send rows to NDB
DBUG_PRINT("info", ("Sending inserts to NDB, "\
"rows_inserted:%d, bulk_insert_rows: %d",
- rows_inserted, bulk_insert_rows));
- bulk_insert_not_flushed= FALSE;
+ m_rows_inserted, m_bulk_insert_rows));
+ m_bulk_insert_not_flushed= FALSE;
if (execute_no_commit(this,trans) != 0) {
no_uncommitted_rows_execute_failure();
my_errno= error= ndb_err(trans);
}
}
- rows_inserted= 0;
- rows_to_insert= 1;
+ m_rows_inserted= 0;
+ m_rows_to_insert= 1;
DBUG_RETURN(error);
}
@@ -2942,8 +2952,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
(NdbConnection*)thd->transaction.stmt.ndb_tid;
DBUG_ASSERT(m_active_trans);
// Start of transaction
- retrieve_all_fields= FALSE;
- ops_pending= 0;
+ m_retrieve_all_fields= FALSE;
+ m_ops_pending= 0;
{
NDBDICT *dict= m_ndb->getDictionary();
const NDBTAB *tab;
@@ -2991,13 +3001,13 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
DBUG_PRINT("warning", ("m_active_cursor != NULL"));
m_active_cursor= NULL;
- if (blobs_pending)
+ if (m_blobs_pending)
DBUG_PRINT("warning", ("blobs_pending != 0"));
- blobs_pending= 0;
+ m_blobs_pending= 0;
- if (ops_pending)
+ if (m_ops_pending)
DBUG_PRINT("warning", ("ops_pending != 0L"));
- ops_pending= 0;
+ m_ops_pending= 0;
}
DBUG_RETURN(error);
}
@@ -3034,8 +3044,8 @@ int ha_ndbcluster::start_stmt(THD *thd)
m_active_trans= trans;
// Start of statement
- retrieve_all_fields= FALSE;
- ops_pending= 0;
+ m_retrieve_all_fields= FALSE;
+ m_ops_pending= 0;
DBUG_RETURN(error);
}
@@ -3112,7 +3122,12 @@ static int create_ndb_column(NDBCOL &col,
HA_CREATE_INFO *info)
{
// Set name
- col.setName(field->field_name);
+ {
+ char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE];
+ strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name));
+ truncated_field_name[sizeof(truncated_field_name)-1]= '\0';
+ col.setName(truncated_field_name);
+ }
// Get char set
CHARSET_INFO *cs= field->charset();
// Set type and sizes
@@ -3440,7 +3455,12 @@ int ha_ndbcluster::create_index(const char *name,
{
Field *field= key_part->field;
DBUG_PRINT("info", ("attr: %s", field->field_name));
- ndb_index.addColumnName(field->field_name);
+ {
+ char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE];
+ strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name));
+ truncated_field_name[sizeof(truncated_field_name)-1]= '\0';
+ ndb_index.addColumnName(truncated_field_name);
+ }
}
if (dict->createIndex(ndb_index))
@@ -3567,10 +3587,10 @@ ulonglong ha_ndbcluster::get_auto_increment()
Uint64 auto_value;
DBUG_ENTER("get_auto_increment");
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
- cache_size= ((rows_to_insert - rows_inserted < autoincrement_prefetch) ?
- rows_to_insert - rows_inserted :
- max(rows_to_insert, autoincrement_prefetch));
- auto_value= ((skip_auto_increment) ?
+ cache_size= ((m_rows_to_insert - m_rows_inserted < autoincrement_prefetch) ?
+ m_rows_to_insert - m_rows_inserted :
+ max(m_rows_to_insert, autoincrement_prefetch));
+ auto_value= ((m_skip_auto_increment) ?
m_ndb->readAutoIncrementValue((const NDBTAB *) m_table) :
m_ndb->getAutoIncrementValue((const NDBTAB *) m_table, cache_size));
DBUG_RETURN((ulonglong) auto_value);
@@ -3595,17 +3615,18 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
m_share(0),
m_use_write(FALSE),
m_ignore_dup_key_not_supported(FALSE),
- retrieve_all_fields(FALSE),
- rows_to_insert(1),
- rows_inserted(0),
- bulk_insert_rows(1024),
- bulk_insert_not_flushed(FALSE),
- ops_pending(0),
- skip_auto_increment(TRUE),
- blobs_pending(0),
- blobs_buffer(0),
- blobs_buffer_size(0),
- dupkey((uint) -1)
+ m_primary_key_update(FALSE),
+ m_retrieve_all_fields(FALSE),
+ m_rows_to_insert(1),
+ m_rows_inserted(0),
+ m_bulk_insert_rows(1024),
+ m_bulk_insert_not_flushed(FALSE),
+ m_ops_pending(0),
+ m_skip_auto_increment(TRUE),
+ m_blobs_pending(0),
+ m_blobs_buffer(0),
+ m_blobs_buffer_size(0),
+ m_dupkey((uint) -1)
{
int i;
@@ -3639,8 +3660,8 @@ ha_ndbcluster::~ha_ndbcluster()
if (m_share)
free_share(m_share);
release_metadata();
- my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
- blobs_buffer= 0;
+ my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ m_blobs_buffer= 0;
// Check for open cursor/transaction
if (m_active_cursor) {
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 245d906c5ae..d61876b1357 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -26,7 +26,6 @@
#endif
#include <ndbapi_limits.h>
-#include <ndb_types.h>
class Ndb; // Forward declaration
class NdbOperation; // Forward declaration
@@ -244,18 +243,19 @@ class ha_ndbcluster: public handler
NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
bool m_use_write;
bool m_ignore_dup_key_not_supported;
- bool retrieve_all_fields;
- ha_rows rows_to_insert;
- ha_rows rows_inserted;
- ha_rows bulk_insert_rows;
- bool bulk_insert_not_flushed;
- ha_rows ops_pending;
- bool skip_auto_increment;
- bool blobs_pending;
+ bool m_primary_key_update;
+ bool m_retrieve_all_fields;
+ ha_rows m_rows_to_insert;
+ ha_rows m_rows_inserted;
+ ha_rows m_bulk_insert_rows;
+ bool m_bulk_insert_not_flushed;
+ ha_rows m_ops_pending;
+ bool m_skip_auto_increment;
+ bool m_blobs_pending;
// memory for blobs in one tuple
- char *blobs_buffer;
- uint32 blobs_buffer_size;
- uint dupkey;
+ char *m_blobs_buffer;
+ uint32 m_blobs_buffer_size;
+ uint m_dupkey;
void set_rec_per_key();
void records_update();
diff --git a/sql/item.cc b/sql/item.cc
index 4c738c9a4c5..d78c6f5b8ba 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -278,6 +278,41 @@ bool Item::eq(const Item *item, bool binary_cmp) const
}
+Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ /*
+ Don't allow automatic conversion to non-Unicode charsets,
+ as it potentially loses data.
+ */
+ if (!(tocs->state & MY_CS_UNICODE))
+ return NULL; // safe conversion is not possible
+ return new Item_func_conv_charset(this, tocs);
+}
+
+
+Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ uint conv_errors;
+ String tmp, cstr, *ostr= val_str(&tmp);
+ cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
+ if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
+ {
+ /*
+ Safe conversion is not possible (or EOM).
+ We could not convert a string into the requested character set
+ without data loss. The target charset does not cover all the
+ characters from the string. Operation cannot be done correctly.
+ */
+ return NULL;
+ }
+ conv->str_value.copy();
+ return conv;
+}
+
+
bool Item_string::eq(const Item *item, bool binary_cmp) const
{
if (type() == item->type())
@@ -372,7 +407,43 @@ Item_splocal::type() const
}
-bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion)
+
+/*
+ Aggregate two collations together taking
+ into account their coercibility (aka derivation):
+
+ 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause
+ 1 == DERIVATION_NONE - a mix of two different collations
+ 2 == DERIVATION_IMPLICIT - a column
+ 3 == DERIVATION_COERCIBLE - a string constant
+
+ The most important rules are:
+
+ 1. If collations are the same:
+ chose this collation, and the strongest derivation.
+
+ 2. If collations are different:
+ - Character sets may differ, but only if conversion without
+ data loss is possible. The caller provides flags whether
+ character set conversion attempts should be done. If no
+ flags are substituted, then the character sets must be the same.
+ Currently processed flags are:
+ MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset
+ MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
+ - two EXPLICIT collations produce an error, e.g. this is wrong:
+ CONCAT(expr1 collate latin1_swedish_ci, expr2 collate latin1_german_ci)
+ - the side with smaller derivation value wins,
+ i.e. a column is stronger than a string constant,
+ an explicit COLLATE clause is stronger than a column.
+ - if derivations are the same, we have DERIVATION_NONE,
+ we'll wait for an explicit COLLATE clause which possibly can
+ come from another argument later: for example, this is valid,
+ but we don't know yet when collecting the first two arguments:
+ CONCAT(latin1_swedish_ci_column,
+ latin1_german1_ci_column,
+ expr COLLATE latin1_german2_ci)
+*/
+bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
nagg++;
if (!my_charset_same(collation, dt.collation))
@@ -403,28 +474,37 @@ bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion)
else
; // Do nothing
}
- else if (superset_conversion)
+ else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
+ derivation < dt.derivation &&
+ collation->state & MY_CS_UNICODE)
{
- if (derivation < dt.derivation &&
- collation->state & MY_CS_UNICODE)
- ; // Do nothing
- else if (dt.derivation < derivation &&
- dt.collation->state & MY_CS_UNICODE)
- {
- set(dt);
- strong= nagg;
- }
- else
- {
- // Cannot convert to superset
- set(0, DERIVATION_NONE);
- return 1;
- }
+ // Do nothing
+ }
+ else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
+ dt.derivation < derivation &&
+ dt.collation->state & MY_CS_UNICODE)
+ {
+ set(dt);
+ strong= nagg;
+ }
+ else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
+ derivation < dt.derivation &&
+ dt.derivation == DERIVATION_COERCIBLE)
+ {
+ // Do nothing;
+ }
+ else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
+ dt.derivation < derivation &&
+ derivation == DERIVATION_COERCIBLE)
+ {
+ set(dt);
+ strong= nagg;
}
else
{
+ // Cannot apply conversion
set(0, DERIVATION_NONE);
- return 1;
+ return 1;
}
}
else if (derivation < dt.derivation)
@@ -847,6 +927,12 @@ String *Item_null::val_str(String *str)
}
+Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ collation.set(tocs);
+ return this;
+}
+
/*********************** Item_param related ******************************/
/*
@@ -942,7 +1028,9 @@ bool Item_param::set_str(const char *str, ulong length)
Assign string with no conversion: data is converted only after it's
been written to the binary log.
*/
- if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin))
+ uint dummy_errors;
+ if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin,
+ &dummy_errors))
DBUG_RETURN(TRUE);
state= STRING_VALUE;
maybe_null= 0;
@@ -1299,6 +1387,10 @@ bool Item_param::convert_str_value(THD *thd)
value.cs_info.character_set_client,
value.cs_info.final_character_set_of_str_value);
}
+ else
+ str_value.set_charset(value.cs_info.final_character_set_of_str_value);
+ /* Here str_value is guaranteed to be in final_character_set_of_str_value */
+
max_length= str_value.length();
decimals= 0;
/*
@@ -1662,6 +1754,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
+Item *Item_field::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ no_const_subst= 1;
+ return Item::safe_charset_converter(tocs);
+}
+
+
void Item_field::cleanup()
{
DBUG_ENTER("Item_field::cleanup");
diff --git a/sql/item.h b/sql/item.h
index eed0b065a83..93c396b95b0 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -38,6 +38,25 @@ enum Derivation
DERIVATION_EXPLICIT= 0
};
+/*
+ Flags for collation aggregation modes:
+ MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset
+ MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
+ (i.e. constant).
+ MY_COLL_ALLOW_CONV - allow any kind of conversion
+ (combintion of the above two)
+ MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE
+ (e.g. when aggregating for comparison)
+ MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV
+ and MY_COLL_DISALLOW_NONE
+*/
+
+#define MY_COLL_ALLOW_SUPERSET_CONV 1
+#define MY_COLL_ALLOW_COERCIBLE_CONV 2
+#define MY_COLL_ALLOW_CONV 3
+#define MY_COLL_DISALLOW_NONE 4
+#define MY_COLL_CMP_CONV 7
+
class DTCollation {
public:
CHARSET_INFO *collation;
@@ -73,9 +92,9 @@ public:
{ collation= collation_arg; }
void set(Derivation derivation_arg)
{ derivation= derivation_arg; }
- bool aggregate(DTCollation &dt, bool superset_conversion= FALSE);
- bool set(DTCollation &dt1, DTCollation &dt2, bool superset_conversion= FALSE)
- { set(dt1); return aggregate(dt2, superset_conversion); }
+ bool aggregate(DTCollation &dt, uint flags= 0);
+ bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
+ { set(dt1); return aggregate(dt2, flags); }
const char *derivation_name() const
{
switch(derivation)
@@ -306,6 +325,7 @@ public:
virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
+ virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
void delete_self()
{
cleanup();
@@ -542,6 +562,7 @@ public:
bool replace_equal_field_processor(byte *arg);
inline uint32 max_disp_length() { return field->max_length(); }
Item_field *filed_for_view_update() { return this; }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -573,6 +594,7 @@ public:
Item *new_item() { return new Item_null(name); }
bool is_null() { return 1; }
void print(String *str) { str->append("NULL", 4); }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
};
@@ -862,6 +884,7 @@ public:
return new Item_string(name, str_value.ptr(),
str_value.length(), &my_charset_bin);
}
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
String *const_string() { return &str_value; }
inline void append(char *str, uint length) { str_value.append(str, length); }
void print(String *str);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 467cd8313a4..905250ed96f 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -185,55 +185,14 @@ void Item_bool_func2::fix_length_and_dec()
to the collation of A.
*/
- if (args[0] && args[1])
- {
- uint strong= 0;
- uint weak= 0;
- uint32 dummy_offset;
- DTCollation coll;
-
- if (args[0]->result_type() == STRING_RESULT &&
- args[1]->result_type() == STRING_RESULT &&
- String::needs_conversion(0, args[0]->collation.collation,
- args[1]->collation.collation,
- &dummy_offset) &&
- !coll.set(args[0]->collation, args[1]->collation, TRUE))
- {
- Item* conv= 0;
- Item_arena *arena= thd->current_arena, backup;
- strong= coll.strong;
- weak= strong ? 0 : 1;
- /*
- In case we're in statement prepare, create conversion item
- in its memory: it will be reused on each execute.
- */
- if (arena->is_stmt_prepare())
- thd->set_n_backup_item_arena(arena, &backup);
- if (args[weak]->type() == STRING_ITEM)
- {
- String tmp, cstr;
- String *ostr= args[weak]->val_str(&tmp);
- cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(),
- args[strong]->collation.collation);
- conv= new Item_string(cstr.ptr(),cstr.length(),cstr.charset(),
- args[weak]->collation.derivation);
- ((Item_string*)conv)->str_value.copy();
- }
- else
- {
- conv= new Item_func_conv_charset(args[weak],
- args[strong]->collation.collation);
- conv->collation.set(args[weak]->collation.derivation);
- conv->fix_fields(thd, 0, &conv);
- }
- if (arena->is_stmt_prepare())
- thd->restore_backup_item_arena(arena, &backup);
- if (args[weak]->type() == FIELD_ITEM)
- ((Item_field *)args[weak])->no_const_subst= 1;
- args[weak]= conv ? conv : args[weak];
- }
- }
+ DTCollation coll;
+ if (args[0]->result_type() == STRING_RESULT &&
+ args[1]->result_type() == STRING_RESULT &&
+ agg_arg_charsets(coll, args, 2, MY_COLL_CMP_CONV))
+ return;
+
+
// Make a special case of compare with fields to get nicer DATE comparisons
if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function.
@@ -859,7 +818,7 @@ void Item_func_between::fix_length_and_dec()
return;
agg_cmp_type(&cmp_type, args, 3);
if (cmp_type == STRING_RESULT &&
- agg_arg_collations_for_comparison(cmp_collation, args, 3))
+ agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV))
return;
/*
@@ -975,7 +934,7 @@ Item_func_ifnull::fix_length_and_dec()
decimals=max(args[0]->decimals,args[1]->decimals);
agg_result_type(&cached_result_type, args, 2);
if (cached_result_type == STRING_RESULT)
- agg_arg_collations(collation, args, arg_count);
+ agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
else if (cached_result_type != REAL_RESULT)
decimals= 0;
@@ -1071,8 +1030,8 @@ Item_func_if::fix_length_and_dec()
agg_result_type(&cached_result_type, args+1, 2);
if (cached_result_type == STRING_RESULT)
{
- if (agg_arg_collations(collation, args+1, 2))
- return;
+ if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV))
+ return;
}
else
{
@@ -1331,8 +1290,10 @@ void Item_func_case::fix_length_and_dec()
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
- // Aggregate all THEN and ELSE expression types
- // and collations when string result
+ /*
+ Aggregate all THEN and ELSE expression types
+ and collations when string result
+ */
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
agg[nagg]= args[nagg*2+1];
@@ -1342,7 +1303,7 @@ void Item_func_case::fix_length_and_dec()
agg_result_type(&cached_result_type, agg, nagg);
if ((cached_result_type == STRING_RESULT) &&
- agg_arg_collations(collation, agg, nagg))
+ agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV))
return;
@@ -1358,7 +1319,7 @@ void Item_func_case::fix_length_and_dec()
nagg++;
agg_cmp_type(&cmp_type, agg, nagg);
if ((cmp_type == STRING_RESULT) &&
- agg_arg_collations_for_comparison(cmp_collation, agg, nagg))
+ agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV))
return;
}
@@ -1465,7 +1426,7 @@ void Item_func_coalesce::fix_length_and_dec()
set_if_bigger(decimals,args[i]->decimals);
}
if (cached_result_type == STRING_RESULT)
- agg_arg_collations(collation, args, arg_count);
+ agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV);
else if (cached_result_type != REAL_RESULT)
decimals= 0;
}
@@ -1795,14 +1756,13 @@ void Item_func_in::fix_length_and_dec()
via creating Item_func_conv_charset().
*/
- if (agg_arg_collations_for_comparison(cmp_collation,
- args, arg_count, TRUE))
+ if (agg_arg_collations_for_comparison(cmp_collation, args, arg_count,
+ MY_COLL_ALLOW_SUPERSET_CONV))
return;
if ((!my_charset_same(args[0]->collation.collation,
cmp_collation.collation) || !const_itm))
{
- if (agg_arg_collations_for_comparison(cmp_collation,
- args, arg_count, FALSE))
+ if (agg_arg_collations_for_comparison(cmp_collation, args, arg_count))
return;
}
else
@@ -1811,25 +1771,27 @@ void Item_func_in::fix_length_and_dec()
Conversion is possible:
All IN arguments are constants.
*/
- Item_arena *arena= thd->current_arena, backup;
- if (arena->is_stmt_prepare())
- thd->set_n_backup_item_arena(arena, &backup);
+ Item_arena *arena, backup;
+ arena= thd->change_arena_if_needed(&backup);
+
for (arg= args+1, arg_end= args+arg_count; arg < arg_end; arg++)
{
- if (!my_charset_same(cmp_collation.collation,
+ if (!arg[0]->null_value &&
+ !my_charset_same(cmp_collation.collation,
arg[0]->collation.collation))
{
Item_string *conv;
String tmp, cstr, *ostr= arg[0]->val_str(&tmp);
+ uint dummy_errors;
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(),
- cmp_collation.collation);
+ cmp_collation.collation, &dummy_errors);
conv= new Item_string(cstr.ptr(),cstr.length(), cstr.charset(),
arg[0]->collation.derivation);
conv->str_value.copy();
arg[0]= conv;
}
}
- if (arena->is_stmt_prepare())
+ if (arena)
thd->restore_backup_item_arena(arena, &backup);
}
}
@@ -2449,7 +2411,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
max_length= 1;
decimals= 0;
- if (agg_arg_collations(cmp_collation, args, 2))
+ if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV))
return 1;
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e21364045ba..cec6de3eede 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -370,7 +370,10 @@ Item *create_func_space(Item *a)
{
sp= new Item_string("",0,cs);
if (sp)
- sp->str_value.copy(" ",1,&my_charset_latin1,cs);
+ {
+ uint dummy_errors;
+ sp->str_value.copy(" ", 1, &my_charset_latin1, cs, &dummy_errors);
+ }
}
else
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 3cc0fd077a4..185d4f115ad 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -79,7 +79,7 @@ static void my_coll_agg_error(Item** args, uint count, const char *fname)
bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count,
- bool allow_superset_conversion)
+ uint flags)
{
uint i;
c.nagg= 0;
@@ -87,29 +87,27 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count,
c.set(av[0]->collation);
for (i= 1; i < count; i++)
{
- if (c.aggregate(av[i]->collation, allow_superset_conversion))
+ if (c.aggregate(av[i]->collation, flags))
{
my_coll_agg_error(av, count, func_name());
return TRUE;
}
}
+ if ((flags & MY_COLL_DISALLOW_NONE) &&
+ c.derivation == DERIVATION_NONE)
+ {
+ my_coll_agg_error(av, count, func_name());
+ return TRUE;
+ }
return FALSE;
}
bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
Item **av, uint count,
- bool allow_superset_conv)
+ uint flags)
{
- if (agg_arg_collations(c, av, count, allow_superset_conv))
- return TRUE;
-
- if (c.derivation == DERIVATION_NONE)
- {
- my_coll_agg_error(av, count, func_name());
- return TRUE;
- }
- return FALSE;
+ return (agg_arg_collations(c, av, count, flags | MY_COLL_DISALLOW_NONE));
}
@@ -122,6 +120,90 @@ eval_const_cond(COND *cond)
}
+
+/*
+ Collect arguments' character sets together.
+ We allow to apply automatic character set conversion in some cases.
+ The conditions when conversion is possible are:
+ - arguments A and B have different charsets
+ - A wins according to coercibility rules
+ (i.e. a column is stronger than a string constant,
+ an explicit COLLATE clause is stronger than a column)
+ - character set of A is either superset for character set of B,
+ or B is a string constant which can be converted into the
+ character set of A without data loss.
+
+ If all of the above is true, then it's possible to convert
+ B into the character set of A, and then compare according
+ to the collation of A.
+
+ For functions with more than two arguments:
+
+ collect(A,B,C) ::= collect(collect(A,B),C)
+*/
+
+bool Item_func::agg_arg_charsets(DTCollation &coll,
+ Item **args, uint nargs, uint flags)
+{
+ Item **arg, **last, *safe_args[2];
+ if (agg_arg_collations(coll, args, nargs, flags))
+ return TRUE;
+
+ /*
+ For better error reporting: save the first and the second argument.
+ We need this only if the the number of args is 3 or 2:
+ - for a longer argument list, "Illegal mix of collations"
+ doesn't display each argument's characteristics.
+ - if nargs is 1, then this error cannot happen.
+ */
+ if (nargs >=2 && nargs <= 3)
+ {
+ safe_args[0]= args[0];
+ safe_args[1]= args[1];
+ }
+
+ THD *thd= current_thd;
+ Item_arena *arena, backup;
+ bool res= FALSE;
+ /*
+ In case we're in statement prepare, create conversion item
+ in its memory: it will be reused on each execute.
+ */
+ arena= thd->change_arena_if_needed(&backup);
+
+ for (arg= args, last= args + nargs; arg < last; arg++)
+ {
+ Item* conv;
+ uint dummy_offset;
+ if (!String::needs_conversion(0, coll.collation,
+ (*arg)->collation.collation,
+ &dummy_offset))
+ continue;
+
+ if (!(conv= (*arg)->safe_charset_converter(coll.collation)))
+ {
+ if (nargs >=2 && nargs <= 3)
+ {
+ /* restore the original arguments for better error message */
+ args[0]= safe_args[0];
+ args[1]= safe_args[1];
+ }
+ my_coll_agg_error(args, nargs, func_name());
+ res= TRUE;
+ break; // we cannot return here, we need to restore "arena".
+ }
+ if ((*arg)->type() == FIELD_ITEM)
+ ((Item_field *)(*arg))->no_const_subst= 1;
+ conv->fix_fields(thd, 0, &conv);
+ *arg= conv;
+ }
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ return res;
+}
+
+
+
void Item_func::set_arguments(List<Item> &list)
{
allowed_arg_cols= 1;
@@ -1185,7 +1267,7 @@ void Item_func_min_max::fix_length_and_dec()
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
}
if (cmp_type == STRING_RESULT)
- agg_arg_collations_for_comparison(collation, args, arg_count);
+ agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
}
@@ -1339,7 +1421,7 @@ longlong Item_func_coercibility::val_int()
void Item_func_locate::fix_length_and_dec()
{
maybe_null=0; max_length=11;
- agg_arg_collations_for_comparison(cmp_collation, args, 2);
+ agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV);
}
@@ -1438,7 +1520,7 @@ void Item_func_field::fix_length_and_dec()
for (uint i=1; i < arg_count ; i++)
cmp_type= item_cmp_type(cmp_type, args[i]->result_type());
if (cmp_type == STRING_RESULT)
- agg_arg_collations_for_comparison(cmp_collation, args, arg_count);
+ agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV);
}
@@ -2346,6 +2428,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->value=0;
entry->length=0;
entry->update_query_id=0;
+ entry->collation.set(NULL, DERIVATION_NONE);
/*
If we are here, we were called from a SET or a query which sets a
variable. Imagine it is this:
@@ -2387,7 +2470,24 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
is different from query_id).
*/
entry->update_query_id= thd->query_id;
- entry->collation.set(args[0]->collation);
+ /*
+ As it is wrong and confusing to associate any
+ character set with NULL, @a should be latin2
+ after this query sequence:
+
+ SET @a=_latin2'string';
+ SET @a=NULL;
+
+ I.e. the second query should not change the charset
+ to the current default value, but should keep the
+ original value assigned during the first query.
+ In order to do it, we don't copy charset
+ from the argument if the argument is NULL
+ and the variable has previously been initialized.
+ */
+ if (!entry->collation.collation || !args[0]->null_value)
+ entry->collation.set(args[0]->collation);
+ collation.set(entry->collation);
cached_result_type= args[0]->result_type();
return 0;
}
@@ -2415,7 +2515,6 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length,
my_free(entry->value,MYF(0));
entry->value=0;
entry->length=0;
- entry->collation.set(cs, dv);
}
else
{
@@ -3003,8 +3102,9 @@ void Item_func_match::init_search(bool no_order)
if (ft_tmp->charset() != cmp_collation.collation)
{
+ uint dummy_errors;
search_value.copy(ft_tmp->ptr(), ft_tmp->length(), ft_tmp->charset(),
- cmp_collation.collation);
+ cmp_collation.collation, &dummy_errors);
ft_tmp= &search_value;
}
@@ -3414,7 +3514,7 @@ Item_func_sp::func_name() const
1 + // .
1 + // end of string
ALIGN_SIZE(1)); // to avoid String reallocation
- String qname((char *)alloc_root(&thd->mem_root, len), len,
+ String qname((char *)alloc_root(thd->mem_root, len), len,
system_charset_info);
qname.length(0);
diff --git a/sql/item_func.h b/sql/item_func.h
index 3b941c4a40c..602b77ae956 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -146,11 +146,12 @@ public:
Item *get_tmp_table_item(THD *thd);
bool agg_arg_collations(DTCollation &c, Item **items, uint nitems,
- bool allow_superset_conversion= FALSE);
+ uint flags= 0);
bool agg_arg_collations_for_comparison(DTCollation &c,
Item **items, uint nitems,
- bool allow_superset_comversion= FALSE);
-
+ uint flags= 0);
+ bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
+ uint flags= 0);
bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
};
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 935925c1e83..7c3319bbfea 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -148,9 +148,9 @@ String *Item_func_geometry_type::val_str(String *str)
swkb->length() - SRID_SIZE)))))
return 0;
/* String will not move */
- str->set(geom->get_class_info()->m_name.str,
- geom->get_class_info()->m_name.length,
- default_charset());
+ str->copy(geom->get_class_info()->m_name.str,
+ geom->get_class_info()->m_name.length,
+ default_charset());
return str;
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index d015ca36eac..889b00eb6a0 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -346,7 +346,7 @@ void Item_func_concat::fix_length_and_dec()
{
max_length=0;
- if (agg_arg_collations(collation, args, arg_count))
+ if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV))
return;
for (uint i=0 ; i < arg_count ; i++)
@@ -640,10 +640,15 @@ void Item_func_concat_ws::fix_length_and_dec()
{
max_length=0;
- if (agg_arg_collations(collation, args, arg_count))
+ if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV))
return;
- max_length= arg_count > 1 ? args[0]->max_length * (arg_count - 2) : 0;
+ /*
+ arg_count cannot be less than 2,
+ it is done on parser level in sql_yacc.yy
+ so, (arg_count - 2) is safe here.
+ */
+ max_length= args[0]->max_length * (arg_count - 2);
for (uint i=1 ; i < arg_count ; i++)
max_length+=args[i]->max_length;
@@ -843,7 +848,7 @@ void Item_func_replace::fix_length_and_dec()
maybe_null=1;
}
- if (agg_arg_collations_for_comparison(collation, args, 3))
+ if (agg_arg_charsets(collation, args, 3, MY_COLL_CMP_CONV))
return;
}
@@ -888,11 +893,13 @@ null:
void Item_func_insert::fix_length_and_dec()
{
- if (collation.set(args[0]->collation, args[3]->collation))
- {
- my_coll_agg_error(args[0]->collation, args[3]->collation, func_name());
- return;
- }
+ Item *cargs[2];
+ cargs[0]= args[0];
+ cargs[1]= args[3];
+ if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV))
+ return;
+ args[0]= cargs[0];
+ args[3]= cargs[1];
max_length=args[0]->max_length+args[3]->max_length;
if (max_length > MAX_BLOB_WIDTH)
{
@@ -1058,7 +1065,7 @@ void Item_func_substr_index::fix_length_and_dec()
{
max_length= args[0]->max_length;
- if (agg_arg_collations_for_comparison(collation, args, 2))
+ if (agg_arg_charsets(collation, args, 2, MY_COLL_CMP_CONV))
return;
}
@@ -1350,10 +1357,14 @@ void Item_func_trim::fix_length_and_dec()
remove.set_ascii(" ",1);
}
else
- if (collation.set(args[1]->collation, args[0]->collation) ||
- collation.derivation == DERIVATION_NONE)
{
- my_coll_agg_error(args[1]->collation, args[0]->collation, func_name());
+ Item *cargs[2];
+ cargs[0]= args[1];
+ cargs[1]= args[0];
+ if (agg_arg_charsets(collation, cargs, 2, MY_COLL_CMP_CONV))
+ return;
+ args[0]= cargs[1];
+ args[1]= cargs[0];
}
}
@@ -1674,7 +1685,7 @@ void Item_func_elt::fix_length_and_dec()
max_length=0;
decimals=0;
- if (agg_arg_collations(collation, args+1, arg_count-1))
+ if (agg_arg_charsets(collation, args+1, arg_count-1, MY_COLL_ALLOW_CONV))
return;
for (uint i= 1 ; i < arg_count ; i++)
@@ -1750,7 +1761,7 @@ void Item_func_make_set::fix_length_and_dec()
{
max_length=arg_count-1;
- if (agg_arg_collations(collation, args, arg_count))
+ if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV))
return;
for (uint i=0 ; i < arg_count ; i++)
@@ -1958,12 +1969,13 @@ err:
void Item_func_rpad::fix_length_and_dec()
{
- if (collation.set(args[0]->collation, args[2]->collation))
- {
- my_coll_agg_error(args[0]->collation, args[2]->collation, func_name());
+ Item *cargs[2];
+ cargs[0]= args[0];
+ cargs[1]= args[2];
+ if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV))
return;
- }
-
+ args[0]= cargs[0];
+ args[2]= cargs[1];
if (args[1]->const_item())
{
uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen;
@@ -2042,11 +2054,13 @@ String *Item_func_rpad::val_str(String *str)
void Item_func_lpad::fix_length_and_dec()
{
- if (collation.set(args[0]->collation, args[2]->collation))
- {
- my_coll_agg_error(args[0]->collation, args[2]->collation, func_name());
+ Item *cargs[2];
+ cargs[0]= args[0];
+ cargs[1]= args[2];
+ if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV))
return;
- }
+ args[0]= cargs[0];
+ args[2]= cargs[1];
if (args[1]->const_item())
{
@@ -2155,13 +2169,14 @@ String *Item_func_conv_charset::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String *arg= args[0]->val_str(str);
+ uint dummy_errors;
if (!arg)
{
null_value=1;
return 0;
}
null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(),
- conv_charset);
+ conv_charset, &dummy_errors);
return null_value ? 0 : &str_value;
}
@@ -2256,11 +2271,12 @@ String *Item_func_charset::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res = args[0]->val_str(str);
+ uint dummy_errors;
if ((null_value=(args[0]->null_value || !res->charset())))
return 0;
str->copy(res->charset()->csname,strlen(res->charset()->csname),
- &my_charset_latin1, collation.collation);
+ &my_charset_latin1, collation.collation, &dummy_errors);
return str;
}
@@ -2268,11 +2284,12 @@ String *Item_func_collation::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res = args[0]->val_str(str);
+ uint dummy_errors;
if ((null_value=(args[0]->null_value || !res->charset())))
return 0;
str->copy(res->charset()->name,strlen(res->charset()->name),
- &my_charset_latin1, collation.collation);
+ &my_charset_latin1, collation.collation, &dummy_errors);
return str;
}
@@ -2499,7 +2516,8 @@ void Item_func_export_set::fix_length_and_dec()
uint sep_length=(arg_count > 3 ? args[3]->max_length : 1);
max_length=length*64+sep_length*63;
- if (agg_arg_collations(collation, args+1, min(4,arg_count)-1))
+ if (agg_arg_charsets(collation, args+1, min(4,arg_count)-1),
+ MY_COLL_ALLOW_CONV)
return;
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index bafca8acf0f..f426f14a25f 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -190,15 +190,16 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
bool Item_subselect::exec()
{
int res;
- MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
- if (&thd->mem_root != old_root)
- {
- my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root);
- res= engine->exec();
- my_pthread_setspecific_ptr(THR_MALLOC, old_root);
- }
- else
- res= engine->exec();
+ MEM_ROOT *old_root= thd->mem_root;
+
+ /*
+ As this is execution, all objects should be allocated through the main
+ mem root
+ */
+ thd->mem_root= &thd->main_mem_root;
+ res= engine->exec();
+ thd->mem_root= old_root;
+
if (engine_changed)
{
engine_changed= 0;
@@ -661,15 +662,10 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
SELECT_LEX *select_lex= join->select_lex;
- Item_arena *arena= thd->current_arena, backup;
-
+ Item_arena *arena, backup;
+ arena= thd->change_arena_if_needed(&backup);
thd->where= "scalar IN/ALL/ANY subquery";
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_item_arena(arena, &backup);
-
/*
Check that the right part of the subselect contains no more than one
column. E.g. in SELECT 1 IN (SELECT * ..) the right part is (SELECT * ...)
@@ -928,11 +924,8 @@ Item_in_subselect::row_value_transformer(JOIN *join)
}
thd->where= "row IN/ALL/ANY subquery";
- Item_arena *arena= thd->current_arena, backup;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_item_arena(arena, &backup);
+ Item_arena *arena, backup;
+ arena= thd->change_arena_if_needed(&backup);
if (select_lex->item_list.elements != left_expr->cols())
{
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 743b3eee58c..72c85e2dd40 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -255,7 +255,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Item *Item_sum_sum::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_sum(thd, this);
+ return new (thd->mem_root) Item_sum_sum(thd, this);
}
@@ -313,7 +313,7 @@ Item_sum_sum_distinct::~Item_sum_sum_distinct()
Item *
Item_sum_sum_distinct::copy_or_same(THD *thd)
{
- return new (&thd->mem_root) Item_sum_sum_distinct(thd, this);
+ return new (thd->mem_root) Item_sum_sum_distinct(thd, this);
}
C_MODE_START
@@ -399,7 +399,7 @@ double Item_sum_sum_distinct::val()
Item *Item_sum_count::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_count(thd, this);
+ return new (thd->mem_root) Item_sum_count(thd, this);
}
@@ -444,7 +444,7 @@ void Item_sum_count::cleanup()
Item *Item_sum_avg::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_avg(thd, this);
+ return new (thd->mem_root) Item_sum_avg(thd, this);
}
@@ -491,7 +491,7 @@ double Item_sum_std::val()
Item *Item_sum_std::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_std(thd, this);
+ return new (thd->mem_root) Item_sum_std(thd, this);
}
@@ -501,7 +501,7 @@ Item *Item_sum_std::copy_or_same(THD* thd)
Item *Item_sum_variance::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_variance(thd, this);
+ return new (thd->mem_root) Item_sum_variance(thd, this);
}
@@ -663,7 +663,7 @@ void Item_sum_hybrid::cleanup()
Item *Item_sum_min::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_min(thd, this);
+ return new (thd->mem_root) Item_sum_min(thd, this);
}
@@ -716,7 +716,7 @@ bool Item_sum_min::add()
Item *Item_sum_max::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_max(thd, this);
+ return new (thd->mem_root) Item_sum_max(thd, this);
}
@@ -783,7 +783,7 @@ void Item_sum_bit::clear()
Item *Item_sum_or::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_or(thd, this);
+ return new (thd->mem_root) Item_sum_or(thd, this);
}
@@ -797,7 +797,7 @@ bool Item_sum_or::add()
Item *Item_sum_xor::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_xor(thd, this);
+ return new (thd->mem_root) Item_sum_xor(thd, this);
}
@@ -811,7 +811,7 @@ bool Item_sum_xor::add()
Item *Item_sum_and::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_and(thd, this);
+ return new (thd->mem_root) Item_sum_and(thd, this);
}
@@ -1449,7 +1449,7 @@ int Item_sum_count_distinct::tree_to_myisam()
Item *Item_sum_count_distinct::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_count_distinct(thd, this);
+ return new (thd->mem_root) Item_sum_count_distinct(thd, this);
}
@@ -1550,7 +1550,7 @@ bool Item_udf_sum::add()
Item *Item_sum_udf_float::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_udf_float(thd, this);
+ return new (thd->mem_root) Item_sum_udf_float(thd, this);
}
double Item_sum_udf_float::val()
@@ -1575,7 +1575,7 @@ String *Item_sum_udf_float::val_str(String *str)
Item *Item_sum_udf_int::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_udf_int(thd, this);
+ return new (thd->mem_root) Item_sum_udf_int(thd, this);
}
@@ -1613,7 +1613,7 @@ void Item_sum_udf_str::fix_length_and_dec()
Item *Item_sum_udf_str::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_sum_udf_str(thd, this);
+ return new (thd->mem_root) Item_sum_udf_str(thd, this);
}
@@ -1927,7 +1927,7 @@ Item_func_group_concat::~Item_func_group_concat()
Item *Item_func_group_concat::copy_or_same(THD* thd)
{
- return new (&thd->mem_root) Item_func_group_concat(thd, this);
+ return new (thd->mem_root) Item_func_group_concat(thd, this);
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 3a25921d84b..566cacca487 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -164,10 +164,10 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
CHARSET_INFO *cs= &my_charset_bin;
int error= 0;
bool usa_time= 0;
- bool sunday_first_n_first_week_non_iso;
+ bool sunday_first_n_first_week_non_iso= -2;
bool strict_week_number;
int strict_week_number_year= -1;
- bool strict_week_number_year_type;
+ bool strict_week_number_year_type= -1;
int frac_part;
const char *val_begin= val;
const char *val_end= val + length;
@@ -175,9 +175,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
const char *end= ptr + format->format.length;
DBUG_ENTER("extract_date_time");
- LINT_INIT(sunday_first_n_first_week_non_iso);
LINT_INIT(strict_week_number);
- LINT_INIT(strict_week_number_year_type);
if (!sub_pattern_end)
bzero((char*) l_time, sizeof(*l_time));
@@ -2140,8 +2138,10 @@ String *Item_char_typecast::val_str(String *str)
else
{
// Convert character set if differ
+ uint dummy_errors;
if (!(res1= args[0]->val_str(&tmp_value)) ||
- str->copy(res1->ptr(), res1->length(),res1->charset(), cast_cs))
+ str->copy(res1->ptr(), res1->length(), res1->charset(),
+ cast_cs, &dummy_errors))
{
null_value= 1;
return 0;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ee5af6ed1c0..c7f6f25e74a 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1535,7 +1535,7 @@ end:
thd->query_length= thd->db_length =0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
close_thread_tables(thd);
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
/*
If there was an error we stop. Otherwise we increment positions. Note that
we will not increment group* positions if we are just after a SET
@@ -2614,10 +2614,10 @@ Slave: load data infile on table '%s' at log position %s in log \
slave_print_error(rli,sql_errno,"\
Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
err, (char*)table_name, print_slave_db_safe(db));
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
return 1;
}
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
if (thd->is_fatal_error)
{
@@ -3250,7 +3250,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
*/
e.fix_fields(thd, 0, 0);
e.update_hash(val, val_len, type, charset, DERIVATION_NONE);
- free_root(&thd->mem_root,0);
+ free_root(thd->mem_root,0);
rli->inc_event_relay_log_pos();
return 0;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index cd2cacad910..b343beaa4e4 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -997,7 +997,7 @@ extern char *default_tz_name;
extern MYSQL_LOG mysql_log,mysql_slow_log,mysql_bin_log;
extern FILE *bootstrap_file;
-extern pthread_key(MEM_ROOT*,THR_MALLOC);
+extern pthread_key(MEM_ROOT**,THR_MALLOC);
extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 3d7ab14f13d..196b7af46b1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -375,7 +375,7 @@ SHOW_COMP_OPTION have_crypt, have_compress;
/* Thread specific variables */
-pthread_key(MEM_ROOT*,THR_MALLOC);
+pthread_key(MEM_ROOT**,THR_MALLOC);
pthread_key(THD*, THR_THD);
pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_mapped_file, LOCK_status,
@@ -2972,11 +2972,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
exit(1);
#ifdef __WIN__
-#define MYSQL_ERR_FILE "mysql.err"
if (!opt_console)
{
- freopen(MYSQL_ERR_FILE,"a+",stdout);
- freopen(MYSQL_ERR_FILE,"a+",stderr);
+ freopen(log_error_file,"a+",stdout);
+ freopen(log_error_file,"a+",stderr);
FreeConsole(); // Remove window
}
#endif
@@ -5132,12 +5131,12 @@ The minimum value for this variable is 4096.",
"Persistent buffer for query parsing and execution",
(gptr*) &global_system_variables.query_prealloc_size,
(gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0},
+ REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 16384, ~0L, 0, 1024, 0},
{"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE,
"Allocation block size for storing ranges during optimization",
(gptr*) &global_system_variables.range_alloc_block_size,
(gptr*) &max_system_variables.range_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0},
+ REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 4096, ~0L, 0, 1024, 0},
{"read_buffer_size", OPT_RECORD_BUFFER,
"Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.",
(gptr*) &global_system_variables.read_buff_size,
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 27311cb5613..bcb1f8634c0 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -53,19 +53,9 @@
#include <errno.h>
#ifdef EMBEDDED_LIBRARY
-
#undef MYSQL_SERVER
-
-#ifndef MYSQL_CLIENT
+#undef MYSQL_CLIENT
#define MYSQL_CLIENT
-#endif
-
-#undef net_flush
-
-extern "C" {
-my_bool net_flush(NET *net);
-}
-
#endif /*EMBEDDED_LIBRARY */
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 286d0d01842..f036cbc799b 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -724,7 +724,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
{
// Allocates everything through the internal memroot
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
- my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
+ thd->mem_root= &alloc;
}
else
bzero((char*) &alloc,sizeof(alloc));
@@ -1041,7 +1041,7 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
rowid_length= table->file->ref_length;
record= head->record[0];
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
- my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
+ thd_param->mem_root= &alloc;
}
@@ -1476,7 +1476,8 @@ public:
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg, uint used_key_parts_arg,
uint group_key_parts_arg, KEY *index_info_arg,
- uint index_arg, uint key_infix_len_arg, byte *key_infix_arg,
+ uint index_arg, uint key_infix_len_arg,
+ byte *key_infix_arg,
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
uint param_idx_arg, ha_rows quick_prefix_records_arg)
: have_min(have_min_arg), have_max(have_max_arg),
@@ -1486,12 +1487,10 @@ public:
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg),
index_tree(index_tree_arg), param_idx(param_idx_arg),
quick_prefix_records(quick_prefix_records_arg)
-{
- if (key_infix_len)
- memcpy(this->key_infix, key_infix_arg, key_infix_len);
-}
-
-
+ {
+ if (key_infix_len)
+ memcpy(this->key_infix, key_infix_arg, key_infix_len);
+ }
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
MEM_ROOT *parent_alloc);
@@ -1649,8 +1648,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_RETURN(0); // Can't use range
}
key_parts= param.key_parts;
- old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
- my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
+ old_root= thd->mem_root;
+ thd->mem_root= &alloc;
/*
Make an array with description of all key parts of all table keys.
@@ -1795,7 +1794,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
}
}
- my_pthread_setspecific_ptr(THR_MALLOC, old_root);
+ thd->mem_root= old_root;
/* If we got a read plan, create a quick select from it. */
if (best_trp)
@@ -1809,8 +1808,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
}
free_mem:
- my_pthread_setspecific_ptr(THR_MALLOC, old_root);
free_root(&alloc,MYF(0)); // Return memory & allocator
+ thd->mem_root= old_root;
thd->no_errors=0;
}
@@ -3566,13 +3565,22 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
}
/*
- We can't use an index when comparing strings of
- different collations
+ 1. Usually we can't use an index if the column collation
+ differ from the operation collation.
+
+ 2. However, we can reuse a case insensitive index for
+ the binary searches:
+
+ WHERE latin1_swedish_ci_column = 'a' COLLATE lati1_bin;
+
+ WHERE latin1_swedish_ci_colimn = BINARY 'a '
+
*/
if (field->result_type() == STRING_RESULT &&
value->result_type() == STRING_RESULT &&
key_part->image_type == Field::itRAW &&
- ((Field_str*)field)->charset() != conf_func->compare_collation())
+ ((Field_str*)field)->charset() != conf_func->compare_collation() &&
+ !(conf_func->compare_collation()->state & MY_CS_BINSORT))
DBUG_RETURN(0);
optimize_range= field->optimize_range(param->real_keynr[key_part->key],
@@ -5220,7 +5228,7 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts)
NOTES
The caller must call QUICK_SELECT::init for returned quick select
- CAUTION! This function may change THR_MALLOC to a MEM_ROOT which will be
+ CAUTION! This function may change thd->mem_root to a MEM_ROOT which will be
deallocated when the returned quick select is deleted.
RETURN
@@ -5464,7 +5472,8 @@ bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List<Item> *fields)
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
TABLE_REF *ref)
{
- MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
+ MEM_ROOT *old_root= thd->mem_root;
+ /* The following call may change thd->mem_root */
QUICK_RANGE_SELECT *quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0);
KEY *key_info = &table->key_info[ref->key];
KEY_PART *key_part;
@@ -5525,11 +5534,11 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
}
ok:
- my_pthread_setspecific_ptr(THR_MALLOC, old_root);
+ thd->mem_root= old_root;
return quick;
err:
- my_pthread_setspecific_ptr(THR_MALLOC, old_root);
+ thd->mem_root= old_root;
delete quick;
return 0;
}
@@ -7488,10 +7497,10 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
if (!parent_alloc)
{
init_sql_alloc(&alloc, join->thd->variables.range_alloc_block_size, 0);
- my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
+ join->thd->mem_root= &alloc;
}
else
- bzero(&alloc, sizeof(MEM_ROOT));
+ bzero(&alloc, sizeof(MEM_ROOT)); // ensure that it's not used
}
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index f548c16d808..c3043ed2c73 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -608,15 +608,13 @@ parse_quoted_escaped_string(char *ptr, char *end,
my_bool
File_parser::parse(gptr base, MEM_ROOT *mem_root,
- struct File_option *parameters, uint required)
+ struct File_option *parameters, uint required)
{
uint first_param= 0, found= 0;
register char *ptr= start;
char *eol;
LEX_STRING *str;
- MEM_ROOT *sql_mem;
List<LEX_STRING> *list;
- bool change_mem;
DBUG_ENTER("File_parser::parse");
while (ptr < end && found < required)
@@ -720,18 +718,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
}
case FILE_OPTIONS_STRLIST:
{
- /*
- TODO: remove play with mem_root, when List will be able
- to store MEM_ROOT* pointer for list elements allocation
- FIXME: we can't handle empty lists
- */
- sql_mem= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
- list= (List<LEX_STRING>*)(base + parameter->offset);
- if ((change_mem= (sql_mem != mem_root)))
- {
- change_mem= 1;
- my_pthread_setspecific_ptr(THR_MALLOC, mem_root);
- }
+ list= (List<LEX_STRING>*)(base + parameter->offset);
list->empty();
// list parsing
@@ -739,7 +726,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
{
if (!(str= (LEX_STRING*)alloc_root(mem_root,
sizeof(LEX_STRING))) ||
- list->push_back(str))
+ list->push_back(str, mem_root))
goto list_err;
if(!(ptr= parse_quoted_escaped_string(ptr, end, mem_root, str)))
goto list_err_w_message;
@@ -754,20 +741,15 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
goto list_err_w_message;
}
}
- end_of_list:
+ end_of_list:
if (*(ptr++) != '\n')
goto list_err;
-
- if (change_mem)
- my_pthread_setspecific_ptr(THR_MALLOC, sql_mem);
break;
list_err_w_message:
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
parameter->name.str, line);
list_err:
- if (change_mem)
- my_pthread_setspecific_ptr(THR_MALLOC, sql_mem);
DBUG_RETURN(TRUE);
}
default:
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 051eaaf7bda..2b0ae60f944 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -486,6 +486,15 @@ void Protocol::init(THD *thd_arg)
}
+bool Protocol::flush()
+{
+#ifndef EMBEDDED_LIBRARY
+ return net_flush(&thd->net);
+#else
+ return 0;
+#endif
+}
+
/*
Send name and type of result to client.
@@ -731,7 +740,8 @@ bool Protocol::store_string_aux(const char *from, uint length,
fromcs != &my_charset_bin &&
tocs != &my_charset_bin)
{
- return convert->copy(from, length, fromcs, tocs) ||
+ uint dummy_errors;
+ return convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
net_store_data(convert->ptr(), convert->length());
}
return net_store_data(from, length);
diff --git a/sql/protocol.h b/sql/protocol.h
index 7d390242417..d342af3ee9f 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -74,6 +74,7 @@ public:
field_count=item_list->elements;
return 0;
}
+ virtual bool flush();
virtual void prepare_for_resend()=0;
virtual bool store_null()=0;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index dc23b014e31..253b2c96545 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -92,7 +92,7 @@ static int init_failsafe_rpl_thread(THD* thd)
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
- thd->mem_root.free=thd->mem_root.used=0;
+ thd->mem_root->free= thd->mem_root->used= 0;
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options|= OPTION_BIG_SELECTS;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 8ffed33d442..ccac3082d5b 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1193,7 +1193,7 @@ static void fix_max_connections(THD *thd, enum_var_type type)
static void fix_thd_mem_root(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
- reset_root_defaults(&thd->mem_root,
+ reset_root_defaults(thd->mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
diff --git a/sql/sp.cc b/sql/sp.cc
index a1e52ee1ca7..96bb8a17a49 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -166,7 +166,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
}
bzero((char *)&chistics, sizeof(chistics));
- if ((ptr= get_field(&thd->mem_root,
+ if ((ptr= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_ACCESS])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
@@ -189,7 +189,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
chistics.daccess= SP_CONTAINS_SQL;
}
- if ((ptr= get_field(&thd->mem_root,
+ if ((ptr= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_DETERMINISTIC])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
@@ -197,7 +197,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
}
chistics.detistic= (ptr[0] == 'N' ? FALSE : TRUE);
- if ((ptr= get_field(&thd->mem_root,
+ if ((ptr= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
@@ -205,7 +205,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
}
chistics.suid= (ptr[0] == 'I' ? SP_IS_NOT_SUID : SP_IS_SUID);
- if ((params= get_field(&thd->mem_root,
+ if ((params= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL)
{
params= "";
@@ -213,14 +213,14 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
if (type == TYPE_ENUM_PROCEDURE)
returns= "";
- else if ((returns= get_field(&thd->mem_root,
+ else if ((returns= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_RETURNS])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
- if ((body= get_field(&thd->mem_root,
+ if ((body= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_BODY])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
@@ -228,7 +228,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
}
// Get additional information
- if ((definer= get_field(&thd->mem_root,
+ if ((definer= get_field(thd->mem_root,
table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
@@ -511,10 +511,10 @@ print_field_values(THD *thd, TABLE *table,
String name_string;
struct st_used_field *used_field= used_fields;
- if (get_field(&thd->mem_root, used_field->field, &db_string))
+ if (get_field(thd->mem_root, used_field->field, &db_string))
db_string.set_ascii("", 0);
used_field+= 1;
- get_field(&thd->mem_root, used_field->field, &name_string);
+ get_field(thd->mem_root, used_field->field, &name_string);
if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0))
{
@@ -539,7 +539,7 @@ print_field_values(THD *thd, TABLE *table,
{
String tmp_string;
- get_field(&thd->mem_root, used_field->field, &tmp_string);
+ get_field(thd->mem_root, used_field->field, &tmp_string);
protocol->store(&tmp_string);
}
break;
@@ -982,7 +982,7 @@ sp_cache_functions(THD *thd, LEX *lex)
newlex->proc_table= oldlex->proc_table; // hint if mysql.oper is opened
name.m_name.str= strchr(name.m_qname.str, '.');
name.m_db.length= name.m_name.str - name.m_qname.str;
- name.m_db.str= strmake_root(&thd->mem_root,
+ name.m_db.str= strmake_root(thd->mem_root,
name.m_qname.str, name.m_db.length);
name.m_name.str+= 1;
name.m_name.length= name.m_qname.length - name.m_db.length - 1;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 8de1b6e906a..47e3952bcdd 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -190,7 +190,7 @@ void
sp_name::init_qname(THD *thd)
{
m_qname.length= m_db.length+m_name.length+1;
- m_qname.str= alloc_root(&thd->mem_root, m_qname.length+1);
+ m_qname.str= thd->alloc(m_qname.length+1);
sprintf(m_qname.str, "%*s.%*s",
m_db.length, (m_db.length ? m_db.str : ""),
m_name.length, m_name.str);
@@ -232,10 +232,9 @@ sp_head::operator new(size_t size)
MEM_ROOT own_root;
sp_head *sp;
- bzero((char *)&own_root, sizeof(own_root));
init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
- sp= (sp_head *)alloc_root(&own_root, size);
- sp->mem_root= own_root;
+ sp= (sp_head *) alloc_root(&own_root, size);
+ sp->main_mem_root= own_root;
DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
DBUG_RETURN(sp);
}
@@ -245,9 +244,10 @@ sp_head::operator delete(void *ptr, size_t size)
{
DBUG_ENTER("sp_head::operator delete");
MEM_ROOT own_root;
- sp_head *sp= (sp_head *)ptr;
+ sp_head *sp= (sp_head *) ptr;
- memcpy(&own_root, (const void *)&sp->mem_root, sizeof(MEM_ROOT));
+ /* Make a copy of main_mem_root as free_root will free the sp */
+ own_root= sp->main_mem_root;
DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx",
(ulong) &sp->mem_root, (ulong) &own_root));
free_root(&own_root, MYF(0));
@@ -291,7 +291,7 @@ 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;
+ MEM_ROOT *root= thd->mem_root;
/* We have to copy strings to get them into the right memroot */
if (name)
@@ -916,19 +916,19 @@ sp_head::set_info(char *definer, uint definerlen,
if (! p)
p= definer; // Weird...
len= p-definer;
- m_definer_user.str= strmake_root(&mem_root, definer, len);
+ m_definer_user.str= strmake_root(mem_root, definer, len);
m_definer_user.length= len;
len= definerlen-len-1;
- m_definer_host.str= strmake_root(&mem_root, p+1, len);
+ m_definer_host.str= strmake_root(mem_root, p+1, len);
m_definer_host.length= len;
m_created= created;
m_modified= modified;
- m_chistics= (st_sp_chistics *)alloc_root(&mem_root, sizeof(st_sp_chistics));
- memcpy(m_chistics, chistics, sizeof(st_sp_chistics));
+ m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics,
+ sizeof(*chistics));
if (m_chistics->comment.length == 0)
m_chistics->comment.str= 0;
else
- m_chistics->comment.str= strmake_root(&mem_root,
+ m_chistics->comment.str= strmake_root(mem_root,
m_chistics->comment.str,
m_chistics->comment.length);
m_sql_mode= sql_mode;
@@ -939,14 +939,14 @@ sp_head::reset_thd_mem_root(THD *thd)
{
DBUG_ENTER("sp_head::reset_thd_mem_root");
m_thd_root= thd->mem_root;
- thd->mem_root= mem_root;
+ thd->mem_root= &main_mem_root;
DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
/* Copy the db, since substatements will point to it */
m_thd_db= thd->db;
- thd->db= strmake_root(&thd->mem_root, thd->db, thd->db_length);
+ thd->db= thd->strmake(thd->db, thd->db_length);
m_thd= thd;
DBUG_VOID_RETURN;
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 6aa05838291..4bfe1076f65 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -231,7 +231,7 @@ public:
private:
- MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
+ MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
THD *m_thd; // Set if we have reset mem_root
char *m_thd_db; // Original thd->db pointer
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 0668dd2faab..bcfefd9dde8 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -828,9 +828,7 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
if (!first_loop)
{
- double d_area= res_area - cur_area;
- if (d_area <= 0)
- return 1;
+ double d_area= fabs(res_area - cur_area);
res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area;
res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area;
}
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index a766081f0a0..3e3642dd0bd 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2426,8 +2426,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
create_new_users= test_if_create_new_users(thd);
int result=0;
rw_wrlock(&LOCK_grant);
- MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
- my_pthread_setspecific_ptr(THR_MALLOC,&memex);
+ MEM_ROOT *old_root= thd->mem_root;
+ thd->mem_root= &memex;
while ((Str = str_list++))
{
@@ -2535,7 +2535,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
}
grant_option=TRUE;
- my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ thd->mem_root= old_root;
rw_unlock(&LOCK_grant);
if (!result)
send_ok(thd);
@@ -2667,6 +2667,7 @@ my_bool grant_init(THD *org_thd)
THD *thd;
TABLE_LIST tables[2];
MYSQL_LOCK *lock;
+ MEM_ROOT *memex_ptr;
my_bool return_val= 1;
TABLE *t_table, *c_table;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
@@ -2714,7 +2715,8 @@ my_bool grant_init(THD *org_thd)
grant_option= TRUE;
/* Will be restored by org_thd->store_globals() */
- my_pthread_setspecific_ptr(THR_MALLOC,&memex);
+ memex_ptr= &memex;
+ my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
do
{
GRANT_TABLE *mem_check;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index c6e11bc73cc..4fae481e5f2 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -509,7 +509,7 @@ void close_temporary_tables(THD *thd)
*/
query_buf_size+= table->key_length+1;
- if ((query = alloc_root(&thd->mem_root, query_buf_size)))
+ if ((query = alloc_root(thd->mem_root, query_buf_size)))
// Better add "if exists", in case a RESET MASTER has been done
end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
@@ -824,7 +824,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
pthread_mutex_lock(&LOCK_open);
if (open_unireg_entry(thd, table, db, table_name, table_name, 0,
- &thd->mem_root) ||
+ thd->mem_root) ||
!(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
key_length)))
{
@@ -1144,7 +1144,7 @@ bool reopen_table(TABLE *table,bool locked)
safe_mutex_assert_owner(&LOCK_open);
if (open_unireg_entry(table->in_use, &tmp, db, table_name,
- table->table_name, 0, &table->in_use->mem_root))
+ table->table_name, 0, table->in_use->mem_root))
goto end;
free_io_cache(table);
@@ -1783,7 +1783,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
- while (!(table= open_table(thd, table_list, &thd->mem_root, &refresh)) &&
+ while (!(table= open_table(thd, table_list, thd->mem_root, &refresh)) &&
refresh)
;
@@ -2608,24 +2608,20 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
- Item *item;
- DBUG_ENTER("setup_wild");
-
if (!wild_num)
- DBUG_RETURN(0);
+ return(0);
- Item_arena *arena= thd->current_arena, backup;
+ Item *item;
+ List_iterator<Item> it(fields);
+ Item_arena *arena, backup;
+ DBUG_ENTER("setup_wild");
/*
Don't use arena if we are not in prepared statements or stored procedures
For PS/SP we have to use arena to remember the changes
*/
- if (arena->is_conventional())
- arena= 0; // For easier test later one
- else
- thd->set_n_backup_item_arena(arena, &backup);
+ arena= thd->change_arena_if_needed(&backup);
- List_iterator<Item> it(fields);
while (wild_num && (item= it++))
{
if (item->type() == Item::FIELD_ITEM &&
@@ -3014,7 +3010,8 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
during cleunup() this item will be put in list to replace
expression from VIEW
*/
- thd->nocheck_register_item_tree_change(it->ref(), item, &thd->mem_root);
+ thd->nocheck_register_item_tree_change(it->ref(), item,
+ thd->mem_root);
}
}
/* All fields are used */
@@ -3119,7 +3116,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
if (arena)
- thd->set_n_backup_item_arena(arena, &backup);
+ arena= thd->change_arena_if_needed(&backup);
TABLE *t1=tab1->table;
TABLE *t2=tab2->table;
@@ -3220,7 +3217,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
embedding->nested_join->join_list.head() == embedded);
}
- if (arena)
+ if (!thd->current_arena->is_conventional())
{
/*
We are in prepared statement preparation code => we should store
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index f5283020b30..15e1cc7e212 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -316,7 +316,7 @@ void THD::init_for_queries()
{
ha_enable_transaction(this,TRUE);
- reset_root_defaults(&mem_root, variables.query_alloc_block_size,
+ reset_root_defaults(mem_root, variables.query_alloc_block_size,
variables.query_prealloc_size);
reset_root_defaults(&transaction.mem_root,
variables.trans_alloc_block_size,
@@ -431,7 +431,7 @@ THD::~THD()
dbug_sentry= THD_SENTRY_GONE;
#endif
/* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */
- clear_alloc_root(&stmt_backup.mem_root);
+ clear_alloc_root(&stmt_backup.main_mem_root);
DBUG_VOID_RETURN;
}
@@ -567,13 +567,14 @@ bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
{
DBUG_ENTER("convert_string");
size_s new_length= to_cs->mbmaxlen * from_length;
+ uint dummy_errors;
if (!(to->str= alloc(new_length+1)))
{
to->length= 0; // Safety fix
DBUG_RETURN(1); // EOM
}
to->length= copy_and_convert((char*) to->str, new_length, to_cs,
- from, from_length, from_cs);
+ from, from_length, from_cs, &dummy_errors);
to->str[to->length]=0; // Safety
DBUG_RETURN(0);
}
@@ -596,7 +597,8 @@ bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
{
- if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs))
+ uint dummy_errors;
+ if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
return TRUE;
/* If convert_buffer >> s copying is more efficient long term */
if (convert_buffer.alloced_length() >= convert_buffer.length() * 2 ||
@@ -1463,10 +1465,10 @@ void select_dumpvar::cleanup()
for memory root initialization.
*/
Item_arena::Item_arena(THD* thd)
- :free_list(0),
- state(INITIALIZED)
+ :free_list(0), mem_root(&main_mem_root),
+ state(INITIALIZED)
{
- init_sql_alloc(&mem_root,
+ init_sql_alloc(&main_mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
@@ -1489,11 +1491,11 @@ Item_arena::Item_arena(THD* thd)
statements.
*/
Item_arena::Item_arena(bool init_mem_root)
- :free_list(0),
+ :free_list(0), mem_root(&main_mem_root),
state(CONVENTIONAL_EXECUTION)
{
if (init_mem_root)
- init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
}
@@ -1624,14 +1626,14 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
void Item_arena::set_item_arena(Item_arena *set)
{
- mem_root= set->mem_root;
+ mem_root= set->mem_root;
free_list= set->free_list;
state= set->state;
}
Statement::~Statement()
{
- free_root(&mem_root, MYF(0));
+ free_root(&main_mem_root, MYF(0));
}
C_MODE_START
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 0da77d5636a..f820f8b9cb9 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -515,7 +515,8 @@ public:
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
- MEM_ROOT mem_root;
+ MEM_ROOT main_mem_root;
+ MEM_ROOT *mem_root; // Pointer to current memroot
#ifndef DBUG_OFF
bool backup_arena;
#endif
@@ -557,24 +558,24 @@ public:
{ return state == PREPARED || state == EXECUTED; }
inline bool is_conventional() const
{ return state == CONVENTIONAL_EXECUTION; }
- inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
+ inline gptr alloc(unsigned int size) { return alloc_root(mem_root,size); }
inline gptr calloc(unsigned int size)
{
gptr ptr;
- if ((ptr=alloc_root(&mem_root,size)))
+ if ((ptr=alloc_root(mem_root,size)))
bzero((char*) ptr,size);
return ptr;
}
inline char *strdup(const char *str)
- { return strdup_root(&mem_root,str); }
+ { return strdup_root(mem_root,str); }
inline char *strmake(const char *str, uint size)
- { return strmake_root(&mem_root,str,size); }
+ { return strmake_root(mem_root,str,size); }
inline char *memdup(const char *str, uint size)
- { return memdup_root(&mem_root,str,size); }
+ { return memdup_root(mem_root,str,size); }
inline char *memdup_w_gap(const char *str, uint size, uint gap)
{
gptr ptr;
- if ((ptr=alloc_root(&mem_root,size+gap)))
+ if ((ptr=alloc_root(mem_root,size+gap)))
memcpy(ptr,str,size);
return ptr;
}
@@ -1171,11 +1172,26 @@ public:
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
+ inline Item_arena *change_arena_if_needed(Item_arena *backup)
+ {
+ /*
+ use new arena if we are in a prepared statements and we have not
+ already changed to use this arena.
+ */
+ if (!current_arena->is_conventional() &&
+ mem_root != &current_arena->main_mem_root)
+ {
+ set_n_backup_item_arena(current_arena, backup);
+ return current_arena;
+ }
+ return 0;
+ }
+
void change_item_tree(Item **place, Item *new_value)
{
/* TODO: check for OOM condition here */
if (!current_arena->is_conventional())
- nocheck_register_item_tree_change(place, *place, &mem_root);
+ nocheck_register_item_tree_change(place, *place, mem_root);
*place= new_value;
}
void nocheck_register_item_tree_change(Item **place, Item *old_value,
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 982ad4a34a9..7a100d05b93 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -724,7 +724,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0)
goto err;
if (!(copy_of_path= thd->memdup(newpath, length+1)) ||
- !(dir= new (&thd->mem_root) String(copy_of_path, length,
+ !(dir= new (thd->mem_root) String(copy_of_path, length,
&my_charset_bin)) ||
raid_dirs.push_back(dir))
goto err;
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index c09bfe0aea8..3fbefdd37ef 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -133,11 +133,11 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
The following code is here to change the allocation to not
use the thd->mem_root, which is freed after each query
*/
- MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
- my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root);
+ MEM_ROOT *old_root= thd->mem_root;
+ thd->mem_root= &thd->warn_root;
if ((err= new MYSQL_ERROR(thd, code, level, msg)))
thd->warn_list.push_back(err);
- my_pthread_setspecific_ptr(THR_MALLOC, old_root);
+ thd->mem_root= old_root;
}
thd->warn_count[(uint) level]++;
thd->total_warn_count++;
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index b349a09e49e..b3d7bebe96a 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -126,7 +126,7 @@ void memorize_variant_topic(THD *thd, TABLE *topics, int count,
String *name, String *description, String *example)
{
DBUG_ENTER("memorize_variant_topic");
- MEM_ROOT *mem_root= &thd->mem_root;
+ MEM_ROOT *mem_root= thd->mem_root;
if (count==0)
{
get_field(mem_root,find_fields[help_topic_name].field, name);
@@ -137,7 +137,7 @@ void memorize_variant_topic(THD *thd, TABLE *topics, int count,
{
if (count == 1)
names->push_back(name);
- String *new_name= new (&thd->mem_root) String;
+ String *new_name= new (thd->mem_root) String;
get_field(mem_root,find_fields[help_topic_name].field,new_name);
names->push_back(new_name);
}
@@ -350,8 +350,8 @@ int search_categories(THD *thd, TABLE *categories,
{
if (select && !select->cond->val_int())
continue;
- String *lname= new (&thd->mem_root) String;
- get_field(&thd->mem_root,pfname,lname);
+ String *lname= new (thd->mem_root) String;
+ get_field(thd->mem_root,pfname,lname);
if (++count == 1 && res_id)
*res_id= (int16) pcat_id->val_int();
names->push_back(lname);
@@ -384,8 +384,8 @@ void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname,
{
if (!select->cond->val_int())
continue;
- String *name= new (&thd->mem_root) String();
- get_field(&thd->mem_root,pfname,name);
+ String *name= new (thd->mem_root) String();
+ get_field(thd->mem_root,pfname,name);
res->push_back(name);
}
end_read_record(&read_record_info);
@@ -638,7 +638,7 @@ int mysqld_help(THD *thd, const char *mask)
String name, description, example;
int res, count_topics, count_categories, error;
uint mlen= strlen(mask);
- MEM_ROOT *mem_root= &thd->mem_root;
+ MEM_ROOT *mem_root= thd->mem_root;
if ((res= open_and_lock_tables(thd, tables)))
goto end;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index b0115dcdb17..6e0260d1acb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -211,7 +211,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
{
/* it should be allocated before Item::fix_fields() */
table->insert_values=
- (byte *)alloc_root(&thd->mem_root, table->rec_buff_length);
+ (byte *)alloc_root(thd->mem_root, table->rec_buff_length);
if (!table->insert_values)
goto abort;
}
@@ -1124,7 +1124,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
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)))
+ 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]
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3cbfd96b6aa..86219abc632 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -178,11 +178,8 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->trg_table= NULL;
lex->proc_list.first= 0;
- extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
- hash_free(&lex->spfuns);
- hash_init(&lex->spfuns, system_charset_info, 0, 0, 0,
- sp_lex_spfuns_key, 0, 0);
-
+ if (lex->spfuns.records)
+ hash_reset(&lex->spfuns);
}
void lex_end(LEX *lex)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 2bdc35f35cb..c8b4faa47c2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -758,7 +758,8 @@ typedef struct st_lex
st_lex() :result(0)
{
- bzero((char *)&spfuns, sizeof(spfuns));
+ extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
+ hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_spfuns_key, 0, 0);
}
~st_lex()
diff --git a/sql/sql_list.h b/sql/sql_list.h
index d8d3719d39d..141742c3d4a 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -113,6 +113,16 @@ public:
}
return 1;
}
+ inline bool push_back(void *info, MEM_ROOT *mem_root)
+ {
+ if (((*last)=new (mem_root) list_node(info, &end_of_list)))
+ {
+ last= &(*last)->next;
+ elements++;
+ return 0;
+ }
+ return 1;
+ }
inline bool push_front(void *info)
{
list_node *node=new list_node(info,first);
@@ -284,6 +294,8 @@ public:
inline List() :base_list() {}
inline List(const List<T> &tmp) :base_list(tmp) {}
inline bool push_back(T *a) { return base_list::push_back(a); }
+ inline bool push_back(T *a, MEM_ROOT *mem_root)
+ { return base_list::push_back(a, mem_root); }
inline bool push_front(T *a) { return base_list::push_front(a); }
inline T* head() {return (T*) base_list::head(); }
inline T** head_ref() {return (T**) base_list::head_ref(); }
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3ac6d8ccbd7..a14a3da8391 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -899,18 +899,20 @@ static int check_connection(THD *thd)
/* Since 4.1 all database names are stored in utf8 */
if (db)
{
+ uint dummy_errors;
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
system_charset_info,
db, strlen(db),
- thd->charset())]= 0;
+ thd->charset(), &dummy_errors)]= 0;
db= db_buff;
}
if (user)
{
+ uint dummy_errors;
user_buff[copy_and_convert(user_buff, sizeof(user_buff)-1,
system_charset_info, user, strlen(user),
- thd->charset())]= '\0';
+ thd->charset(), &dummy_errors)]= '\0';
user= user_buff;
}
@@ -1144,14 +1146,14 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
{
thd->net.error = 0;
close_thread_tables(thd); // Free tables
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
break;
}
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
break;
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
}
@@ -1412,9 +1414,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
/* Convert database name to utf8 */
+ uint dummy_errors;
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
system_charset_info, db, strlen(db),
- thd->charset())]= 0;
+ thd->charset(), &dummy_errors)]= 0;
db= db_buff;
/* Save user and privileges */
@@ -1856,7 +1859,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_RETURN(error);
}
@@ -2141,15 +2144,19 @@ mysql_execute_command(THD *thd)
query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) :
pstr->length();
- if (!(query_str= alloc_root(&thd->mem_root, query_len+1)))
+ if (!(query_str= alloc_root(thd->mem_root, query_len+1)))
{
res= -1;
break; // EOM (error should be reported by allocator)
}
if (need_conversion)
- query_len= copy_and_convert(query_str, query_len, to_cs, pstr->ptr(),
- pstr->length(), pstr->charset());
+ {
+ uint dummy_errors;
+ query_len= copy_and_convert(query_str, query_len, to_cs,
+ pstr->ptr(), pstr->length(),
+ pstr->charset(), &dummy_errors);
+ }
else
memcpy(query_str, pstr->ptr(), pstr->length());
query_str[query_len]= 0;
@@ -2716,6 +2723,7 @@ unsent_create_error:
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error(); // No binlog error generated
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -2745,6 +2753,7 @@ unsent_create_error:
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error(); // No binlog error generated
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -2767,6 +2776,7 @@ unsent_create_error:
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error(); // No binlog error generated
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -4479,8 +4489,8 @@ mysql_init_select(LEX *lex)
bool
mysql_new_select(LEX *lex, bool move_down)
{
- SELECT_LEX *select_lex = new(&lex->thd->mem_root) SELECT_LEX();
- if (!select_lex)
+ SELECT_LEX *select_lex;
+ if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
return 1;
select_lex->select_number= ++lex->thd->select_number;
select_lex->init_query();
@@ -4489,9 +4499,10 @@ mysql_new_select(LEX *lex, bool move_down)
if (move_down)
{
/* first select_lex of subselect or derived table */
- SELECT_LEX_UNIT *unit= new(&lex->thd->mem_root) SELECT_LEX_UNIT();
- if (!unit)
+ SELECT_LEX_UNIT *unit;
+ if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
return 1;
+
unit->init_query();
unit->init_select();
unit->thd= lex->thd;
@@ -4518,7 +4529,8 @@ mysql_new_select(LEX *lex, bool move_down)
as far as we included SELECT_LEX for UNION unit should have
fake SELECT_LEX for UNION processing
*/
- fake= unit->fake_select_lex= new(&lex->thd->mem_root) SELECT_LEX();
+ if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
+ return 1;
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 3b6aa7594f1..1c23162b212 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -171,8 +171,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
(stmt->param_count &&
stmt->thd->protocol_simple.send_fields((List<Item> *)
&stmt->lex->param_list,
- Protocol::SEND_EOF)) ||
- net_flush(net));
+ Protocol::SEND_EOF)));
}
#else
static bool send_prep_stmt(Prepared_statement *stmt,
@@ -1072,7 +1071,7 @@ static int mysql_test_select(Prepared_statement *stmt,
DBUG_RETURN(1);
#endif
- if (!lex->result && !(lex->result= new (&stmt->mem_root) select_send))
+ if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
{
send_error(thd);
goto err;
@@ -1098,7 +1097,7 @@ static int mysql_test_select(Prepared_statement *stmt,
{
if (lex->describe)
{
- if (send_prep_stmt(stmt, 0))
+ if (send_prep_stmt(stmt, 0) || thd->protocol->flush())
goto err_prep;
}
else
@@ -1116,11 +1115,8 @@ static int mysql_test_select(Prepared_statement *stmt,
prepared in unit->prepare call above.
*/
if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
- lex->result->send_fields(fields, Protocol::SEND_EOF)
-#ifndef EMBEDDED_LIBRARY
- || net_flush(&thd->net)
-#endif
- )
+ lex->result->send_fields(fields, Protocol::SEND_EOF) ||
+ thd->protocol->flush())
goto err_prep;
}
}
@@ -1407,7 +1403,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
enum enum_sql_command sql_command= lex->sql_command;
int res= 0;
DBUG_ENTER("send_prepare_results");
-
DBUG_PRINT("enter",("command: %d, param_count: %ld",
sql_command, stmt->param_count));
@@ -1472,6 +1467,7 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
break;
case SQLCOM_INSERT_SELECT:
+ case SQLCOM_REPLACE_SELECT:
res= mysql_test_insert_select(stmt, tables);
break;
@@ -1510,7 +1506,8 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
goto error;
}
if (res == 0)
- DBUG_RETURN(text_protocol? 0 : send_prep_stmt(stmt, 0));
+ DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) ||
+ thd->protocol->flush()));
error:
if (res < 0)
send_error(thd,thd->killed_errno());
@@ -1540,7 +1537,7 @@ static bool init_param_array(Prepared_statement *stmt)
List_iterator<Item_param> param_iterator(lex->param_list);
/* Use thd->mem_root as it points at statement mem_root */
stmt->param_array= (Item_param **)
- alloc_root(&stmt->thd->mem_root,
+ alloc_root(stmt->thd->mem_root,
sizeof(Item_param*) * stmt->param_count);
if (!stmt->param_array)
{
@@ -1606,7 +1603,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
if (name)
{
stmt->name.length= name->length;
- if (!(stmt->name.str= memdup_root(&stmt->mem_root, (char*)name->str,
+ if (!(stmt->name.str= memdup_root(stmt->mem_root, (char*)name->str,
name->length)))
{
delete stmt;
@@ -1850,7 +1847,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
DBUG_PRINT("info",("Using READ_ONLY cursor"));
if (!stmt->cursor &&
- !(stmt->cursor= new (&stmt->mem_root) Cursor()))
+ !(stmt->cursor= new (&stmt->main_mem_root) Cursor()))
{
send_error(thd, ER_OUT_OF_RESOURCES);
DBUG_VOID_RETURN;
@@ -2035,7 +2032,12 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
/*
COM_FETCH handler: fetches requested amount of rows from cursor
+
SYNOPSIS
+ mysql_stmt_fetch()
+ thd Thread handler
+ packet Packet from client (with stmt_id & num_rows)
+ packet_length Length of packet
*/
void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
@@ -2045,7 +2047,6 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
ulong num_rows= uint4korr(packet+=4);
Statement *stmt;
int error;
-
DBUG_ENTER("mysql_stmt_fetch");
thd->current_arena= stmt;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 18ffb7079c8..85feea3d51a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1652,9 +1652,13 @@ Cursor::init_from_thd(THD *thd)
/*
We need to save and reset thd->mem_root, otherwise it'll be freed
later in mysql_parse.
+
+ We can't just change the thd->mem_root here as we want to keep the things
+ that is already allocated in thd->mem_root for Cursor::fetch()
*/
- mem_root= thd->mem_root;
- init_sql_alloc(&thd->mem_root,
+ main_mem_root= *thd->mem_root;
+ /* Allocate new memory root for thd */
+ init_sql_alloc(thd->mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
@@ -1668,7 +1672,7 @@ Cursor::init_from_thd(THD *thd)
open_tables= thd->open_tables;
lock= thd->lock;
query_id= thd->query_id;
- free_list= thd->free_list;
+ free_list= thd->free_list;
reset_thd(thd);
/*
XXX: thd->locked_tables is not changed.
@@ -1769,15 +1773,15 @@ int
Cursor::fetch(ulong num_rows)
{
THD *thd= join->thd;
- JOIN_TAB *join_tab= join->join_tab + join->const_tables;;
+ JOIN_TAB *join_tab= join->join_tab + join->const_tables;
COND *on_expr= *join_tab->on_expr_ref;
COND *select_cond= join_tab->select_cond;
READ_RECORD *info= &join_tab->read_record;
-
int error= 0;
/* save references to memory, allocated during fetch */
thd->set_n_backup_item_arena(this, &thd->stmt_backup);
+
join->fetch_limit+= num_rows;
/*
@@ -1841,6 +1845,7 @@ Cursor::fetch(ulong num_rows)
if (thd->net.report_error)
error= -1;
+
if (error == -3) /* LIMIT clause worked */
error= 0;
@@ -1871,7 +1876,7 @@ Cursor::fetch(ulong num_rows)
/* free cursor memory */
free_items(free_list);
free_list= 0;
- free_root(&mem_root, MYF(0));
+ free_root(&main_mem_root, MYF(0));
}
return error;
}
@@ -1923,7 +1928,7 @@ Cursor::~Cursor()
Must be last, as some memory might be allocated for free purposes,
like in free_tmp_table() (TODO: fix this issue)
*/
- free_root(&mem_root, MYF(0));
+ free_root(&main_mem_root, MYF(0));
}
/*********************************************************************/
@@ -5002,7 +5007,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
{
tmp= new Item_func_trig_cond(tmp, &tab->found);
}
- if (!tmp)
+ if (tmp)
tmp->quick_fix_field();
return tmp;
}
@@ -5276,8 +5281,17 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
/* Join with outer join condition */
COND *orig_cond=sel->cond;
sel->cond= and_conds(sel->cond, *tab->on_expr_ref);
+
+ /*
+ We can't call sel->cond->fix_fields,
+ as it will break tab->on_expr if it's AND condition
+ (fix_fields currently removes extra AND/OR levels).
+ Yet attributes of the just built condition are not needed.
+ Thus we call sel->cond->quick_fix_field for safety.
+ */
if (sel->cond && !sel->cond->fixed)
- sel->cond->fix_fields(join->thd, 0, &sel->cond);
+ sel->cond->quick_fix_field();
+
if (sel->test_quick_select(join->thd, tab->keys,
used_tables & ~ current_map,
(join->select_options &
@@ -7474,7 +7488,7 @@ static 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);
if (new_field)
{
if (modify_item)
@@ -8077,7 +8091,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!using_unique_constraint)
{
group->buff=(char*) group_buff;
- if (!(group->field=field->new_field(&thd->mem_root,table)))
+ if (!(group->field=field->new_field(thd->mem_root,table)))
goto err; /* purecov: inspected */
if (maybe_null)
{
@@ -11675,7 +11689,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);
char *tmp=(char*) sql_alloc(field->pack_length()+1);
if (!tmp)
goto err;
@@ -12122,7 +12136,7 @@ bool JOIN::rollup_init()
return 1;
rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts);
ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);
- rollup.item_null= new (&thd->mem_root) Item_null();
+ rollup.item_null= new (thd->mem_root) Item_null();
/*
Prepare space for field list for the different levels
diff --git a/sql/sql_select.h b/sql/sql_select.h
index d489e911363..e1bf60f6896 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -426,7 +426,7 @@ class store_key :public Sql_alloc
field_arg->table, field_arg->charset());
else
{
- to_field=field_arg->new_field(&thd->mem_root,field_arg->table);
+ to_field=field_arg->new_field(thd->mem_root,field_arg->table);
if (to_field)
to_field->move_field(ptr, (uchar*) null, 1);
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 28e9baa1c36..557ec1bd5d2 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -804,8 +804,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
String def(tmp1,sizeof(tmp1), system_charset_info);
type.set(tmp, sizeof(tmp), field->charset());
field->val_str(&type);
+ uint dummy_errors;
def.copy(type.ptr(), type.length(), type.charset(),
- system_charset_info);
+ system_charset_info, &dummy_errors);
protocol->store(def.ptr(), def.length(), def.charset());
}
else if (field->unireg_check == Field::NEXT_NUMBER ||
@@ -1177,7 +1178,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
Protocol::SEND_EOF))
DBUG_VOID_RETURN;
- net_flush(&thd->net);
+ thd->protocol->flush();
DBUG_VOID_RETURN;
}
@@ -1194,13 +1195,11 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
if (store_create_info(thd, table, packet))
DBUG_RETURN(-1);
- //if (protocol->convert)
- // protocol->convert->convert((char*) packet->ptr(), packet->length());
if (fd < 0)
{
if (protocol->write())
DBUG_RETURN(-1);
- net_flush(&thd->net);
+ protocol->flush();
}
else
{
@@ -1436,9 +1435,10 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (type.length())
{
String def_val;
+ uint dummy_errors;
/* convert to system_charset_info == utf8 */
def_val.copy(type.ptr(), type.length(), field->charset(),
- system_charset_info);
+ system_charset_info, &dummy_errors);
append_unescaped(packet, def_val.ptr(), def_val.length());
}
else
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 7d0dd3ca566..69b530911f4 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -121,12 +121,13 @@ bool String::set(ulonglong num, CHARSET_INFO *cs)
bool String::set(double num,uint decimals, CHARSET_INFO *cs)
{
char buff[331];
+ uint dummy_errors;
str_charset=cs;
if (decimals >= NOT_FIXED_DEC)
{
uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME
- return copy(buff, len, &my_charset_latin1, cs);
+ return copy(buff, len, &my_charset_latin1, cs, &dummy_errors);
}
#ifdef HAVE_FCONVERT
int decpt,sign;
@@ -141,7 +142,8 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs)
buff[0]='-';
pos=buff;
}
- return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs);
+ uint dummy_errors;
+ return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors);
}
if (alloc((uint32) ((uint32) decpt+3+decimals)))
return TRUE;
@@ -191,7 +193,8 @@ end:
#else
sprintf(buff,"%.*f",(int) decimals,num);
#endif
- return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs);
+ return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs,
+ &dummy_errors);
#endif
}
@@ -336,14 +339,12 @@ bool String::copy(const char *str, uint32 arg_length,
uint32 offset;
if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
{
- if (errors)
- *errors= 0;
+ *errors= 0;
return copy(str, arg_length, to_cs);
}
if ((from_cs == &my_charset_bin) && offset)
{
- if (errors)
- *errors= 0;
+ *errors= 0;
return copy_aligned(str, arg_length, offset, to_cs);
}
uint32 new_length= to_cs->mbmaxlen*arg_length;
@@ -382,7 +383,8 @@ bool String::set_ascii(const char *str, uint32 arg_length)
set(str, arg_length, str_charset);
return 0;
}
- return copy(str, arg_length, &my_charset_latin1, str_charset);
+ uint dummy_errors;
+ return copy(str, arg_length, &my_charset_latin1, str_charset, &dummy_errors);
}
@@ -436,10 +438,12 @@ bool String::append(const char *s,uint32 arg_length)
if (str_charset->mbminlen > 1)
{
uint32 add_length=arg_length * str_charset->mbmaxlen;
+ uint dummy_errors;
if (realloc(str_length+ add_length))
return TRUE;
str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
- s, arg_length, &my_charset_latin1);
+ s, arg_length, &my_charset_latin1,
+ &dummy_errors);
return FALSE;
}
@@ -476,10 +480,11 @@ bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs)
if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
{
uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
+ uint dummy_errors;
if (realloc(str_length + add_length))
return TRUE;
str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
- s, arg_length, cs);
+ s, arg_length, cs, &dummy_errors);
}
else
{
@@ -829,8 +834,7 @@ outp:
else
break;
}
- if (errors)
- *errors= error_count;
+ *errors= error_count;
return (uint32) (to - to_start);
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index d6807fa83ad..cb5b1fb25fd 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -29,7 +29,7 @@ int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length,
- CHARSET_INFO *from_cs, uint *errors= 0);
+ CHARSET_INFO *from_cs, uint *errors);
class String
{
@@ -199,7 +199,7 @@ public:
CHARSET_INFO *cs);
bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
- CHARSET_INFO *csto, uint *errors= 0);
+ CHARSET_INFO *csto, uint *errors);
bool append(const String &s);
bool append(const char *s);
bool append(const char *s,uint32 arg_length);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 26c483a61a8..e73bf81eb74 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1401,7 +1401,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
create_info, *extra_fields, *keys, 0,
select_field_count))
{
- if (!(table= open_table(thd, create_table, &thd->mem_root, (bool*) 0)))
+ if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0)))
quick_rm_table(create_info->db_type, create_table->db,
table_case_name(create_info, create_table->real_name));
}
@@ -1740,6 +1740,12 @@ end:
}
+/*
+ RETURN VALUES
+ 0 Message sent to net (admin operation went ok)
+ -1 Message should be sent by caller
+ (admin operation or network communication failed)
+*/
static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT* check_opt,
const char *operator_name,
@@ -1787,9 +1793,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (prepare_func)
{
switch ((*prepare_func)(thd, table, check_opt)) {
- case 1: continue; // error, message written to net
- case -1: goto err; // error, message could be written to net
- default: ; // should be 0 otherwise
+ case 1: // error, message written to net
+ close_thread_tables(thd);
+ continue;
+ case -1: // error, message could be written to net
+ goto err;
+ default: // should be 0 otherwise
+ ;
}
}
@@ -3067,7 +3077,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
bzero((void*) &tbl, sizeof(tbl));
tbl.db= new_db;
tbl.real_name= tbl.alias= tmp_name;
- new_table= open_table(thd, &tbl, &thd->mem_root, 0);
+ new_table= open_table(thd, &tbl, thd->mem_root, 0);
}
else
{
@@ -3506,6 +3516,8 @@ int mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
create_info.db_type=DB_TYPE_DEFAULT;
create_info.row_type=ROW_TYPE_DEFAULT;
create_info.default_table_charset=default_charset_info;
+ /* Force alter table to recreate table */
+ lex->alter_info.flags= ALTER_CHANGE_COLUMN;
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
table_list, lex->create_list,
lex->key_list, 0, (ORDER *) 0,
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 17f3bc48678..5d175be74e1 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -134,7 +134,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
TABLE *table= tables->table;
char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
LEX_STRING dir, file;
- MEM_ROOT *old_global_root;
LEX_STRING *trg_def, *name;
List_iterator_fast<LEX_STRING> it(names_list);
@@ -168,9 +167,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
triggers_file_ext, NullS) - file_buff;
file.str= file_buff;
- old_global_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
- my_pthread_setspecific_ptr(THR_MALLOC, &table->mem_root);
-
/*
Soon we will invalidate table object and thus Table_triggers_list object
so don't care about place to which trg_def->ptr points and other
@@ -181,17 +177,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
*/
if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
sizeof(LEX_STRING))) ||
- definitions_list.push_back(trg_def))
- {
- my_pthread_setspecific_ptr(THR_MALLOC, old_global_root);
+ definitions_list.push_back(trg_def, &table->mem_root))
return 1;
- }
trg_def->str= thd->query;
trg_def->length= thd->query_length;
- my_pthread_setspecific_ptr(THR_MALLOC, old_global_root);
-
return sql_create_definition_file(&dir, &file, &triggers_file_type,
(gptr)this, triggers_file_parameters, 3);
}
@@ -302,7 +293,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
char path_buff[FN_REFLEN];
LEX_STRING path;
File_parser *parser;
- MEM_ROOT *old_global_mem_root;
DBUG_ENTER("Table_triggers_list::check_n_load");
@@ -406,14 +396,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
trg_name_str->str= trg_name_buff;
trg_name_str->length= lex.name_and_length.length;
- old_global_mem_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
- my_pthread_setspecific_ptr(THR_MALLOC, &table->mem_root);
-
- if (triggers->names_list.push_back(trg_name_str))
+ if (triggers->names_list.push_back(trg_name_str, &table->mem_root))
goto err_with_lex_cleanup;
- my_pthread_setspecific_ptr(THR_MALLOC, old_global_mem_root);
-
lex_end(&lex);
}
thd->lex= old_lex;
@@ -431,7 +416,8 @@ err_with_lex_cleanup:
We don't care about this error message much because .TRG files will
be merged into .FRM anyway.
*/
- my_error(ER_WRONG_OBJECT, MYF(0), table_name, triggers_file_ext, "TRIGGER");
+ my_error(ER_WRONG_OBJECT, MYF(0), table_name, triggers_file_ext,
+ "TRIGGER");
DBUG_RETURN(1);
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 46f11683e4e..792e2cdf775 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -315,26 +315,23 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (!item_list.elements)
{
Field **field;
- Item_arena backup;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_item_arena(arena, &backup);
+ Item_arena *tmp_arena,backup;
+ tmp_arena= thd->change_arena_if_needed(&backup);
for (field= table->field; *field; field++)
{
Item_field *item= new Item_field(*field);
if (!item || item_list.push_back(item))
{
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
+ if (tmp_arena)
+ thd->restore_backup_item_arena(tmp_arena, &backup);
DBUG_RETURN(-1);
}
}
- if (arena)
+ if (tmp_arena)
+ thd->restore_backup_item_arena(tmp_arena, &backup);
+ if (arena->is_stmt_prepare())
{
- thd->restore_backup_item_arena(arena, &backup);
-
/* prepare fake select to initialize it correctly */
ulong options_tmp= init_prepare_fake_select_lex(thd);
/*
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index b37759cc256..760ada9cdbd 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -435,7 +435,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
DBUG_RETURN(-1);
}
- if (!(parser= sql_parse_prepare(&path, &thd->mem_root, 0)))
+ if (!(parser= sql_parse_prepare(&path, thd->mem_root, 0)))
DBUG_RETURN(1);
if (!parser->ok() ||
@@ -452,7 +452,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
TODO: read dependence list, too, to process cascade/restrict
TODO: special cascade/restrict procedure for alter?
*/
- if (parser->parse((gptr)view, &thd->mem_root,
+ if (parser->parse((gptr)view, thd->mem_root,
view_parameters + revision_number_position, 1))
{
DBUG_RETURN(thd->net.report_error? -1 : 0);
@@ -586,7 +586,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
TODO: when VIEWs will be stored in cache, table mem_root should
be used here
*/
- if (parser->parse((gptr)table, &thd->mem_root, view_parameters,
+ if (parser->parse((gptr)table, thd->mem_root, view_parameters,
required_view_parameters))
goto err;
@@ -607,7 +607,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
now Lex placed in statement memory
*/
- table->view= lex= thd->lex= (LEX*) new(&thd->mem_root) st_lex_local;
+ table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
lex_start(thd, (uchar*)table->query.str, table->query.length);
lex->select_lex.select_number= ++thd->select_number;
old_lex->derived_tables|= DERIVED_VIEW;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index c658d2ae016..309a9249d0e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1848,7 +1848,7 @@ sp_proc_stmt:
i->m_query.length= lex->ptr - sp->m_tmp_query;
else
i->m_query.length= lex->tok_end - sp->m_tmp_query;
- i->m_query.str= strmake_root(&YYTHD->mem_root,
+ i->m_query.str= strmake_root(YYTHD->mem_root,
(char *)sp->m_tmp_query,
i->m_query.length);
i->set_lex(lex);
@@ -4781,7 +4781,7 @@ opt_distinct:
|DISTINCT { $$ = 1; };
opt_gconcat_separator:
- /* empty */ { $$ = new (&YYTHD->mem_root) String(",",1,default_charset_info); }
+ /* empty */ { $$ = new (YYTHD->mem_root) String(",",1,default_charset_info); }
|SEPARATOR_SYM text_string { $$ = $2; };
@@ -5070,15 +5070,15 @@ key_list_or_empty:
key_usage_list2:
key_usage_list2 ',' ident
{ Select->
- interval_list.push_back(new (&YYTHD->mem_root) String((const char*) $3.str, $3.length,
+ interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length,
system_charset_info)); }
| ident
{ Select->
- interval_list.push_back(new (&YYTHD->mem_root) String((const char*) $1.str, $1.length,
+ interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length,
system_charset_info)); }
| PRIMARY_SYM
{ Select->
- interval_list.push_back(new (&YYTHD->mem_root) String("PRIMARY", 7,
+ interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7,
system_charset_info)); };
using_list:
@@ -6128,7 +6128,7 @@ opt_db:
wild:
/* empty */
| LIKE TEXT_STRING_sys
- { Lex->wild= new (&YYTHD->mem_root) String($2.str, $2.length,
+ { Lex->wild= new (YYTHD->mem_root) String($2.str, $2.length,
system_charset_info); };
opt_full:
@@ -6182,7 +6182,7 @@ opt_describe_column:
/* empty */ {}
| text_string { Lex->wild= $1; }
| ident
- { Lex->wild= new (&YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info); };
+ { Lex->wild= new (YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info); };
/* flush things */
@@ -6428,7 +6428,7 @@ text_literal:
text_string:
TEXT_STRING_literal
- { $$= new (&YYTHD->mem_root) String($1.str,$1.length,YYTHD->variables.collation_connection); }
+ { $$= new (YYTHD->mem_root) String($1.str,$1.length,YYTHD->variables.collation_connection); }
| HEX_NUM
{
Item *tmp = new Item_varbinary($1.str,$1.length);
@@ -7700,7 +7700,7 @@ column_list:
column_list_id:
ident
{
- String *new_str = new (&YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info);
+ String *new_str = new (YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info);
List_iterator <LEX_COLUMN> iter(Lex->columns);
class LEX_COLUMN *point;
LEX *lex=Lex;
diff --git a/sql/table.cc b/sql/table.cc
index 8c58c5296ad..0e8045abacf 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -83,13 +83,14 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
uchar *null_pos;
uint null_bit, new_frm_ver, field_pack_length;
SQL_CRYPT *crypted=0;
- MEM_ROOT *old_root;
+ MEM_ROOT **root_ptr, *old_root;
DBUG_ENTER("openfrm");
DBUG_PRINT("enter",("name: '%s' form: 0x%lx",name,outparam));
error=1;
disk_buff=NULL;
- old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
+ old_root= *root_ptr;
if ((file=my_open(fn_format(index_file, name, "", reg_ext,
MY_UNPACK_FILENAME),
@@ -123,7 +124,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
outparam->blob_ptr_size=sizeof(char*);
outparam->db_stat = db_stat;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
- my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
+ *root_ptr= &outparam->mem_root;
outparam->real_name=strdup_root(&outparam->mem_root,
name+dirname_length(name));
@@ -274,9 +275,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
#ifdef HAVE_CRYPTED_FRM
else if (*(head+26) == 2)
{
- my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ *root_ptr= old_root
crypted=get_crypt_for_frm();
- my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
+ *root_ptr= &outparam->mem_root;
outparam->crypted=1;
}
#endif
@@ -762,7 +763,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
}
outparam->db_low_byte_first=outparam->file->low_byte_first();
- my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ *root_ptr= old_root;
thd->status_var.opened_tables++;
#ifndef DBUG_OFF
if (use_hash)
@@ -782,7 +783,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
err_end: /* Here when no file */
delete crypted;
- my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ *root_ptr= old_root;
frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG);
delete outparam->file;
outparam->file=0; // For easier errorchecking
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index fa678ec7de2..3a9ca397bba 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -38,7 +38,7 @@ void init_sql_alloc(MEM_ROOT *mem_root, uint block_size, uint pre_alloc)
gptr sql_alloc(uint Size)
{
- MEM_ROOT *root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ MEM_ROOT *root= *my_pthread_getspecific_ptr(MEM_ROOT**,THR_MALLOC);
char *ptr= (char*) alloc_root(root,Size);
return ptr;
}
@@ -108,8 +108,11 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length,
memcpy(pos, str, new_length);
}
else
+ {
+ uint dummy_errors;
new_length= copy_and_convert((char*) pos, new_length, to_cs, str,
- arg_length, from_cs);
+ arg_length, from_cs, &dummy_errors);
+ }
pos[new_length]= 0;
*result_length= new_length;
return pos;