summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorserg@janus.mylan <>2007-03-06 13:44:57 +0100
committerserg@janus.mylan <>2007-03-06 13:44:57 +0100
commit6aa5c001c5debfedb044b4be455e0549de836409 (patch)
tree6633aa27d1875e982ecf73b0f605752dcadbc94f /sql
parent30321673a278025b40ee93b9b1c8e75f3dc89acb (diff)
parent2baf35b4fab1cd1c185b7b98645eb76ed88d9f73 (diff)
downloadmariadb-git-6aa5c001c5debfedb044b4be455e0549de836409.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into janus.mylan:/usr/home/serg/Abk/mysql-5.1
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc6
-rw-r--r--sql/ha_ndbcluster.cc35
-rw-r--r--sql/ha_ndbcluster_binlog.cc137
-rw-r--r--sql/ha_partition.cc30
-rw-r--r--sql/ha_partition.h6
-rw-r--r--sql/item.cc129
-rw-r--r--sql/item.h49
-rw-r--r--sql/item_cmpfunc.cc22
-rw-r--r--sql/item_cmpfunc.h8
-rw-r--r--sql/log.cc2
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/opt_range.cc4
-rw-r--r--sql/rpl_injector.h2
-rw-r--r--sql/sql_base.cc17
-rw-r--r--sql/sql_binlog.cc2
-rw-r--r--sql/sql_delete.cc6
-rw-r--r--sql/sql_help.cc2
-rw-r--r--sql/sql_insert.cc97
-rw-r--r--sql/sql_lex.cc3
-rw-r--r--sql/sql_lex.h8
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc98
-rw-r--r--sql/sql_table.cc8
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc5
-rw-r--r--sql/sql_yacc.yy13
28 files changed, 519 insertions, 201 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 867edc6f9dd..5d4dbe9a416 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6297,9 +6297,9 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
void Field_string::sort_string(char *to,uint length)
{
- uint tmp= my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) ptr, field_length);
+ IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
+ (uchar*) to, length,
+ (uchar*) ptr, field_length);
DBUG_ASSERT(tmp == length);
}
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 6766e9b990a..deb634581b0 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -2764,10 +2764,12 @@ int ha_ndbcluster::write_row(byte *record)
{
Ndb *ndb= get_ndb();
Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
+#ifndef DBUG_OFF
char buff[22];
DBUG_PRINT("info",
("Trying to set next auto increment value to %s",
llstr(next_val, buff)));
+#endif
Ndb_tuple_id_range_guard g(m_share);
if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE)
== -1)
@@ -3986,7 +3988,7 @@ int ha_ndbcluster::end_bulk_insert()
}
else
{
- int res= trans->restart();
+ IF_DBUG(int res=) trans->restart();
DBUG_ASSERT(res == 0);
}
}
@@ -4704,7 +4706,9 @@ static int create_ndb_column(NDBCOL &col,
// Set autoincrement
if (field->flags & AUTO_INCREMENT_FLAG)
{
+#ifndef DBUG_OFF
char buff[22];
+#endif
col.setAutoIncrement(TRUE);
ulonglong value= info->auto_increment_value ?
info->auto_increment_value : (ulonglong) 1;
@@ -5375,7 +5379,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
{
DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
share->key, share->use_count));
- int r= rename_share(share, to);
+ IF_DBUG(int r=) rename_share(share, to);
DBUG_ASSERT(r == 0);
}
#endif
@@ -5396,8 +5400,8 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
#ifdef HAVE_NDB_BINLOG
if (share)
{
- int r= rename_share(share, from);
- DBUG_ASSERT(r == 0);
+ IF_DBUG(int ret=) rename_share(share, from);
+ DBUG_ASSERT(ret == 0);
/* ndb_share reference temporary free */
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
share->key, share->use_count));
@@ -7255,7 +7259,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
if (share->commit_count != 0)
{
*commit_count= share->commit_count;
+#ifndef DBUG_OFF
char buff[22];
+#endif
DBUG_PRINT("info", ("Getting commit_count: %s from share",
llstr(share->commit_count, buff)));
pthread_mutex_unlock(&share->mutex);
@@ -7291,7 +7297,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
pthread_mutex_lock(&share->mutex);
if (share->commit_count_lock == lock)
{
+#ifndef DBUG_OFF
char buff[22];
+#endif
DBUG_PRINT("info", ("Setting commit_count to %s",
llstr(stat.commit_count, buff)));
share->commit_count= stat.commit_count;
@@ -7350,7 +7358,9 @@ ndbcluster_cache_retrieval_allowed(THD *thd,
bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
char *dbname= full_name;
char *tabname= dbname+strlen(dbname)+1;
+#ifndef DBUG_OFF
char buff[22], buff2[22];
+#endif
DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
dbname, tabname, is_autocommit));
@@ -7417,7 +7427,9 @@ ha_ndbcluster::register_query_cache_table(THD *thd,
ulonglong *engine_data)
{
Uint64 commit_count;
+#ifndef DBUG_OFF
char buff[22];
+#endif
bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d",
@@ -7862,7 +7874,9 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
int retries= 10;
int reterr= 0;
int retry_sleep= 30 * 1000; /* 30 milliseconds */
+#ifndef DBUG_OFF
char buff[22], buff2[22], buff3[22], buff4[22];
+#endif
DBUG_ENTER("ndb_get_table_statistics");
DBUG_PRINT("enter", ("table: %s", ndbtab->getName()));
@@ -8680,7 +8694,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
ndb_get_table_statistics(NULL, FALSE, ndb,
ndbtab_g.get_table(), &stat) == 0)
{
+#ifndef DBUG_OFF
char buff[22], buff2[22];
+#endif
DBUG_PRINT("info",
("Table: %s commit_count: %s rows: %s",
share->key,
@@ -9532,8 +9548,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("INT_ITEM"));
if (context->expecting(Item::INT_ITEM))
{
- Item_int *int_item= (Item_int *) item;
- DBUG_PRINT("info", ("value %ld", (long) int_item->value));
+ DBUG_PRINT("info", ("value %ld",
+ (long) ((Item_int*) item)->value));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::INT_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -9559,8 +9575,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("REAL_ITEM"));
if (context->expecting(Item::REAL_ITEM))
{
- Item_float *float_item= (Item_float *) item;
- DBUG_PRINT("info", ("value %f", float_item->value));
+ DBUG_PRINT("info", ("value %f", ((Item_float*) item)->value));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::REAL_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -9607,8 +9622,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("DECIMAL_ITEM"));
if (context->expecting(Item::DECIMAL_ITEM))
{
- Item_decimal *decimal_item= (Item_decimal *) item;
- DBUG_PRINT("info", ("value %f", decimal_item->val_real()));
+ DBUG_PRINT("info", ("value %f",
+ ((Item_decimal*) item)->val_real()));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::DECIMAL_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index ea5a2deaeb3..73363328078 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -1829,15 +1829,15 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
// fall through
case SOT_CREATE_TABLE:
pthread_mutex_lock(&LOCK_open);
- if (ndbcluster_check_if_local_table(schema->db, schema->name))
- {
- DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
- schema->db, schema->name));
+ if (ndbcluster_check_if_local_table(schema->db, schema->name))
+ {
+ DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
+ schema->db, schema->name));
sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from "
"binlog schema event '%s' from node %d. ",
schema->db, schema->name, schema->query,
schema->node_id);
- }
+ }
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
{
sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
@@ -1854,27 +1854,27 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
log_query= 1;
break;
case SOT_DROP_DB:
- /* Drop the database locally if it only contains ndb tables */
- if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db))
- {
- run_query(thd, schema->query,
- schema->query + schema->query_length,
- TRUE, /* print error */
- TRUE); /* don't binlog the query */
- /* binlog dropping database after any table operations */
- post_epoch_log_list->push_back(schema, mem_root);
- /* acknowledge this query _after_ epoch completion */
- post_epoch_unlock= 1;
- }
- else
- {
- /* Database contained local tables, leave it */
- sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables "
+ /* Drop the database locally if it only contains ndb tables */
+ if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db))
+ {
+ run_query(thd, schema->query,
+ schema->query + schema->query_length,
+ TRUE, /* print error */
+ TRUE); /* don't binlog the query */
+ /* binlog dropping database after any table operations */
+ post_epoch_log_list->push_back(schema, mem_root);
+ /* acknowledge this query _after_ epoch completion */
+ post_epoch_unlock= 1;
+ }
+ else
+ {
+ /* Database contained local tables, leave it */
+ sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables "
"binlog schema event '%s' from node %d. ",
schema->db, schema->query,
schema->node_id);
- log_query= 1;
- }
+ log_query= 1;
+ }
break;
case SOT_CREATE_DB:
/* fall through */
@@ -2121,18 +2121,18 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
share= 0;
}
pthread_mutex_lock(&LOCK_open);
- if (ndbcluster_check_if_local_table(schema->db, schema->name))
- {
- DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
- schema->db, schema->name));
+ if (ndbcluster_check_if_local_table(schema->db, schema->name))
+ {
+ DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
+ schema->db, schema->name));
sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from "
"binlog schema event '%s' from node %d. ",
schema->db, schema->name, schema->query,
schema->node_id);
- }
+ }
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
- {
- sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
+ {
+ sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
"binlog schema event '%s' from node %d. my_errno: %d",
schema->db, schema->name, schema->query,
schema->node_id, my_errno);
@@ -2260,7 +2260,7 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
{
TABLE_LIST *p_binlog_tables= &binlog_tables;
close_tables_for_reopen(thd, &p_binlog_tables);
- ndb_binlog_index= 0;
+ ndb_binlog_index= 0;
continue;
}
sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
@@ -3225,15 +3225,17 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- int ret= get_ndb_blobs_value(table, share->ndb_value[0],
- blobs_buffer[0], blobs_buffer_size[0],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ blobs_buffer[0],
+ blobs_buffer_size[0],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]);
- int ret= trans.write_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields, table->record[0]);
+ IF_DBUG(int ret=) trans.write_row(::server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields, table->record[0]);
DBUG_ASSERT(ret == 0);
}
break;
@@ -3251,27 +3253,29 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
n= 0; /*
use the primary key only as it save time and space and
it is the only thing needed to log the delete
- */
+ */
else
n= 1; /*
we use the before values since we don't have a primary key
since the mysql server does not handle the hidden primary
key
- */
+ */
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[n] - table->record[0];
- int ret= get_ndb_blobs_value(table, share->ndb_value[n],
- blobs_buffer[n], blobs_buffer_size[n],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[n],
+ blobs_buffer[n],
+ blobs_buffer_size[n],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]);
DBUG_EXECUTE("info", print_records(table, table->record[n]););
- int ret= trans.delete_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields, table->record[n]);
+ IF_DBUG(int ret =) trans.delete_row(::server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields, table->record[n]);
DBUG_ASSERT(ret == 0);
}
break;
@@ -3283,9 +3287,10 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- int ret= get_ndb_blobs_value(table, share->ndb_value[0],
- blobs_buffer[0], blobs_buffer_size[0],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ blobs_buffer[0],
+ blobs_buffer_size[0],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0],
@@ -3296,7 +3301,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/*
since table has a primary key, we can do a write
using only after values
- */
+ */
trans.write_row(::server_id, injector::transaction::table(table, TRUE),
&b, n_fields, table->record[0]);// after values
}
@@ -3305,22 +3310,24 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/*
mysql server cannot handle the ndb hidden key and
therefore needs the before image as well
- */
+ */
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[1] - table->record[0];
- int ret= get_ndb_blobs_value(table, share->ndb_value[1],
- blobs_buffer[1], blobs_buffer_size[1],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[1],
+ blobs_buffer[1],
+ blobs_buffer_size[1],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]);
DBUG_EXECUTE("info", print_records(table, table->record[1]););
- int ret= trans.update_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields,
- table->record[1], // before values
- table->record[0]);// after values
+ IF_DBUG(int ret =) trans.update_row(::server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields,
+ table->record[1], // before values
+ table->record[0]);// after values
DBUG_ASSERT(ret == 0);
}
}
@@ -3850,7 +3857,9 @@ restart:
continue;
}
TABLE *table= share->table;
+#ifndef DBUG_OFF
const LEX_STRING &name= table->s->table_name;
+#endif
if ((event_types & (NdbDictionary::Event::TE_INSERT |
NdbDictionary::Event::TE_UPDATE |
NdbDictionary::Event::TE_DELETE)) == 0)
@@ -3867,7 +3876,7 @@ restart:
}
DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
injector::transaction::table tbl(table, TRUE);
- int ret= trans.use_table(::server_id, tbl);
+ IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
}
}
@@ -3877,10 +3886,12 @@ restart:
{
TABLE *table= ndb_apply_status_share->table;
- const LEX_STRING& name=table->s->table_name;
+#ifndef DBUG_OFF
+ const LEX_STRING& name= table->s->table_name;
DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
+#endif
injector::transaction::table tbl(table, TRUE);
- int ret= trans.use_table(::server_id, tbl);
+ IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
// Set all fields non-null.
@@ -3945,7 +3956,7 @@ restart:
else
{
// set injector_ndb database/schema from table internal name
- int ret=
+ IF_DBUG(int ret=)
i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable());
DBUG_ASSERT(ret == 0);
ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, row);
@@ -3979,7 +3990,7 @@ restart:
/*
note! pOp is not referring to an event in the next epoch
or is == 0
- */
+ */
#ifdef RUN_NDB_BINLOG_TIMER
write_timer.stop();
#endif
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index d9f671c5412..670a3e10e0e 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -158,7 +158,7 @@ static uint alter_table_flags(uint flags __attribute__((unused)))
ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
:handler(hton, share), m_part_info(NULL), m_create_handler(FALSE),
- m_is_sub_partitioned(0)
+ m_is_sub_partitioned(0), is_clone(FALSE)
{
DBUG_ENTER("ha_partition::ha_partition(table)");
init_handler_variables();
@@ -180,8 +180,7 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
ha_partition::ha_partition(handlerton *hton, partition_info *part_info)
:handler(hton, NULL), m_part_info(part_info),
m_create_handler(TRUE),
- m_is_sub_partitioned(m_part_info->is_sub_partitioned())
-
+ m_is_sub_partitioned(m_part_info->is_sub_partitioned()), is_clone(FALSE)
{
DBUG_ENTER("ha_partition::ha_partition(part_info)");
init_handler_variables();
@@ -2262,9 +2261,12 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
}
/* Initialise the bitmap we use to determine what partitions are used */
- if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
- DBUG_RETURN(1);
- bitmap_set_all(&(m_part_info->used_partitions));
+ if (!is_clone)
+ {
+ if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
+ DBUG_RETURN(1);
+ bitmap_set_all(&(m_part_info->used_partitions));
+ }
/* Recalculate table flags as they may change after open */
m_table_flags= m_file[0]->table_flags();
@@ -2320,6 +2322,19 @@ err_handler:
DBUG_RETURN(error);
}
+handler *ha_partition::clone(MEM_ROOT *mem_root)
+{
+ handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type);
+ ((ha_partition*)new_handler)->m_part_info= m_part_info;
+ ((ha_partition*)new_handler)->is_clone= TRUE;
+ if (new_handler && !new_handler->ha_open(table,
+ table->s->normalized_path.str,
+ table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
+ return new_handler;
+ return NULL;
+}
+
/*
Close handler object
@@ -2346,7 +2361,8 @@ int ha_partition::close(void)
DBUG_ENTER("ha_partition::close");
delete_queue(&m_queue);
- bitmap_free(&(m_part_info->used_partitions));
+ if (!is_clone)
+ bitmap_free(&(m_part_info->used_partitions));
file= m_file;
repeat:
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index ad5d412a6d2..2d43e2b0df2 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -132,7 +132,13 @@ private:
THR_LOCK_DATA lock; /* MySQL lock */
PARTITION_SHARE *share; /* Shared lock info */
+ /*
+ TRUE <=> this object was created with ha_partition::clone and doesn't
+ "own" the m_part_info structure.
+ */
+ bool is_clone;
public:
+ handler *clone(MEM_ROOT *mem_root);
virtual void set_part_info(partition_info *part_info)
{
m_part_info= part_info;
diff --git a/sql/item.cc b/sql/item.cc
index d0691979c66..a01a68de783 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1639,7 +1639,7 @@ void Item_ident_for_show::make_field(Send_field *tmp_field)
Item_field::Item_field(Field *f)
:Item_ident(0, NullS, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(0), any_privileges(0), fixed_as_field(0)
{
set_field(f);
/*
@@ -1654,7 +1654,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
:Item_ident(context_arg, f->table->s->db.str, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(0), any_privileges(0), fixed_as_field(0)
{
/*
We always need to provide Item_field with a fully qualified field
@@ -1693,9 +1693,12 @@ Item_field::Item_field(Name_resolution_context *context_arg,
const char *field_name_arg)
:Item_ident(context_arg, db_arg,table_name_arg,field_name_arg),
field(0), result_field(0), item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(0), any_privileges(0), fixed_as_field(0)
{
+ SELECT_LEX *select= current_thd->lex->current_select;
collation.set(DERIVATION_IMPLICIT);
+ if (select && select->parsing_place != IN_HAVING)
+ select->select_n_where_fields++;
}
// Constructor need to process subselect with temporary tables (see Item)
@@ -1706,7 +1709,8 @@ Item_field::Item_field(THD *thd, Item_field *item)
item_equal(item->item_equal),
no_const_subst(item->no_const_subst),
have_privileges(item->have_privileges),
- any_privileges(item->any_privileges)
+ any_privileges(item->any_privileges),
+ fixed_as_field(item->fixed_as_field)
{
collation.set(DERIVATION_IMPLICIT);
}
@@ -3517,8 +3521,46 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
}
if (*from_field != view_ref_found)
{
+
prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
prev_subselect_item->const_item_cache= 0;
+ if (!last_checked_context->select_lex->having_fix_field &&
+ !fixed_as_field)
+ {
+ Item_outer_ref *rf;
+ Query_arena *arena= 0, backup;
+ /*
+ Each outer field is replaced for an Item_outer_ref object.
+ This is done in order to get correct results when the outer
+ select employs a temporary table.
+ The original fields are saved in the inner_fields_list of the
+ outer select. This list is created by the following reasons:
+ 1. We can't add field items to the outer select list directly
+ because the outer select hasn't been fully fixed yet.
+ 2. We need a location to refer to in the Item_ref object
+ so the inner_fields_list is used as such temporary
+ reference storage.
+ The new Item_outer_ref object replaces the original field and is
+ also saved in the inner_refs_list of the outer select. Here
+ it is only created. It can be fixed only after the original
+ field has been fixed and this is done in the fix_inner_refs()
+ function.
+ */
+ set_field(*from_field);
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+ rf= new Item_outer_ref(context, this);
+ if (!rf)
+ {
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ return -1;
+ }
+ *reference= rf;
+ select->inner_refs_list.push_back(rf);
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ fixed_as_field= 1;
+ }
if (thd->lex->in_sum_func &&
thd->lex->in_sum_func->nest_level ==
thd->lex->current_select->nest_level)
@@ -3646,7 +3688,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
- this, this);
+ this, (Item_ident*)*reference);
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -4895,6 +4937,51 @@ void Item_field::update_null_value()
}
+/*
+ Add the field to the select list and substitute it for the reference to
+ the field.
+
+ SYNOPSIS
+ Item_field::update_value_transformer()
+ select_arg current select
+
+ DESCRIPTION
+ If the field doesn't belong to the table being inserted into then it is
+ added to the select list, pointer to it is stored in the ref_pointer_array
+ of the select and the field itself is substituted for the Item_ref object.
+ This is done in order to get correct values from update fields that
+ belongs to the SELECT part in the INSERT .. SELECT .. ON DUPLICATE KEY
+ UPDATE statement.
+
+ RETURN
+ 0 if error occured
+ ref if all conditions are met
+ this field otherwise
+*/
+
+Item *Item_field::update_value_transformer(byte *select_arg)
+{
+ SELECT_LEX *select= (SELECT_LEX*)select_arg;
+ DBUG_ASSERT(fixed);
+
+ if (field->table != select->context.table_list->table &&
+ type() != Item::TRIGGER_FIELD_ITEM)
+ {
+ List<Item> *all_fields= &select->join->all_fields;
+ Item **ref_pointer_array= select->ref_pointer_array;
+ int el= all_fields->elements;
+ Item_ref *ref;
+
+ ref_pointer_array[el]= (Item*)this;
+ all_fields->push_front((Item*)this);
+ ref= new Item_ref(&select->context, ref_pointer_array + el,
+ table_name, field_name);
+ return ref;
+ }
+ return this;
+}
+
+
Item_ref::Item_ref(Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
const char *field_name_arg)
@@ -4904,8 +4991,7 @@ Item_ref::Item_ref(Name_resolution_context *context_arg,
/*
This constructor used to create some internals references over fixed items
*/
- DBUG_ASSERT(ref != 0);
- if (*ref && (*ref)->fixed)
+ if (ref && *ref && (*ref)->fixed)
set_properties();
}
@@ -5206,7 +5292,7 @@ void Item_ref::print(String *str)
if (ref)
{
if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF &&
- name && alias_name_used)
+ ref_type() != OUTER_REF && name && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, name, (uint) strlen(name));
@@ -5454,7 +5540,7 @@ bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
/*
- Prepare referenced view viewld then call usual Item_direct_ref::fix_fields
+ Prepare referenced field then call usual Item_direct_ref::fix_fields
SYNOPSIS
Item_direct_view_ref::fix_fields()
@@ -5478,6 +5564,31 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
}
/*
+ Prepare referenced outer field then call usual Item_direct_ref::fix_fields
+
+ SYNOPSIS
+ Item_outer_ref::fix_fields()
+ thd thread handler
+ reference reference on reference where this item stored
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
+{
+ DBUG_ASSERT(*ref);
+ /* outer_field->check_cols() will be made in Item_direct_ref::fix_fields */
+ outer_field->fixed_as_field= 1;
+ if (!outer_field->fixed &&
+ (outer_field->fix_fields(thd, reference)))
+ return TRUE;
+ table_name= outer_field->table_name;
+ return Item_direct_ref::fix_fields(thd, reference);
+}
+
+/*
Compare two view column references for equality.
SYNOPSIS
diff --git a/sql/item.h b/sql/item.h
index 09c118a2e14..be4636db91e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -325,10 +325,10 @@ private:
TABLE_LIST *save_first_name_resolution_table;
TABLE_LIST *save_next_name_resolution_table;
bool save_resolve_in_select_list;
+ TABLE_LIST *save_next_local;
public:
Name_resolution_context_state() {} /* Remove gcc warning */
- TABLE_LIST *save_next_local;
public:
/* Save the state of a name resolution context. */
@@ -350,6 +350,11 @@ public:
context->first_name_resolution_table= save_first_name_resolution_table;
context->resolve_in_select_list= save_resolve_in_select_list;
}
+
+ TABLE_LIST *get_first_name_resolution_table()
+ {
+ return save_first_name_resolution_table;
+ }
};
@@ -912,6 +917,7 @@ public:
virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
+ virtual Item *update_value_transformer(byte *select_arg) { return this; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
void delete_self()
{
@@ -1311,7 +1317,7 @@ public:
uint have_privileges;
/* field need any privileges (for VIEW creation) */
bool any_privileges;
-
+ bool fixed_as_field;
Item_field(Name_resolution_context *context_arg,
const char *db_arg,const char *table_name_arg,
const char *field_name_arg);
@@ -1391,6 +1397,7 @@ public:
Item_field *filed_for_view_update() { return this; }
Item *safe_charset_converter(CHARSET_INFO *tocs);
int fix_outer_field(THD *thd, Field **field, Item **reference);
+ virtual Item *update_value_transformer(byte *select_arg);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -1921,7 +1928,7 @@ class Item_ref :public Item_ident
protected:
void set_properties();
public:
- enum Ref_Type { REF, DIRECT_REF, VIEW_REF };
+ enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF };
Field *result_field; /* Save result here */
Item **ref;
Item_ref(Name_resolution_context *context_arg,
@@ -1982,7 +1989,7 @@ public:
(*ref)->get_tmp_table_item(thd));
}
table_map used_tables() const
- {
+ {
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
table_map not_null_tables() const { return (*ref)->not_null_tables(); }
@@ -2055,6 +2062,40 @@ public:
};
+class Item_outer_ref :public Item_direct_ref
+{
+public:
+ Item_field *outer_field;
+ Item_outer_ref(Name_resolution_context *context_arg,
+ Item_field *outer_field_arg)
+ :Item_direct_ref(context_arg, 0, outer_field_arg->table_name,
+ outer_field_arg->field_name),
+ outer_field(outer_field_arg)
+ {
+ ref= (Item**)&outer_field;
+ set_properties();
+ fixed= 0;
+ }
+ void cleanup()
+ {
+ ref= (Item**)&outer_field;
+ fixed= 0;
+ Item_direct_ref::cleanup();
+ outer_field->cleanup();
+ }
+ void save_in_result_field(bool no_conversions)
+ {
+ outer_field->save_org_in_field(result_field);
+ }
+ bool fix_fields(THD *, Item **);
+ table_map used_tables() const
+ {
+ return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT;
+ }
+ virtual Ref_Type ref_type() { return OUTER_REF; }
+};
+
+
class Item_in_subselect;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 17da1174e37..415c91772fc 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2568,6 +2568,7 @@ void Item_func_in::fix_length_and_dec()
THD *thd= current_thd;
uint found_types= 0;
uint type_cnt= 0, i;
+ Item_result cmp_type= STRING_RESULT;
left_result_type= args[0]->result_type();
found_types= collect_cmp_types(args, arg_count);
@@ -2582,25 +2583,28 @@ void Item_func_in::fix_length_and_dec()
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & 1 << i)
+ {
(type_cnt)++;
+ cmp_type= (Item_result) i;
+ }
}
+
+ if (type_cnt == 1)
+ {
+ if (cmp_type == STRING_RESULT &&
+ agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ return;
+ arg_types_compatible= TRUE;
+ }
+
/*
Row item with NULLs inside can return NULL or FALSE =>
they can't be processed as static
*/
if (type_cnt == 1 && const_itm && !nulls_in_row())
{
- uint tmp_type;
- Item_result cmp_type;
- /* Only one cmp type was found. Extract it here */
- for (tmp_type= 0; found_types - 1; found_types>>= 1)
- tmp_type++;
- cmp_type= (Item_result)tmp_type;
-
switch (cmp_type) {
case STRING_RESULT:
- if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
- return;
array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 6186d4a78f8..08a411ae39a 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1045,12 +1045,18 @@ public:
*/
in_vector *array;
bool have_null;
+ /*
+ true when all arguments of the IN clause are of compatible types
+ and can be used safely as comparisons for key conditions
+ */
+ bool arg_types_compatible;
Item_result left_result_type;
cmp_item *cmp_items[5]; /* One cmp_item for each result type */
DTCollation cmp_collation;
Item_func_in(List<Item> &list)
- :Item_func_opt_neg(list), array(0), have_null(0)
+ :Item_func_opt_neg(list), array(0), have_null(0),
+ arg_types_compatible(FALSE)
{
bzero(&cmp_items, sizeof(cmp_items));
allowed_arg_cols= 0; // Fetch this value from first argument
diff --git a/sql/log.cc b/sql/log.cc
index 6e24a0b99ea..cf5b423f03e 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1742,7 +1742,7 @@ void setup_windows_event_source()
/* Register EventMessageFile */
dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
- (PBYTE) szPath, strlen(szPath)+1);
+ (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
/* Register supported event types */
dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index e3815c2b235..c215c8c9fdc 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -915,6 +915,8 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
+bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array);
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index f87439dd3eb..32c7b23ce35 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -4940,8 +4940,8 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
type. Tree won't be built for values with different result types,
so we check it here to avoid unnecessary work.
*/
- if (!func->array)
- break;
+ if (!func->arg_types_compatible)
+ break;
if (inv)
{
diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h
index 8b08c0672c9..61c2e0ecebc 100644
--- a/sql/rpl_injector.h
+++ b/sql/rpl_injector.h
@@ -284,12 +284,14 @@ public:
*/
int check_state(enum_state const target_state)
{
+#ifndef DBUG_OFF
static char const *state_name[] = {
"START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT"
};
DBUG_ASSERT(0 <= target_state && target_state <= STATE_COUNT);
DBUG_PRINT("info", ("In state %s", state_name[m_state]));
+#endif
if (m_state <= target_state && target_state <= m_state + 1 &&
m_state < STATE_COUNT)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 15d616bdd4f..02f7044a4bf 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -5465,21 +5465,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
uint tablenr= 0;
DBUG_ENTER("setup_tables");
- /*
- Due to the various call paths that lead to setup_tables() it may happen
- that context->table_list and context->first_name_resolution_table can be
- NULL (this is typically done when creating TABLE_LISTs internally).
- TODO:
- Investigate all cases when this my happen, initialize the name resolution
- context correctly in all those places, and remove the context reset below.
- */
- if (!context->table_list || !context->first_name_resolution_table)
- {
- /* Test whether the context is in a consistent state. */
- DBUG_ASSERT(!context->first_name_resolution_table && !context->table_list);
- context->table_list= context->first_name_resolution_table= tables;
- }
-
+ DBUG_ASSERT ((select_insert && !tables->next_name_resolution_table) || !tables ||
+ (context->table_list && context->first_name_resolution_table));
/*
this is used for INSERT ... SELECT.
For select we setup tables except first (and its underlying tables)
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index d8f12375258..b0a54bec664 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -163,7 +163,7 @@ void mysql_client_binlog_statement(THD* thd)
(ulong) uint4korr(bufptr+EVENT_LEN_OFFSET)));
#endif
ev->thd= thd;
- if (int err= ev->exec_event(thd->rli_fake))
+ if (IF_DBUG(int err= ) ev->exec_event(thd->rli_fake))
{
DBUG_PRINT("error", ("exec_event() returned: %d", err));
/*
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index ea8c0e2d83e..3ab053d1741 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -377,6 +377,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
Item *fake_conds= 0;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
+ List<Item> all_fields;
thd->lex->allow_sum_func= 0;
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
@@ -400,6 +401,11 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
DBUG_RETURN(TRUE);
}
}
+
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
+ DBUG_RETURN(-1);
+
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 6656543e13d..2130e632571 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -661,6 +661,8 @@ bool mysqld_help(THD *thd, const char *mask)
Init tables and fields to be usable from items
tables do not contain VIEWs => we can pass 0 as conds
*/
+ thd->lex->select_lex.context.table_list=
+ thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
if (setup_tables(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
tables, &leaves, FALSE))
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index be13fe58882..45ca0f3971c 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -947,6 +947,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
+ /* INSERT should have a SELECT or VALUES clause */
+ DBUG_ASSERT (!select_insert || !values);
/*
For subqueries in VALUES() we should not see the table in which we are
@@ -978,44 +980,40 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert))
DBUG_RETURN(TRUE);
- /* Save the state of the current name resolution context. */
- ctx_state.save_state(context, table_list);
-
- /*
- Perform name resolution only in the first table - 'table_list',
- which is the table that is inserted into.
- */
- table_list->next_local= 0;
- context->resolve_in_table_list_only(table_list);
/* Prepare the fields in the statement. */
- if (values &&
- !(res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view, &map) ||
- setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) &&
- duplic == DUP_UPDATE)
+ if (values)
{
- select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, context->table_list, update_fields, &map);
- select_lex->no_wrap_view_item= FALSE;
+ /* if we have INSERT ... VALUES () we cannot have a GROUP BY clause */
+ DBUG_ASSERT (!select_lex->group_list.elements);
+
+ /* Save the state of the current name resolution context. */
+ ctx_state.save_state(context, table_list);
+
/*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part.
- */
- if (select_lex->group_list.elements == 0)
+ Perform name resolution only in the first table - 'table_list',
+ which is the table that is inserted into.
+ */
+ table_list->next_local= 0;
+ context->resolve_in_table_list_only(table_list);
+
+ if (!(res= check_insert_fields(thd, context->table_list, fields, *values,
+ !insert_into_view, &map) ||
+ setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
+ && duplic == DUP_UPDATE)
{
- context->table_list->next_local= ctx_state.save_next_local;
- /* first_name_resolution_table was set by resolve_in_table_list_only() */
- context->first_name_resolution_table->
- next_name_resolution_table= ctx_state.save_next_local;
+ select_lex->no_wrap_view_item= TRUE;
+ res= check_update_fields(thd, context->table_list, update_fields, &map);
+ select_lex->no_wrap_view_item= FALSE;
}
+
+ /* Restore the current context. */
+ ctx_state.restore_state(context, table_list);
+
if (!res)
res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
}
- /* Restore the current context. */
- ctx_state.restore_state(context, table_list);
-
if (res)
DBUG_RETURN(res);
@@ -2470,7 +2468,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (info.handle_duplicates == DUP_UPDATE)
{
- /* Save the state of the current name resolution context. */
Name_resolution_context *context= &lex->select_lex.context;
Name_resolution_context_state ctx_state;
@@ -2486,18 +2483,40 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*info.update_fields, &map);
lex->select_lex.no_wrap_view_item= FALSE;
/*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part
- */
- if (lex->select_lex.group_list.elements == 0)
+ When we are not using GROUP BY and there are no ungrouped aggregate functions
+ we can refer to other tables in the ON DUPLICATE KEY part.
+ We use next_name_resolution_table descructively, so check it first (views?)
+ */
+ DBUG_ASSERT (!table_list->next_name_resolution_table);
+ if (lex->select_lex.group_list.elements == 0 &&
+ !lex->select_lex.with_sum_func)
+ /*
+ We must make a single context out of the two separate name resolution contexts :
+ the INSERT table and the tables in the SELECT part of INSERT ... SELECT.
+ To do that we must concatenate the two lists
+ */
+ table_list->next_name_resolution_table=
+ ctx_state.get_first_name_resolution_table();
+
+ res= res || setup_fields(thd, 0, *info.update_values,
+ MARK_COLUMNS_READ, 0, 0);
+ if (!res)
{
- context->table_list->next_local= ctx_state.save_next_local;
- /* first_name_resolution_table was set by resolve_in_table_list_only() */
- context->first_name_resolution_table->
- next_name_resolution_table= ctx_state.save_next_local;
+ /*
+ Traverse the update values list and substitute fields from the
+ select for references (Item_ref objects) to them. This is done in
+ order to get correct values from those fields when the select
+ employs a temporary table.
+ */
+ List_iterator<Item> li(*info.update_values);
+ Item *item;
+
+ while ((item= li++))
+ {
+ item->transform(&Item::update_value_transformer,
+ (byte*)lex->current_select);
+ }
}
- res= res || setup_fields(thd, 0, *info.update_values, MARK_COLUMNS_READ,
- 0, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index af2929b6268..c7cad2761bf 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1172,6 +1172,7 @@ void st_select_lex::init_query()
cond_count= between_count= with_wild= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
+ select_n_where_fields= 0;
select_n_having_items= 0;
subquery_in_having= explicit_limit= 0;
is_item_list_lookup= 0;
@@ -1212,6 +1213,7 @@ void st_select_lex::init_select()
is_correlated= 0;
cur_pos_in_select_list= UNDEF_POS;
non_agg_fields.empty();
+ inner_refs_list.empty();
}
/*
@@ -1569,6 +1571,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
(Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items +
item_list.elements +
select_n_having_items +
+ select_n_where_fields +
order_group_num)*5)) == 0;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 821af3f946d..fa0f9d7cbbb 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -566,6 +566,11 @@ public:
uint select_n_having_items;
uint cond_count; /* number of arguments of and/or/xor in where/having/on */
uint between_count; /* number of between predicates in where/having/on */
+ /*
+ Number of fields used in select list or where clause of current select
+ and all inner subselects.
+ */
+ uint select_n_where_fields;
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
/*
@@ -583,7 +588,8 @@ public:
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
-
+ /* List of references to fields referenced from inner selects */
+ List<Item_outer_ref> inner_refs_list;
/* Number of Item_sum-derived objects in this SELECT */
uint n_sum_items;
/* Number of Item_sum-derived objects in children and descendant SELECTs */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ce7f34e3a06..11eb510d6c8 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3268,7 +3268,9 @@ end_with_restore_list:
We WANT to write and we CAN write.
! we write after unlocking the table.
*/
- /* Presumably, RESET and binlog writing doesn't require synchronization */
+ /*
+ Presumably, RESET and binlog writing doesn't require synchronization
+ */
if (!lex->no_write_to_binlog && write_to_binlog)
{
if (mysql_bin_log.is_open())
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 1acc08e095d..7de8a9a64ec 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1571,21 +1571,16 @@ error:
static bool mysql_insert_select_prepare_tester(THD *thd)
{
- TABLE_LIST *first;
- bool res;
SELECT_LEX *first_select= &thd->lex->select_lex;
+ TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)->
+ next_local;
+
/* Skip first table, which is the table we are inserting in */
- first_select->table_list.first= (byte*)(first=
- ((TABLE_LIST*)first_select->
- table_list.first)->next_local);
- res= mysql_insert_select_prepare(thd);
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- thd->lex->select_lex.context.resolve_in_select_list= TRUE;
- thd->lex->select_lex.context.table_list= first;
- return res;
+ first_select->table_list.first= (byte *) second_table;
+ thd->lex->select_lex.context.table_list=
+ thd->lex->select_lex.context.first_name_resolution_table= second_table;
+
+ return mysql_insert_select_prepare(thd);
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 17163fb1940..1a8446a86e9 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -23,7 +23,9 @@
int max_binlog_dump_events = 0; // unlimited
my_bool opt_sporadic_binlog_dump_fail = 0;
+#ifndef DBUG_OFF
static int binlog_dump_count = 0;
+#endif
/*
fake_rotate_event() builds a fake (=which does not exist physically in any
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 6de7ba1d58b..90d78a0245b 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -268,6 +268,70 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
/*
+ Fix fields referenced from inner selects.
+
+ SYNOPSIS
+ fix_inner_refs()
+ thd Thread handle
+ all_fields List of all fields used in select
+ select Current select
+ ref_pointer_array Array of references to Items used in current select
+
+ DESCRIPTION
+ The function fixes fields referenced from inner selects and
+ also fixes references (Item_ref objects) to these fields. Each field
+ is fixed as a usual hidden field of the current select - it is added
+ to the all_fields list and the pointer to it is saved in the
+ ref_pointer_array if latter is provided.
+ After the field has been fixed we proceed with fixing references
+ (Item_ref objects) to this field from inner subqueries. If the
+ ref_pointer_array is provided then Item_ref objects is set to
+ reference element in that array with the pointer to the field.
+
+ RETURN
+ TRUE an error occured
+ FALSE ok
+*/
+
+bool
+fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array)
+{
+ Item_outer_ref *ref;
+ bool res= FALSE;
+ List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
+ while ((ref= ref_it++))
+ {
+ Item_field *item= ref->outer_field;
+ /*
+ TODO: this field item already might be present in the select list.
+ In this case instead of adding new field item we could use an
+ existing one. The change will lead to less operations for copying fields,
+ smaller temporary tables and less data passed through filesort.
+ */
+ if (ref_pointer_array)
+ {
+ int el= all_fields.elements;
+ ref_pointer_array[el]= (Item*)item;
+ /* Add the field item to the select list of the current select. */
+ all_fields.push_front((Item*)item);
+ /*
+ If it's needed reset each Item_ref item that refers this field with
+ a new reference taken from ref_pointer_array.
+ */
+ ref->ref= ref_pointer_array + el;
+ }
+ if (!ref->fixed && ref->fix_fields(thd, 0))
+ {
+ res= TRUE;
+ break;
+ }
+ thd->used_tables|= item->used_tables();
+ }
+ return res;
+}
+
+/*
Function to setup clauses without sum functions
*/
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
@@ -394,6 +458,10 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having && having->with_sum_func)
having->split_sum_func2(thd, ref_pointer_array, all_fields,
&having, TRUE);
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
+ DBUG_RETURN(-1);
+
if (select_lex->inner_sum_func_list)
{
Item_sum *end=select_lex->inner_sum_func_list;
@@ -474,6 +542,9 @@ JOIN::prepare(Item ***rref_pointer_array,
}
}
+ if (!procedure && result && result->prepare(fields_list, unit_arg))
+ goto err; /* purecov: inspected */
+
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
@@ -487,9 +558,6 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err;
}
#endif
- if (!procedure && result && result->prepare(fields_list, unit_arg))
- goto err; /* purecov: inspected */
-
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
goto err;
if (alloc_func_list())
@@ -2884,15 +2952,9 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
-
- We also cannot use index on a text column, as the column may
- contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
- 'x' when searching for WHERE col='x '
*/
if (field->cmp_type() == STRING_RESULT &&
- (((Field_str*)field)->charset() != cond->compare_collation() ||
- ((*value)->type() != Item::NULL_ITEM &&
- (field->flags & BLOB_FLAG) && !field->binary())))
+ ((Field_str*)field)->charset() != cond->compare_collation())
return;
}
}
@@ -5287,13 +5349,15 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
key_part->length,
keyuse->val);
}
- else if (keyuse->val->type() == Item::FIELD_ITEM)
+ else if (keyuse->val->type() == Item::FIELD_ITEM ||
+ (keyuse->val->type() == Item::REF_ITEM &&
+ ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF) )
return new store_key_field(thd,
key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
- ((Item_field*) keyuse->val)->field,
+ ((Item_field*) keyuse->val->real_item())->field,
keyuse->val->full_name());
return new store_key_item(thd,
key_part->field,
@@ -8887,7 +8951,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
type they needed to be handled separately.
*/
if ((type= item->field_type()) == MYSQL_TYPE_DATETIME ||
- type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE)
+ type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_TIMESTAMP)
new_field= item->tmp_table_field_from_field_type(table, 1);
/*
Make sure that the blob fits into a Field_varstring which has
@@ -9003,8 +9068,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item *orig_item= 0;
if (type != Item::FIELD_ITEM &&
- item->real_item()->type() == Item::FIELD_ITEM &&
- !((Item_ref *) item)->depended_from)
+ item->real_item()->type() == Item::FIELD_ITEM)
{
orig_item= item;
item= item->real_item();
@@ -13723,10 +13787,8 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
param->quick_group=1;
while ((field=li++))
{
- Item::Type type=field->type();
Item::Type real_type= field->real_item()->type();
- if (type == Item::FIELD_ITEM || (real_type == Item::FIELD_ITEM &&
- !((Item_ref *) field)->depended_from))
+ if (real_type == Item::FIELD_ITEM)
param->field_count++;
else if (real_type == Item::SUM_FUNC_ITEM)
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 36f0acd8f67..0697fdd79b4 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -41,7 +41,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
static bool prepare_blob_field(THD *thd, create_field *sql_field);
static bool check_engine(THD *thd, const char *table_name,
- HA_CREATE_INFO *create_info);
+ HA_CREATE_INFO *create_info);
static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> *fields,
List<Key> *keys, bool tmp_table,
@@ -4818,7 +4818,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
else
unlock_dst_table= TRUE;
- int result= store_create_info(thd, table, &query, create_info);
+ IF_DBUG(int result=) store_create_info(thd, table, &query,
+ create_info);
DBUG_ASSERT(result == 0); // store_create_info() always return 0
write_bin_log(thd, TRUE, query.ptr(), query.length());
@@ -6645,7 +6646,8 @@ view_err:
thd->query, thd->query_length,
db, table_name);
- DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based &&
+ DBUG_ASSERT(!(mysql_bin_log.is_open() &&
+ thd->current_stmt_binlog_row_based &&
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
write_bin_log(thd, TRUE, thd->query, thd->query_length);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 9fe20c502d6..f020168d742 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -147,6 +147,8 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
&result_table_list.next_local);
+ fake_select_lex->context.table_list= fake_select_lex->context.first_name_resolution_table=
+ fake_select_lex->get_table_list();
for (ORDER *order= (ORDER *)global_parameters->order_list.first;
order;
order=order->next)
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index a8b7efcc1bd..02a90b942bf 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -133,6 +133,7 @@ int mysql_update(THD *thd,
SELECT_LEX *select_lex= &thd->lex->select_lex;
bool need_reopen;
ulonglong id;
+ List<Item> all_fields;
DBUG_ENTER("mysql_update");
for ( ; ; )
@@ -216,6 +217,10 @@ int mysql_update(THD *thd,
DBUG_RETURN(1); /* purecov: inspected */
}
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
+ DBUG_RETURN(-1);
+
if (conds)
{
Item::cond_result cond_value;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9c062407921..297bd9f2737 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5941,8 +5941,13 @@ select_into:
| select_from into;
select_from:
- FROM join_table_list where_clause group_clause having_clause
+ FROM join_table_list where_clause group_clause having_clause
opt_order_clause opt_limit_clause procedure_clause
+ {
+ Select->context.table_list=
+ Select->context.first_name_resolution_table=
+ (TABLE_LIST *) Select->table_list.first;
+ }
| FROM DUAL_SYM where_clause opt_limit_clause
/* oracle compatibility: oracle always requires FROM clause,
and DUAL is system table without fields.
@@ -11045,6 +11050,12 @@ subselect_end:
lex->current_select = lex->current_select->return_after_parsing();
lex->nest_level--;
lex->current_select->n_child_sum_items += child->n_sum_items;
+ /*
+ A subselect can add fields to an outer select. Reserve space for
+ them.
+ */
+ lex->current_select->select_n_where_fields+=
+ child->select_n_where_fields;
};
/**************************************************************************