summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@mishka.local>2004-12-22 13:54:39 +0200
committerunknown <monty@mishka.local>2004-12-22 13:54:39 +0200
commitbb2d3eaa30a3881927142c985fb637aca06d9823 (patch)
tree8e5f08b17957f896c2d4e931e60b57d99c260ed6 /sql
parent52d080f09979deb2063a8010feee3b925a3d7938 (diff)
parent5c79810a6d3ca19254c310f1519664729367b647 (diff)
downloadmariadb-git-bb2d3eaa30a3881927142c985fb637aca06d9823.tar.gz
Merge with 4.1
BitKeeper/etc/ignore: auto-union BitKeeper/etc/logging_ok: auto-union Build-tools/Do-compile: Auto merged VC++Files/sql/mysqld.dsp: Auto merged client/Makefile.am: Auto merged client/mysql.cc: Auto merged BitKeeper/deleted/.del-acinclude.m4~f4ab416bac5003: Auto merged client/mysqltest.c: Auto merged include/my_base.h: Auto merged innobase/dict/dict0dict.c: Auto merged innobase/dict/dict0load.c: Auto merged innobase/include/dict0dict.h: Auto merged innobase/include/row0mysql.h: Auto merged innobase/os/os0file.c: Auto merged innobase/srv/srv0srv.c: Auto merged libmysql/libmysql.c: Auto merged myisam/mi_check.c: Auto merged myisam/mi_rnext_same.c: Auto merged myisam/mi_write.c: Auto merged myisam/sort.c: Auto merged mysql-test/mysql-test-run.sh: Auto merged mysql-test/r/ctype_ucs.result: Auto merged mysql-test/r/ctype_ujis.result: Auto merged mysql-test/r/gis-rtree.result: Auto merged mysql-test/r/group_by.result: Auto merged mysql-test/r/merge.result: Auto merged mysql-test/r/metadata.result: Auto merged mysql-test/r/ndb_alter_table.result: Auto merged mysql-test/r/ps_1general.result: Auto merged mysql-test/r/insert_update.result: Auto merged mysql-test/r/timezone2.result: Auto merged mysql-test/r/type_enum.result: Auto merged mysql-test/r/variables.result: Auto merged mysql-test/t/ctype_ucs.test: Auto merged mysql-test/t/merge.test: Auto merged mysql-test/t/ps_1general.test: Auto merged mysql-test/t/subselect.test: Auto merged mysql-test/t/system_mysql_db_fix.test: Auto merged mysql-test/t/variables.test: Auto merged ndb/include/ndbapi/NdbConnection.hpp: Auto merged ndb/include/ndbapi/NdbDictionary.hpp: Auto merged ndb/src/common/util/version.c: Auto merged ndb/src/kernel/blocks/dbacc/DbaccInit.cpp: Auto merged ndb/src/kernel/blocks/dbacc/Makefile.am: Auto merged ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Auto merged ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Auto merged ndb/src/kernel/blocks/dblqh/DblqhInit.cpp: Auto merged ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Auto merged ndb/src/kernel/blocks/dbtux/Dbtux.hpp: Auto merged ndb/src/ndbapi/NdbBlob.cpp: Auto merged ndb/src/ndbapi/NdbConnection.cpp: Auto merged ndb/src/ndbapi/NdbDictionary.cpp: Auto merged ndb/src/ndbapi/NdbDictionaryImpl.cpp: Auto merged ndb/src/ndbapi/NdbDictionaryImpl.hpp: Auto merged ndb/src/ndbapi/NdbOperationExec.cpp: Auto merged ndb/src/ndbapi/NdbScanOperation.cpp: Auto merged ndb/test/ndbapi/Makefile.am: Auto merged scripts/make_win_src_distribution.sh: Auto merged scripts/mysql_install_db.sh: Auto merged sql/field.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/ha_ndbcluster.h: Auto merged sql/handler.cc: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_create.h: Auto merged sql/item_func.cc: Auto merged sql/item_geofunc.cc: Auto merged sql/item_row.cc: Auto merged sql/item_strfunc.cc: Auto merged sql/item_strfunc.h: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/mysqld.cc: Auto merged sql/net_serv.cc: Auto merged sql/password.c: Auto merged sql/protocol.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/slave.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_derived.cc: Auto merged sql/sql_do.cc: Auto merged sql/sql_handler.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_repl.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_union.cc: Auto merged sql/examples/ha_archive.cc: Auto merged sql/strfunc.cc: Auto merged sql/table.cc: Auto merged sql/table.h: Auto merged sql/tztime.h: Auto merged sql/udf_example.cc: Auto merged sql/unireg.cc: Auto merged Makefile.am: Simple merge client/mysqldump.c: Simple merge configure.in: Simple merge libmysqld/lib_sql.cc: Automatic merge mysql-test/r/func_str.result: Automatic merge mysql-test/r/grant.result: simple merge mysql-test/r/multi_update.result: automatc merge mysql-test/r/ps.result: automatic merge mysql-test/r/ps_2myisam.result: Automatic merge mysql-test/r/ps_3innodb.result: Automatic merge mysql-test/r/ps_4heap.result: Automatic merge mysql-test/r/ps_5merge.result: Automatic merge mysql-test/r/ps_6bdb.result: Automatic merge mysql-test/r/ps_7ndb.result: Automatic merge mysql-test/r/show_check.result: Automatic merge mysql-test/r/subselect.result: Automatic merge mysql-test/t/grant.test: Automatic merge mysql-test/t/multi_update.test: Automatic merge mysql-test/t/ps.test: Automatic merge mysql-test/t/show_check.test: Automatic merge ndb/docs/wl2077.txt: merge ndb/src/mgmsrv/main.cpp: merge scripts/mysql_fix_privilege_tables.sh: merge sql/item.cc: Merge (difficult) sql/item.h: simple merge sql/item_cmpfunc.h: Automatic merge sql/item_subselect.cc: Simple merge sql/item_subselect.h: Automatic merge sql/mysql_priv.h: Simple merge sql/slave.h: Automatic merge sql/sql_base.cc: Removed code that was backported to 4.1 sql/sql_class.h: Merge (some code moved to sql_insert.cc) sql/sql_db.cc: simple merge sql/sql_insert.cc: Merge (difficult as logic had changed both in 4.1 and 5.0) Some coded moved here from sql_class.h sql/sql_parse.cc: Merge (difficult) sql/sql_prepare.cc: Simple merge sql/sql_select.cc: Automatic merge sql/sql_table.cc: Simple merge sql/sql_update.cc: Difficult merge because of different logic for multi-updates sql/sql_yacc.yy: Simple merge tests/client_test.c: Simple merge
Diffstat (limited to 'sql')
-rw-r--r--sql/examples/ha_archive.cc3
-rw-r--r--sql/field.cc22
-rw-r--r--sql/ha_ndbcluster.cc63
-rw-r--r--sql/ha_ndbcluster.h2
-rw-r--r--sql/handler.cc6
-rw-r--r--sql/item.cc62
-rw-r--r--sql/item.h80
-rw-r--r--sql/item_cmpfunc.cc55
-rw-r--r--sql/item_cmpfunc.h24
-rw-r--r--sql/item_create.h2
-rw-r--r--sql/item_func.cc21
-rw-r--r--sql/item_geofunc.cc1
-rw-r--r--sql/item_row.cc1
-rw-r--r--sql/item_strfunc.cc18
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_subselect.cc58
-rw-r--r--sql/item_subselect.h20
-rw-r--r--sql/item_sum.cc19
-rw-r--r--sql/item_sum.h8
-rw-r--r--sql/log.cc1
-rw-r--r--sql/log_event.cc10
-rw-r--r--sql/mysql_priv.h21
-rw-r--r--sql/mysqld.cc50
-rw-r--r--sql/net_serv.cc4
-rw-r--r--sql/password.c5
-rw-r--r--sql/protocol.cc12
-rw-r--r--sql/repl_failsafe.cc1
-rw-r--r--sql/set_var.cc21
-rw-r--r--sql/slave.cc62
-rw-r--r--sql/slave.h27
-rw-r--r--sql/sql_acl.cc1
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_cache.cc3
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_db.cc26
-rw-r--r--sql/sql_derived.cc1
-rw-r--r--sql/sql_do.cc1
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_help.cc3
-rw-r--r--sql/sql_insert.cc45
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc112
-rw-r--r--sql/sql_prepare.cc26
-rw-r--r--sql/sql_repl.cc9
-rw-r--r--sql/sql_select.cc9
-rw-r--r--sql/sql_show.cc1
-rw-r--r--sql/sql_table.cc51
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc16
-rw-r--r--sql/sql_yacc.yy51
-rw-r--r--sql/strfunc.cc20
-rw-r--r--sql/table.cc26
-rw-r--r--sql/table.h10
-rw-r--r--sql/tztime.h6
-rw-r--r--sql/udf_example.cc13
-rw-r--r--sql/unireg.cc22
58 files changed, 818 insertions, 343 deletions
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index f754793e319..f79ca903e7a 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -520,6 +520,7 @@ error:
int ha_archive::write_row(byte * buf)
{
z_off_t written;
+ Field_blob **field;
DBUG_ENTER("ha_archive::write_row");
if (share->crashed)
@@ -540,7 +541,7 @@ int ha_archive::write_row(byte * buf)
We should probably mark the table as damagaged if the record is written
but the blob fails.
*/
- for (Field_blob **field=table->blob_field ; *field ; field++)
+ for (field= table->blob_field ; *field ; field++)
{
char *ptr;
uint32 size= (*field)->get_length();
diff --git a/sql/field.cc b/sql/field.cc
index ebeee476985..0f1faccfe42 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2197,7 +2197,7 @@ int Field_longlong::store(double nr)
res= LONGLONG_MIN;
error= (nr < (double) LONGLONG_MIN);
}
- else if (nr >= (double) LONGLONG_MAX)
+ else if (nr >= (double) (ulonglong) LONGLONG_MAX)
{
res= LONGLONG_MAX;
error= (nr > (double) LONGLONG_MAX);
@@ -5919,8 +5919,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
}
/* Remove end space */
- while (length > 0 && my_isspace(system_charset_info,from[length-1]))
- length--;
+ length= field_charset->cset->lengthsp(field_charset, from, length);
uint tmp=find_type2(typelib, from, length, field_charset);
if (!tmp)
{
@@ -6022,7 +6021,7 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
val_ptr->set("", 0, field_charset);
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
- (uint) strlen(typelib->type_names[tmp-1]),
+ typelib->type_lengths[tmp-1],
field_charset);
return val_ptr;
}
@@ -6059,13 +6058,14 @@ void Field_enum::sql_type(String &res) const
res.append("enum(");
bool flag=0;
- for (const char **pos= typelib->type_names; *pos; pos++)
+ uint *len= typelib->type_lengths;
+ for (const char **pos= typelib->type_names; *pos; pos++, len++)
{
uint dummy_errors;
if (flag)
res.append(',');
/* convert to res.charset() == utf8, then quote */
- enum_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors);
+ enum_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
append_unescaped(&res, enum_item.ptr(), enum_item.length());
flag= 1;
}
@@ -6144,14 +6144,15 @@ String *Field_set::val_str(String *val_buffer,
uint bitnr=0;
val_buffer->length(0);
+ val_buffer->set_charset(field_charset);
while (tmp && bitnr < (uint) typelib->count)
{
if (tmp & 1)
{
if (val_buffer->length())
- val_buffer->append(field_separator);
+ val_buffer->append(&field_separator, 1, &my_charset_latin1);
String str(typelib->type_names[bitnr],
- (uint) strlen(typelib->type_names[bitnr]),
+ typelib->type_lengths[bitnr],
field_charset);
val_buffer->append(str);
}
@@ -6171,13 +6172,14 @@ void Field_set::sql_type(String &res) const
res.append("set(");
bool flag=0;
- for (const char **pos= typelib->type_names; *pos; pos++)
+ uint *len= typelib->type_lengths;
+ for (const char **pos= typelib->type_names; *pos; pos++, len++)
{
uint dummy_errors;
if (flag)
res.append(',');
/* convert to res.charset() == utf8, then quote */
- set_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors);
+ set_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
append_unescaped(&res, set_item.ptr(), set_item.length());
flag= 1;
}
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index f838bfcd8c3..7320665dc49 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -32,6 +32,10 @@
#include <ndbapi/NdbApi.hpp>
#include <ndbapi/NdbScanFilter.hpp>
+// options from from mysqld.cc
+extern my_bool opt_ndb_optimized_node_selection;
+extern const char *opt_ndbcluster_connectstring;
+
// Default value for parallelism
static const int parallelism= 240;
@@ -39,9 +43,6 @@ static const int parallelism= 240;
// createable against NDB from this handler
static const int max_transactions= 256;
-// connectstring to cluster if given by mysqld
-const char *ndbcluster_connectstring= 0;
-
static const char *ha_ndb_ext=".ndb";
#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8
@@ -192,7 +193,7 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbConnection *trans)
if (m_batch_execute)
return 0;
#endif
- return trans->execute(NoCommit,IgnoreError,h->m_force_send);
+ return trans->execute(NoCommit, AO_IgnoreError,h->m_force_send);
}
/*
@@ -3638,9 +3639,13 @@ int ha_ndbcluster::create_index(const char *name,
int ha_ndbcluster::rename_table(const char *from, const char *to)
{
+ NDBDICT *dict;
char new_tabname[FN_HEADLEN];
+ const NDBTAB *orig_tab;
+ int result;
DBUG_ENTER("ha_ndbcluster::rename_table");
+ DBUG_PRINT("info", ("Renaming %s to %s", from, to));
set_dbname(from);
set_tabname(from);
set_tabname(to, new_tabname);
@@ -3648,14 +3653,20 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
if (check_ndb_connection())
DBUG_RETURN(my_errno= HA_ERR_NO_CONNECTION);
+ dict= m_ndb->getDictionary();
+ if (!(orig_tab= dict->getTable(m_tabname)))
+ ERR_RETURN(dict->getNdbError());
- int result= alter_table_name(m_tabname, new_tabname);
- if (result == 0)
+ m_table= (void *)orig_tab;
+ // Change current database to that of target table
+ set_dbname(to);
+ m_ndb->setDatabaseName(m_dbname);
+ if (!(result= alter_table_name(new_tabname)))
{
- set_tabname(to);
- handler::rename_table(from, to);
+ // Rename .ndb file
+ result= handler::rename_table(from, to);
}
-
+
DBUG_RETURN(result);
}
@@ -3664,19 +3675,16 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
Rename a table in NDB Cluster using alter table
*/
-int ha_ndbcluster::alter_table_name(const char *from, const char *to)
+int ha_ndbcluster::alter_table_name(const char *to)
{
- NDBDICT *dict= m_ndb->getDictionary();
- const NDBTAB *orig_tab;
+ NDBDICT * dict= m_ndb->getDictionary();
+ const NDBTAB *orig_tab= (const NDBTAB *) m_table;
+ int ret;
DBUG_ENTER("alter_table_name_table");
- DBUG_PRINT("enter", ("Renaming %s to %s", from, to));
- if (!(orig_tab= dict->getTable(from)))
- ERR_RETURN(dict->getNdbError());
-
- NdbDictionary::Table copy_tab= dict->getTableForAlteration(from);
- copy_tab.setName(to);
- if (dict->alterTable(copy_tab) != 0)
+ NdbDictionary::Table new_tab= *orig_tab;
+ new_tab.setName(to);
+ if (dict->alterTable(new_tab) != 0)
ERR_RETURN(dict->getNdbError());
m_table= NULL;
@@ -3699,7 +3707,7 @@ int ha_ndbcluster::delete_table(const char *name)
if (check_ndb_connection())
DBUG_RETURN(HA_ERR_NO_CONNECTION);
-
+ // Remove .ndb file
handler::delete_table(name);
DBUG_RETURN(drop_table());
}
@@ -3958,6 +3966,7 @@ Ndb* check_ndb_in_thd(THD* thd)
}
+
int ha_ndbcluster::check_ndb_connection()
{
THD* thd= current_thd;
@@ -4240,15 +4249,19 @@ bool ndbcluster_init()
int res;
DBUG_ENTER("ndbcluster_init");
// Set connectstring if specified
- if (ndbcluster_connectstring != 0)
- DBUG_PRINT("connectstring", ("%s", ndbcluster_connectstring));
+ if (opt_ndbcluster_connectstring != 0)
+ DBUG_PRINT("connectstring", ("%s", opt_ndbcluster_connectstring));
if ((g_ndb_cluster_connection=
- new Ndb_cluster_connection(ndbcluster_connectstring)) == 0)
+ new Ndb_cluster_connection(opt_ndbcluster_connectstring)) == 0)
{
- DBUG_PRINT("error",("Ndb_cluster_connection(%s)",ndbcluster_connectstring));
+ DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
+ opt_ndbcluster_connectstring));
goto ndbcluster_init_error;
}
+ g_ndb_cluster_connection->set_optimized_node_selection
+ (opt_ndb_optimized_node_selection);
+
// Create a Ndb object to open the connection to NDB
g_ndb= new Ndb(g_ndb_cluster_connection, "sys");
g_ndb->getDictionary()->set_local_table_data_size(sizeof(Ndb_table_local_info));
@@ -4263,7 +4276,7 @@ bool ndbcluster_init()
DBUG_PRINT("info",("NDBCLUSTER storage engine at %s on port %d",
g_ndb_cluster_connection->get_connected_host(),
g_ndb_cluster_connection->get_connected_port()));
- g_ndb->waitUntilReady(10);
+ g_ndb_cluster_connection->wait_until_ready(10,0);
}
else if(res == 1)
{
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 2f18a52b8e9..ca3fa929674 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -148,7 +148,7 @@ class ha_ndbcluster: public handler
uint8 table_cache_type();
private:
- int alter_table_name(const char *from, const char *to);
+ int alter_table_name(const char *to);
int drop_table();
int create_index(const char *name, KEY *key_info, bool unique);
int create_ordered_index(const char *name, KEY *key_info);
diff --git a/sql/handler.cc b/sql/handler.cc
index e43f2c2e888..d6ce85f6a13 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1232,6 +1232,9 @@ void handler::print_error(int error, myf errflag)
textno=ER_DUP_KEY;
break;
}
+ case HA_ERR_NULL_IN_SPATIAL:
+ textno= ER_UNKNOWN_ERROR;
+ DBUG_VOID_RETURN;
case HA_ERR_FOUND_DUPP_UNIQUE:
textno=ER_DUP_UNIQUE;
break;
@@ -1345,7 +1348,8 @@ uint handler::get_dup_key(int error)
{
DBUG_ENTER("handler::get_dup_key");
table->file->errkey = (uint) -1;
- if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
+ if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE ||
+ error == HA_ERR_NULL_IN_SPATIAL)
info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
DBUG_RETURN(table->file->errkey);
}
diff --git a/sql/item.cc b/sql/item.cc
index 9117105f26e..ee77f2d43c0 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -73,7 +73,7 @@ Item::Item():
}
/*
- Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_*_ref & agregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
*/
@@ -171,7 +171,7 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
}
-/* Constructor used by Item_field & Item_ref (see Item comment) */
+/* Constructor used by Item_field & Item_*_ref (see Item comment) */
Item_ident::Item_ident(THD *thd, Item_ident *item)
:Item(thd, item),
@@ -1780,16 +1780,13 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
}
return (select->ref_pointer_array + counter);
}
- else if (group_by_ref)
+ if (group_by_ref)
return group_by_ref;
- else
- {
- DBUG_ASSERT(FALSE);
- return NULL; /* So there is no compiler warning. */
- }
+ DBUG_ASSERT(FALSE);
+ return NULL; /* So there is no compiler warning. */
}
- else
- return (Item**) not_found_item;
+
+ return (Item**) not_found_item;
}
@@ -1847,6 +1844,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
{
+ enum_parsing_place place= NO_MATTER;
DBUG_ASSERT(fixed == 0);
if (!field) // If field is not checked
{
@@ -1885,13 +1883,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
/* Search in the tables of the FROM clause of the outer select. */
table_list= outer_sel->get_table_list();
if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
+ {
/*
It is a primary INSERT st_select_lex => do not resolve against the
first table.
*/
table_list= table_list->next_local;
-
- enum_parsing_place place= prev_subselect_item->parsing_place;
+ }
+ place= prev_subselect_item->parsing_place;
/*
Check table fields only if the subquery is used somewhere out of
HAVING, or the outer SELECT does not use grouping (i.e. tables are
@@ -1926,7 +1925,6 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
/* Search in the SELECT and GROUP lists of the outer select. */
if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
- {
if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
return TRUE; /* Some error occured (e.g. ambigous names). */
if (ref != not_found_item)
@@ -1968,10 +1966,23 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
}
else if (ref != not_found_item)
{
+ Item *save;
+ Item_ref *rf;
+
/* Should have been checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
-
- Item_ref *rf= new Item_ref(ref, (char *)table_name, (char *)field_name);
+ /*
+ Here, a subset of actions performed by Item_ref::set_properties
+ is not enough. So we pass ptr to NULL into Item_[direct]_ref
+ constructor, so no initialization is performed, and call
+ fix_fields() below.
+ */
+ save= *ref;
+ *ref= NULL; // Don't call set_properties()
+ rf= (place == IN_HAVING ?
+ new Item_ref(ref, (char*) table_name, (char*) field_name) :
+ new Item_direct_ref(ref, (char*) table_name, (char*) field_name));
+ *ref= save;
if (!rf)
return TRUE;
thd->change_item_tree(reference, rf);
@@ -2859,6 +2870,7 @@ bool Item_field::send(Protocol *protocol, String *buffer)
bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
{
DBUG_ASSERT(fixed == 0);
+ enum_parsing_place place= NO_MATTER;
SELECT_LEX *current_sel= thd->lex->current_select;
if (!ref)
@@ -2919,7 +2931,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
*/
table_list= table_list->next_local;
- enum_parsing_place place= prev_subselect_item->parsing_place;
+ place= prev_subselect_item->parsing_place;
/*
Check table fields only if the subquery is used somewhere out of
HAVING or the outer SELECT does not use grouping (i.e. tables are
@@ -3037,6 +3049,16 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
"forward reference in item list"));
return TRUE;
}
+
+ set_properties();
+
+ if (ref && (*ref)->check_cols(1))
+ return 1;
+ return 0;
+}
+
+void Item_ref::set_properties()
+{
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
@@ -3047,10 +3069,6 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
else
alias_name_used= TRUE; // it is not field, so it is was resolved by alias
fixed= 1;
-
- if (ref && (*ref)->check_cols(1))
- return TRUE;
- return FALSE;
}
@@ -3156,7 +3174,7 @@ bool Item_default_value::fix_fields(THD *thd,
fixed= 1;
return FALSE;
}
- if (arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return TRUE;
if (arg->type() == REF_ITEM)
@@ -3207,7 +3225,7 @@ bool Item_insert_value::fix_fields(THD *thd,
Item **items)
{
DBUG_ASSERT(fixed == 0);
- if (arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return TRUE;
if (arg->type() == REF_ITEM)
diff --git a/sql/item.h b/sql/item.h
index d5361bdcc8a..5a760db23f5 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -941,7 +941,7 @@ class Item_empty_string :public Item_string
public:
Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) :
Item_string("",0, cs ? cs : &my_charset_bin)
- { name=(char*) header; max_length=length;}
+ { name=(char*) header; max_length= cs ? length * cs->mbmaxlen : length; }
void make_field(Send_field *field);
};
@@ -1010,14 +1010,36 @@ public:
class Item_ref :public Item_ident
{
+protected:
+ void set_properties();
public:
Field *result_field; /* Save result here */
Item **ref;
Item_ref(const char *db_par, const char *table_name_par,
const char *field_name_par)
:Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {}
+ /*
+ This constructor is used in two scenarios:
+ A) *item = NULL
+ No initialization is performed, fix_fields() call will be necessary.
+
+ B) *item points to an Item this Item_ref will refer to. This is
+ used for GROUP BY. fix_fields() will not be called in this case,
+ so we call set_properties to make this item "fixed". set_properties
+ performs a subset of action Item_ref::fix_fields does, and this subset
+ is enough for Item_ref's used in GROUP BY.
+
+ TODO we probably fix a superset of problems like in BUG#6658. Check this
+ with Bar, and if we have a more broader set of problems like this.
+ */
Item_ref(Item **item, const char *table_name_par, const char *field_name_par)
- :Item_ident(NullS, table_name_par, field_name_par), result_field(0), ref(item) {}
+ :Item_ident(NullS, table_name_par, field_name_par), result_field(0), ref(item)
+ {
+ DBUG_ASSERT(item);
+ if (*item)
+ set_properties();
+ }
+
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
enum Type type() const { return REF_ITEM; }
@@ -1025,29 +1047,34 @@ public:
{ return ref && (*ref)->eq(item, binary_cmp); }
double val_real()
{
+ DBUG_ASSERT(fixed);
double tmp=(*ref)->val_result();
null_value=(*ref)->null_value;
return tmp;
}
longlong val_int()
{
+ DBUG_ASSERT(fixed);
longlong tmp=(*ref)->val_int_result();
null_value=(*ref)->null_value;
return tmp;
}
String *val_str(String* tmp)
{
+ DBUG_ASSERT(fixed);
tmp=(*ref)->str_result(tmp);
null_value=(*ref)->null_value;
return tmp;
}
bool is_null()
{
+ DBUG_ASSERT(fixed);
(void) (*ref)->val_int_result();
return (*ref)->null_value;
}
bool get_date(TIME *ltime,uint fuzzydate)
{
+ DBUG_ASSERT(fixed);
return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
}
double val_result();
@@ -1079,7 +1106,52 @@ public:
void cleanup();
};
+
+/*
+ The same as Item_ref, but get value from val_* family of method to get
+ value of item on which it referred instead of result* family.
+*/
+class Item_direct_ref :public Item_ref
+{
+public:
+ Item_direct_ref(Item **item, const char *table_name_par,
+ const char *field_name_par)
+ :Item_ref(item, table_name_par, field_name_par) {}
+ /* Constructor need to process subselect with temporary tables (see Item) */
+ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
+
+ double val()
+ {
+ double tmp=(*ref)->val();
+ null_value=(*ref)->null_value;
+ return tmp;
+ }
+ longlong val_int()
+ {
+ longlong tmp=(*ref)->val_int();
+ null_value=(*ref)->null_value;
+ return tmp;
+ }
+ String *val_str(String* tmp)
+ {
+ tmp=(*ref)->val_str(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+ }
+ bool is_null()
+ {
+ (void) (*ref)->val_int();
+ return (*ref)->null_value;
+ }
+ bool get_date(TIME *ltime,uint fuzzydate)
+ {
+ return (null_value=(*ref)->get_date(ltime,fuzzydate));
+ }
+};
+
+
class Item_in_subselect;
+
class Item_ref_null_helper: public Item_ref
{
protected:
@@ -1101,9 +1173,9 @@ class Item_null_helper :public Item_ref_null_helper
public:
Item_null_helper(Item_in_subselect* master, Item *item,
const char *table_name_par, const char *field_name_par)
- :Item_ref_null_helper(master, &store, table_name_par, field_name_par),
+ :Item_ref_null_helper(master, &item, table_name_par, field_name_par),
store(item)
- {}
+ { ref= &store; }
void print(String *str);
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 90eee9e76d1..a118de6fdb9 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -106,7 +106,7 @@ longlong Item_func_not::val_int()
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
null_value=args[0]->null_value;
- return !null_value && value == 0 ? 1 : 0;
+ return ((!null_value && value == 0) ? 1 : 0);
}
/*
@@ -117,13 +117,23 @@ longlong Item_func_not_all::val_int()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- if (abort_on_null)
- {
- null_value= 0;
- return (args[0]->null_value || value == 0) ? 1 : 0;
- }
+
+ /*
+ return TRUE if there was records in underlaying select in max/min
+ optimisation (ALL subquery)
+ */
+ if (empty_underlying_subquery())
+ return 1;
+
null_value= args[0]->null_value;
- return (!null_value && value == 0) ? 1 : 0;
+ return ((!null_value && value == 0) ? 1 : 0);
+}
+
+
+bool Item_func_not_all::empty_underlying_subquery()
+{
+ return ((test_sum_item && !test_sum_item->any_value()) ||
+ (test_sub_item && !test_sub_item->any_value()));
}
void Item_func_not_all::print(String *str)
@@ -134,6 +144,30 @@ void Item_func_not_all::print(String *str)
args[0]->print(str);
}
+
+/*
+ Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all
+ (return TRUE if underlaying sudquery do not return rows) but if subquery
+ returns some rows it return same value as argument (TRUE/FALSE).
+*/
+
+longlong Item_func_nop_all::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ double value= args[0]->val();
+
+ /*
+ return FALSE if there was records in underlaying select in max/min
+ optimisation (SAME/ANY subquery)
+ */
+ if (empty_underlying_subquery())
+ return 0;
+
+ null_value= args[0]->null_value;
+ return (null_value || value == 0) ? 0 : 1;
+}
+
+
/*
Convert a constant expression or string to an integer.
This is done when comparing DATE's of different formats and
@@ -2053,6 +2087,7 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
{
Item **ref= li.ref();
uint el= fields.elements;
+ ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
ref_pointer_array[el]= item;
@@ -2404,8 +2439,10 @@ bool
Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (args[0]->fix_fields(thd, tables, args) || args[0]->check_cols(1) ||
- args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(1))
+ if ((!args[0]->fixed &&
+ args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) ||
+ (!args[1]->fixed &&
+ args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1))
return TRUE; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
max_length= 1;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 6a7e037bed1..a6fe9e44a3d 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -231,6 +231,7 @@ public:
Item *neg_transformer(THD *thd);
};
+class Item_maxmin_subselect;
/*
The class Item_func_trig_cond is used for guarded predicates
@@ -267,19 +268,40 @@ public:
class Item_func_not_all :public Item_func_not
{
+ /* allow to check presence od values in max/min optimisation */
+ Item_sum_hybrid *test_sum_item;
+ Item_maxmin_subselect *test_sub_item;
+
bool abort_on_null;
public:
bool show;
- Item_func_not_all(Item *a) :Item_func_not(a), abort_on_null(0), show(0) {}
+ Item_func_not_all(Item *a)
+ :Item_func_not(a), test_sum_item(0), test_sub_item(0), abort_on_null(0),
+ show(0)
+ {}
virtual void top_level_item() { abort_on_null= 1; }
bool top_level() { return abort_on_null; }
longlong val_int();
enum Functype functype() const { return NOT_ALL_FUNC; }
const char *func_name() const { return "<not>"; }
void print(String *str);
+ void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; };
+ void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; };
+ bool empty_underlying_subquery();
};
+
+class Item_func_nop_all :public Item_func_not_all
+{
+public:
+
+ Item_func_nop_all(Item *a) :Item_func_not_all(a) {}
+ longlong val_int();
+ const char *func_name() const { return "<nop>"; }
+};
+
+
class Item_func_eq :public Item_bool_rowready_func2
{
public:
diff --git a/sql/item_create.h b/sql/item_create.h
index d48aed5284a..1be33fef257 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -86,7 +86,7 @@ Item *create_func_soundex(Item* a);
Item *create_func_space(Item *);
Item *create_func_sqrt(Item* a);
Item *create_func_strcmp(Item* a, Item *b);
-Item *create_func_tan(Item* a);;
+Item *create_func_tan(Item* a);
Item *create_func_time_format(Item *a, Item *b);
Item *create_func_time_to_sec(Item* a);
Item *create_func_to_days(Item* a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index aba53b9b397..e2a9071324b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -394,8 +394,8 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
+ ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
- new_item->collation.set(item->collation);
fields.push_front(item);
ref_pointer_array[el]= item;
thd->change_item_tree(arg, new_item);
@@ -855,9 +855,25 @@ longlong Item_func_neg::val_int()
void Item_func_neg::fix_length_and_dec()
{
+ enum Item_result arg_result= args[0]->result_type();
+ enum Item::Type arg_type= args[0]->type();
decimals=args[0]->decimals;
max_length=args[0]->max_length;
hybrid_type= REAL_RESULT;
+
+ /*
+ We need to account for added '-' in the following cases:
+ A) argument is a real or integer positive constant - in this case
+ argument's max_length is set to actual number of bytes occupied, and not
+ maximum number of bytes real or integer may require. Note that all
+ constants are non negative so we don't need to account for removed '-'.
+ B) argument returns a string.
+ */
+ if (arg_result == STRING_RESULT ||
+ (arg_type == REAL_ITEM && ((Item_real*)args[0])->value >= 0) ||
+ (arg_type == INT_ITEM && ((Item_int*)args[0])->value > 0))
+ max_length++;
+
if (args[0]->result_type() == INT_RESULT)
{
/*
@@ -1742,7 +1758,8 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
- if ((*arg)->fix_fields(thd, tables, arg))
+ if (!(*arg)->fixed &&
+ (*arg)->fix_fields(thd, tables, arg))
DBUG_RETURN(1);
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 163260f6428..1a8cb50081b 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -24,7 +24,6 @@
#include "mysql_priv.h"
#ifdef HAVE_SPATIAL
-#include "sql_acl.h"
#include <m_ctype.h>
void Item_geometry_func::fix_length_and_dec()
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 0c7eae9d920..62f31186b09 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -95,6 +95,7 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
+ ref_pointer_array[el]=*arg;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, (*arg)->name);
fields.push_front(*arg);
ref_pointer_array[el]= *arg;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index bf172e1744d..c271ff43fa3 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -25,7 +25,6 @@
#endif
#include "mysql_priv.h"
-#include "sql_acl.h"
#include <m_ctype.h>
#ifdef HAVE_OPENSSL
#include <openssl/des.h>
@@ -955,8 +954,9 @@ String *Item_func_left::val_str(String *str)
if (res->length() <= (uint) length ||
res->length() <= (char_pos= res->charpos(length)))
return res;
- str_value.set(*res, 0, char_pos);
- return &str_value;
+
+ tmp_value.set(*res, 0, char_pos);
+ return &tmp_value;
}
@@ -1748,6 +1748,7 @@ void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array,
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
+ ref_pointer_array[el]=item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
ref_pointer_array[el]= item;
@@ -2332,17 +2333,6 @@ String *Item_func_hex::val_str(String *str)
return &tmp_value;
}
-inline int hexchar_to_int(char c)
-{
- if (c <= '9' && c >= '0')
- return c-'0';
- c|=32;
- if (c <= 'f' && c >= 'a')
- return c-'a'+10;
- return -1;
-}
-
-
/* Convert given hex string to a binary string */
String *Item_func_unhex::val_str(String *str)
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 647cf022d79..e322e5616a1 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -162,6 +162,7 @@ public:
class Item_func_left :public Item_str_func
{
+ String tmp_value;
public:
Item_func_left(Item *a,Item *b) :Item_str_func(a,b) {}
String *val_str(String *);
@@ -396,7 +397,8 @@ public:
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- return (item->fix_fields(thd, tlist, &item) ||
+ return (!item->fixed &&
+ item->fix_fields(thd, tlist, &item) ||
item->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref));
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 304c3ed4bbd..064744158d1 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -155,6 +155,8 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
// did we changed top item of WHERE condition
if (unit->outer_select()->where == (*ref))
unit->outer_select()->where= substitution; // correct WHERE for PS
+ else if (unit->outer_select()->having == (*ref))
+ unit->outer_select()->having= substitution; // correct HAVING for PS
(*ref)= substitution;
substitution->name= name;
@@ -272,7 +274,7 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
Item_subselect *parent,
st_select_lex *select_lex,
bool max_arg)
- :Item_singlerow_subselect()
+ :Item_singlerow_subselect(), was_values(TRUE)
{
DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect");
max= max_arg;
@@ -297,12 +299,31 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
DBUG_VOID_RETURN;
}
+void Item_maxmin_subselect::cleanup()
+{
+ DBUG_ENTER("Item_maxmin_subselect::cleanup");
+ Item_singlerow_subselect::cleanup();
+
+ /*
+ By default it is TRUE to avoid TRUE reporting by
+ Item_func_not_all/Item_func_nop_all if this item was never called.
+
+ Engine exec() set it to FALSE by reset_value_registration() call.
+ select_max_min_finder_subselect::send_data() set it back to TRUE if some
+ value will be found.
+ */
+ was_values= TRUE;
+ DBUG_VOID_RETURN;
+}
+
+
void Item_maxmin_subselect::print(String *str)
{
str->append(max?"<max>":"<min>", 5);
Item_singlerow_subselect::print(str);
}
+
void Item_singlerow_subselect::reset()
{
null_value= 1;
@@ -310,6 +331,7 @@ void Item_singlerow_subselect::reset()
value->null_value= 1;
}
+
Item_subselect::trans_res
Item_singlerow_subselect::select_transformer(JOIN *join)
{
@@ -525,7 +547,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
Item_in_subselect::Item_in_subselect(Item * left_exp,
st_select_lex *select_lex):
- Item_exists_subselect(), transformed(0), upper_not(0)
+ Item_exists_subselect(), transformed(0), upper_item(0)
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr= left_exp;
@@ -687,7 +709,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
NULL/IS NOT NULL functions). If so, we rewrite ALL/ANY with NOT EXISTS
later in this method.
*/
- if ((abort_on_null || (upper_not && upper_not->top_level())) &&
+ if ((abort_on_null || (upper_item && upper_item->top_level())) &&
!select_lex->master_unit()->uncacheable && !func->eqne_op())
{
if (substitution)
@@ -701,7 +723,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
!select_lex->with_sum_func &&
!(select_lex->next_select()))
{
- Item *item;
+ Item_sum_hybrid *item;
if (func->l_op())
{
/*
@@ -718,6 +740,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
item= new Item_sum_min(*select_lex->ref_pointer_array);
}
+ if (upper_item)
+ upper_item->set_sum_test(item);
*select_lex->ref_pointer_array= item;
{
List_iterator<Item> it(select_lex->item_list);
@@ -738,15 +762,19 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
else
{
+ Item_maxmin_subselect *item;
// remove LIMIT placed by ALL/ANY subquery
select_lex->master_unit()->global_parameters->select_limit=
HA_POS_ERROR;
- subs= new Item_maxmin_subselect(thd, this, select_lex, func->l_op());
+ subs= item= new Item_maxmin_subselect(thd, this, select_lex, func->l_op());
+ if (upper_item)
+ upper_item->set_sub_test(item);
}
// left expression belong to outer select
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
- if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
+ if (!left_expr->fixed &&
+ left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
thd->lex->current_select= current;
goto err;
@@ -777,9 +805,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
As far as Item_ref_in_optimizer do not substitude itself on fix_fields
we can use same item for all selects.
*/
- expr= new Item_ref((Item**)optimizer->get_cache(),
- (char *)"<no matter>",
- (char *)in_left_expr_name);
+ expr= new Item_direct_ref((Item**)optimizer->get_cache(),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name);
unit->uncacheable|= UNCACHEABLE_DEPENDENT;
}
@@ -966,9 +994,10 @@ Item_in_subselect::row_value_transformer(JOIN *join)
(char *) "<no matter>",
(char *) "<list ref>");
func=
- eq_creator.create(new Item_ref((*optimizer->get_cache())->addr(i),
- (char *)"<no matter>",
- (char *)in_left_expr_name),
+ eq_creator.create(new Item_direct_ref((*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name),
func);
item= and_items(item, func);
}
@@ -1041,8 +1070,8 @@ Item_subselect::trans_res
Item_allany_subselect::select_transformer(JOIN *join)
{
transformed= 1;
- if (upper_not)
- upper_not->show= 1;
+ if (upper_item)
+ upper_item->show= 1;
return single_value_transformer(join, func);
}
@@ -1241,6 +1270,7 @@ int subselect_single_select_engine::exec()
}
if (!executed)
{
+ item->reset_value_registration();
join->exec();
executed= 1;
thd->where= save_where;
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index d0ff3654e48..53fe21a9bb6 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -93,7 +93,7 @@ public:
return null_value;
}
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
- bool exec();
+ virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
bool const_item() const;
@@ -109,6 +109,11 @@ public:
engine_changed= 1;
return eng == 0;
}
+ /*
+ Used by max/min subquery to initialize value presence registration
+ mechanism. Engine call this method before rexecution query.
+ */
+ virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; }
friend class select_subselect;
@@ -151,13 +156,20 @@ public:
};
/* used in static ALL/ANY optimisation */
+class select_max_min_finder_subselect;
class Item_maxmin_subselect :public Item_singlerow_subselect
{
+protected:
bool max;
+ bool was_values; // Set if we have found at least one row
public:
Item_maxmin_subselect(THD *thd, Item_subselect *parent,
st_select_lex *select_lex, bool max);
void print(String *str);
+ void cleanup();
+ bool any_value() { return was_values; }
+ void register_value() { was_values= TRUE; }
+ void reset_value_registration() { was_values= FALSE; }
};
/* exists subselect */
@@ -205,11 +217,11 @@ protected:
bool abort_on_null;
bool transformed;
public:
- Item_func_not_all *upper_not; // point on NOT before ALL subquery
+ Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
- :Item_exists_subselect(), abort_on_null(0), transformed(0), upper_not(0)
+ :Item_exists_subselect(), abort_on_null(0), transformed(0), upper_item(0)
{}
subs_type substype() { return IN_SUBS; }
@@ -249,7 +261,7 @@ public:
st_select_lex *select_lex, bool all);
// only ALL subquery has upper not
- subs_type substype() { return upper_not?ALL_SUBS:ANY_SUBS; }
+ subs_type substype() { return all?ALL_SUBS:ANY_SUBS; }
trans_res select_transformer(JOIN *join);
void print(String *str);
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 949545bcdb0..92c91b2e866 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -656,9 +656,24 @@ void Item_sum_hybrid::cleanup()
DBUG_ENTER("Item_sum_hybrid::cleanup");
Item_sum::cleanup();
used_table_cache= ~(table_map) 0;
+
+ /*
+ by default it is TRUE to avoid TRUE reporting by
+ Item_func_not_all/Item_func_nop_all if this item was never called.
+
+ no_rows_in_result() set it to FALSE if was not results found.
+ If some results found it will be left unchanged.
+ */
+ was_values= TRUE;
DBUG_VOID_RETURN;
}
+void Item_sum_hybrid::no_rows_in_result()
+{
+ Item_sum::no_rows_in_result();
+ was_values= FALSE;
+}
+
Item *Item_sum_min::copy_or_same(THD* thd)
{
@@ -2017,7 +2032,9 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
for (i=0 ; i < arg_count ; i++)
{
- if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
+ if ((!args[i]->fixed &&
+ args[i]->fix_fields(thd, tables, args + i)) ||
+ args[i]->check_cols(1))
return TRUE;
if (i < arg_count_field)
maybe_null|= args[i]->maybe_null;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index c1352f7ae7d..157791722f6 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -442,18 +442,20 @@ class Item_sum_hybrid :public Item_sum
enum_field_types hybrid_field_type;
int cmp_sign;
table_map used_table_cache;
+ bool was_values; // Set if we have found at least one row (for max/min only)
public:
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
- cmp_sign(sign), used_table_cache(~(table_map) 0)
+ cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item):
Item_sum(thd, item), value(item->value),
sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type),
hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign),
- used_table_cache(item->used_table_cache)
+ used_table_cache(item->used_table_cache),
+ was_values(TRUE)
{ collation.set(item->collation); }
bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
@@ -473,6 +475,8 @@ class Item_sum_hybrid :public Item_sum
void min_max_update_real_field();
void min_max_update_int_field();
void cleanup();
+ bool any_value() { return was_values; }
+ void no_rows_in_result();
};
diff --git a/sql/log.cc b/sql/log.cc
index c659a3ede2e..5d56fefa26a 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -23,7 +23,6 @@
#endif
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "sql_repl.h"
#include "ha_innodb.h" // necessary to cut the binlog when crash recovery
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 760436592b9..581d3ef0d21 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -438,6 +438,9 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
Note that Rotate_log_event::exec_event() does not call this function,
so there is no chance that a fake rotate event resets
last_master_timestamp.
+ Note that we update without mutex (probably ok - except in some very
+ rare cases, only consequence is that value may take some time to
+ display in Seconds_Behind_Master - not critical).
*/
rli->last_master_timestamp= when;
}
@@ -2126,7 +2129,9 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
List<Item> &fields_arg,
enum enum_duplicates handle_dup,
bool using_trans)
- :Log_event(thd_arg, 0, using_trans), thread_id(thd_arg->thread_id),
+ :Log_event(thd_arg, !thd_arg->tmp_table_used ?
+ 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans),
+ thread_id(thd_arg->thread_id),
slave_proxy_id(thd_arg->variables.pseudo_thread_id),
num_fields(0),fields(0),
field_lens(0),field_block_len(0),
@@ -2329,6 +2334,9 @@ void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev
commented ? "# " : "",
db);
+ if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
+ fprintf(file,"%sSET @@session.pseudo_thread_id=%lu;\n",
+ commented ? "# " : "", (ulong)thread_id);
fprintf(file, "%sLOAD DATA ",
commented ? "# " : "");
if (check_fname_outside_temp_buf())
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 2fc82e05f31..c346de98615 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -410,7 +410,6 @@ inline THD *_current_thd(void)
#include "sql_udf.h"
class user_var_entry;
#include "item.h"
-#include "tztime.h"
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
/* sql_parse.cc */
void free_items(Item *item);
@@ -428,7 +427,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
bool mysql_multi_update_prepare(THD *thd);
bool mysql_multi_delete_prepare(THD *thd);
bool mysql_insert_select_prepare(THD *thd);
-bool insert_select_precheck(THD *thd, TABLE_LIST *tables);
bool update_precheck(THD *thd, TABLE_LIST *tables);
bool delete_precheck(THD *thd, TABLE_LIST *tables);
bool insert_precheck(THD *thd, TABLE_LIST *tables);
@@ -436,6 +434,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table);
Item *negate_expression(THD *thd, Item *expr);
#include "sql_class.h"
+#include "sql_acl.h"
+#include "tztime.h"
#include "opt_range.h"
#ifdef HAVE_QUERY_CACHE
@@ -1322,6 +1322,23 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
/*
+ SYNOPSYS
+ hexchar_to_int()
+ convert a hex digit into number
+*/
+
+inline int hexchar_to_int(char c)
+{
+ if (c <= '9' && c >= '0')
+ return c-'0';
+ c|=32;
+ if (c <= 'f' && c >= 'a')
+ return c-'a'+10;
+ return -1;
+}
+
+
+/*
Some functions that are different in the embedded library and the normal
server
*/
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c5698469341..203be4b96a4 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -17,7 +17,6 @@
#include "mysql_priv.h"
#include <m_ctype.h>
#include <my_dir.h>
-#include "sql_acl.h"
#include "slave.h"
#include "sql_repl.h"
#include "repl_failsafe.h"
@@ -55,6 +54,11 @@
#endif
#ifdef HAVE_NDBCLUSTER_DB
#define OPT_NDBCLUSTER_DEFAULT 0
+#ifdef NDB_SHM_TRANSPORTER
+#define OPT_NDB_SHM_DEFAULT 1
+#else
+#define OPT_NDB_SHM_DEFAULT 0
+#endif
#else
#define OPT_NDBCLUSTER_DEFAULT 0
#endif
@@ -289,6 +293,10 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster;
+#ifdef HAVE_NDBCLUSTER_DB
+const char *opt_ndbcluster_connectstring= 0;
+my_bool opt_ndb_shm, opt_ndb_optimized_node_selection;
+#endif
my_bool opt_readonly, use_temp_pool, relay_log_purge;
my_bool opt_sync_bdb_logs, opt_sync_frm;
my_bool opt_secure_auth= 0;
@@ -4108,6 +4116,7 @@ enum options_mysqld
OPT_INNODB, OPT_ISAM,
OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
+ OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION,
OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
@@ -4577,24 +4586,46 @@ Disable with --skip-ndbcluster (will save memory).",
#ifdef HAVE_NDBCLUSTER_DB
{"ndb-connectstring", OPT_NDB_CONNECTSTRING,
"Connect string for ndbcluster.",
- (gptr*) &ndbcluster_connectstring, (gptr*) &ndbcluster_connectstring,
+ (gptr*) &opt_ndbcluster_connectstring,
+ (gptr*) &opt_ndbcluster_connectstring,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"ndb_autoincrement_prefetch_sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
- "Specify number of autoincrement values that are prefetched",
+ {"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
+ "Specify number of autoincrement values that are prefetched.",
(gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz,
(gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz,
0, GET_INT, REQUIRED_ARG, 32, 1, 256, 0, 0, 0},
+ {"ndb-force-send", OPT_NDB_FORCE_SEND,
+ "Force send of buffers to ndb immediately without waiting for "
+ "other threads.",
+ (gptr*) &global_system_variables.ndb_force_send,
+ (gptr*) &global_system_variables.ndb_force_send,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"ndb_force_send", OPT_NDB_FORCE_SEND,
- "Force send of buffers to ndb immediately without waiting for other threads",
+ "same as --ndb-force-send.",
(gptr*) &global_system_variables.ndb_force_send,
(gptr*) &global_system_variables.ndb_force_send,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"ndb-use-exact-count", OPT_NDB_USE_EXACT_COUNT,
+ "Use exact records count during query planning and for fast "
+ "select count(*), disable for faster queries.",
+ (gptr*) &global_system_variables.ndb_use_exact_count,
+ (gptr*) &global_system_variables.ndb_use_exact_count,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"ndb_use_exact_count", OPT_NDB_USE_EXACT_COUNT,
- "Use exact records count during query planning and for "
- "fast select count(*)",
+ "same as --ndb-use-exact-count.",
(gptr*) &global_system_variables.ndb_use_exact_count,
(gptr*) &global_system_variables.ndb_use_exact_count,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"ndb-shm", OPT_NDB_SHM,
+ "Use shared memory connections when available.",
+ (gptr*) &opt_ndb_shm,
+ (gptr*) &opt_ndb_shm,
+ 0, GET_BOOL, OPT_ARG, OPT_NDB_SHM_DEFAULT, 0, 0, 0, 0, 0},
+ {"ndb-optimized-node-selection", OPT_NDB_OPTIMIZED_NODE_SELECTION,
+ "Select nodes for transactions in a more optimal way.",
+ (gptr*) &opt_ndb_optimized_node_selection,
+ (gptr*) &opt_ndb_optimized_node_selection,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
#endif
{"new", 'n', "Use very new possible 'unsafe' functions.",
(gptr*) &global_system_variables.new_mode,
@@ -4895,7 +4926,8 @@ log and this option does nothing anymore.",
(gptr*) &delayed_queue_size, (gptr*) &delayed_queue_size, 0, GET_ULONG,
REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1, 0},
{"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
- "Binary logs will be rotated after expire-log-days days ",
+ "If non-zero, binary logs will be purged after expire_logs_days "
+ "days; possible purges happen at startup and at binary log rotation.",
(gptr*) &expire_logs_days,
(gptr*) &expire_logs_days, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
@@ -5141,7 +5173,7 @@ The minimum value for this variable is 4096.",
"Default pointer size to be used for MyISAM tables.",
(gptr*) &myisam_data_pointer_size,
(gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
- 4, 2, 7, 0, 1, 0},
+ 4, 2, 8, 0, 1, 0},
{"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
"Used to help MySQL to decide when to use the slow but safe key cache index create method.",
(gptr*) &global_system_variables.myisam_max_extra_sort_file_size,
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 899733d8639..3bec00a5177 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -169,8 +169,8 @@ my_bool net_realloc(NET *net, ulong length)
if (length >= net->max_packet_size)
{
- DBUG_PRINT("error",("Packet too large. Max sixe: %lu",
- net->max_packet_size));
+ DBUG_PRINT("error", ("Packet too large. Max size: %lu",
+ net->max_packet_size));
net->error= 1;
net->report_error= 1;
net->last_errno= ER_NET_PACKET_TOO_LARGE;
diff --git a/sql/password.c b/sql/password.c
index e2f7e14d39f..79675ade30b 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -211,12 +211,13 @@ check_scramble_323(const char *scrambled, const char *message,
ulong hash_message[2];
char buff[16],*to,extra; /* Big enough for check */
const char *pos;
-
+
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
to=buff;
- for (pos=scrambled ; *pos ; pos++)
+ DBUG_ASSERT(sizeof(buff) > SCRAMBLE_LENGTH_323);
+ for (pos=scrambled ; *pos && to < buff+sizeof(buff) ; pos++)
*to++=(char) (floor(my_rnd(&rand_st)*31)+64);
if (pos-scrambled != SCRAMBLE_LENGTH_323)
return 1;
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 4c916d78378..d537f9cf829 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -537,10 +537,18 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
pos= (char*) local_packet->ptr()+local_packet->length();
*pos++= 12; // Length of packed fields
if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
+ {
+ /* No conversion */
int2store(pos, field.charsetnr);
+ int4store(pos+2, field.length);
+ }
else
- int2store(pos, thd_charset->number);
- int4store(pos+2, field.length);
+ {
+ /* With conversion */
+ int2store(pos, thd_charset->number);
+ uint char_len= field.length / item->collation.collation->mbmaxlen;
+ int4store(pos+2, char_len * thd_charset->mbmaxlen);
+ }
pos[6]= field.type;
int2store(pos+7,field.flags);
pos[9]= (char) field.decimals;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index b7575f3a44e..7852993b95b 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -20,7 +20,6 @@
#include "repl_failsafe.h"
#include "sql_repl.h"
#include "slave.h"
-#include "sql_acl.h"
#include "log_event.h"
#include <mysql.h>
diff --git a/sql/set_var.cc b/sql/set_var.cc
index da6341597f1..a5370fde671 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -55,7 +55,6 @@
#include "mysql_priv.h"
#include <mysql.h>
#include "slave.h"
-#include "sql_acl.h"
#include <my_getopt.h>
#include <thr_alarm.h>
#include <myisam.h>
@@ -374,22 +373,18 @@ sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks",
sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment",
&srv_auto_extend_increment);
#endif
+
#ifdef HAVE_NDBCLUSTER_DB
-// ndb thread specific variable settings
+/* ndb thread specific variable settings */
sys_var_thd_ulong
sys_ndb_autoincrement_prefetch_sz("ndb_autoincrement_prefetch_sz",
&SV::ndb_autoincrement_prefetch_sz);
sys_var_thd_bool
-sys_ndb_force_send("ndb_force_send",
- &SV::ndb_force_send);
+sys_ndb_force_send("ndb_force_send", &SV::ndb_force_send);
sys_var_thd_bool
-sys_ndb_use_exact_count("ndb_use_exact_count",
- &SV::ndb_use_exact_count);
+sys_ndb_use_exact_count("ndb_use_exact_count", &SV::ndb_use_exact_count);
sys_var_thd_bool
-sys_ndb_use_transactions("ndb_use_transactions",
- &SV::ndb_use_transactions);
-// ndb server global variable settings
-// none
+sys_ndb_use_transactions("ndb_use_transactions", &SV::ndb_use_transactions);
#endif
/* Time/date/datetime formats */
@@ -2856,7 +2851,8 @@ int set_var::check(THD *thd)
return 0;
}
- if (value->fix_fields(thd, 0, &value) || value->check_cols(1))
+ if ((!value->fixed &&
+ value->fix_fields(thd, 0, &value)) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
{
@@ -2890,7 +2886,8 @@ int set_var::light_check(THD *thd)
if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
return 1;
- if (value && (value->fix_fields(thd, 0, &value) || value->check_cols(1)))
+ if (value && ((!value->fixed && value->fix_fields(thd, 0, &value)) ||
+ value->check_cols(1)))
return -1;
return 0;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 9ddbe7d05de..6b8559859fc 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -658,7 +658,7 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
pthread_mutex_t *cond_lock,
pthread_cond_t* term_cond,
- volatile bool* slave_running)
+ volatile uint *slave_running)
{
if (term_lock)
{
@@ -696,7 +696,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
pthread_mutex_t *cond_lock,
pthread_cond_t *start_cond,
- volatile bool *slave_running,
+ volatile uint *slave_running,
volatile ulong *slave_run_id,
MASTER_INFO* mi,
bool high_priority)
@@ -1081,7 +1081,7 @@ void end_slave()
static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
{
DBUG_ASSERT(mi->io_thd == thd);
- DBUG_ASSERT(mi->slave_running == 1); // tracking buffer overrun
+ DBUG_ASSERT(mi->slave_running); // tracking buffer overrun
return mi->abort_slave || abort_loop || thd->killed;
}
@@ -1949,19 +1949,13 @@ void init_master_info_with_options(MASTER_INFO* mi)
strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
}
-static void clear_slave_error(RELAY_LOG_INFO* rli)
+void clear_slave_error(RELAY_LOG_INFO* rli)
{
/* Clear the errors displayed by SHOW SLAVE STATUS */
rli->last_slave_error[0]= 0;
rli->last_slave_errno= 0;
}
-void clear_slave_error_timestamp(RELAY_LOG_INFO* rli)
-{
- rli->last_master_timestamp= 0;
- clear_slave_error(rli);
-}
-
/*
Reset UNTIL condition for RELAY_LOG_INFO
SYNOPSYS
@@ -2349,6 +2343,11 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
String *packet= &thd->packet;
protocol->prepare_for_resend();
+ /*
+ TODO: we read slave_running without run_lock, whereas these variables
+ are updated under run_lock and not data_lock. In 5.0 we should lock
+ run_lock on top of data_lock (with good order).
+ */
pthread_mutex_lock(&mi->data_lock);
pthread_mutex_lock(&mi->rli.data_lock);
@@ -2409,7 +2408,12 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store(mi->ssl_cipher, &my_charset_bin);
protocol->store(mi->ssl_key, &my_charset_bin);
- if (mi->rli.last_master_timestamp)
+ /*
+ Seconds_Behind_Master: if SQL thread is running and I/O thread is
+ connected, we can compute it otherwise show NULL (i.e. unknown).
+ */
+ if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
+ mi->rli.slave_running)
{
long tmp= (long)((time_t)time((time_t*) 0)
- mi->rli.last_master_timestamp)
@@ -2429,9 +2433,13 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
slave is 2. At SHOW SLAVE STATUS time, assume that the difference
between timestamp of slave and rli->last_master_timestamp is 0
(i.e. they are in the same second), then we get 0-(2-1)=-1 as a result.
- This confuses users, so we don't go below 0.
+ This confuses users, so we don't go below 0: hence the max().
+
+ last_master_timestamp == 0 (an "impossible" timestamp 1970) is a
+ special marker to say "consider we have caught up".
*/
- protocol->store((longlong)(max(0, tmp)));
+ protocol->store((longlong)(mi->rli.last_master_timestamp ? max(0, tmp)
+ : 0));
}
else
protocol->store_null();
@@ -3280,6 +3288,8 @@ slave_begin:
connected:
+ // TODO: the assignment below should be under mutex (5.0)
+ mi->slave_running= MYSQL_SLAVE_RUN_CONNECT;
thd->slave_net = &mysql->net;
thd->proc_info = "Checking master version";
if (get_master_version_and_clock(mysql, mi))
@@ -3312,6 +3322,7 @@ dump");
goto err;
}
+ mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
#ifdef SIGNAL_WITH_VIO_CLOSE
thd->clear_active_vio();
@@ -3388,6 +3399,7 @@ max_allowed_packet",
mysql_error(mysql));
goto err;
}
+ mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
thd->proc_info = "Waiting to reconnect after a failed master event read";
#ifdef SIGNAL_WITH_VIO_CLOSE
thd->clear_active_vio();
@@ -3566,6 +3578,14 @@ slave_begin:
pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd);
pthread_mutex_unlock(&LOCK_thread_count);
+ /*
+ We are going to set slave_running to 1. Assuming slave I/O thread is
+ alive and connected, this is going to make Seconds_Behind_Master be 0
+ i.e. "caught up". Even if we're just at start of thread. Well it's ok, at
+ the moment we start we can think we are caught up, and the next second we
+ start receiving data so we realize we are not caught up and
+ Seconds_Behind_Master grows. No big deal.
+ */
rli->slave_running = 1;
rli->abort_slave = 0;
pthread_mutex_unlock(&rli->run_lock);
@@ -4604,6 +4624,21 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
*/
if (hot_log)
{
+ /*
+ We say in Seconds_Behind_Master that we have "caught up". Note that
+ for example if network link is broken but I/O slave thread hasn't
+ noticed it (slave_net_timeout not elapsed), then we'll say "caught
+ up" whereas we're not really caught up. Fixing that would require
+ internally cutting timeout in smaller pieces in network read, no
+ thanks. Another example: SQL has caught up on I/O, now I/O has read
+ a new event and is queuing it; the false "0" will exist until SQL
+ finishes executing the new event; it will be look abnormal only if
+ the events have old timestamps (then you get "many", 0, "many").
+ Transient phases like this can't really be fixed.
+ */
+ time_t save_timestamp= rli->last_master_timestamp;
+ rli->last_master_timestamp= 0;
+
DBUG_ASSERT(rli->relay_log.get_open_count() == rli->cur_log_old_open_count);
/*
We can, and should release data_lock while we are waiting for
@@ -4650,6 +4685,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
rli->relay_log.wait_for_update(rli->sql_thd, 1);
// re-acquire data lock since we released it earlier
pthread_mutex_lock(&rli->data_lock);
+ rli->last_master_timestamp= save_timestamp;
continue;
}
/*
diff --git a/sql/slave.h b/sql/slave.h
index 69d3dc38e78..e0816fd45a7 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -93,6 +93,21 @@ extern my_bool opt_log_slave_updates;
extern ulonglong relay_log_space_limit;
struct st_master_info;
+/*
+ 3 possible values for MASTER_INFO::slave_running and
+ RELAY_LOG_INFO::slave_running.
+ The values 0,1,2 are very important: to keep the diff small, I didn't
+ substitute places where we use 0/1 with the newly defined symbols. So don't change
+ these values.
+ The same way, code is assuming that in RELAY_LOG_INFO we use only values
+ 0/1.
+ I started with using an enum, but
+ enum_variable=1; is not legal so would have required many line changes.
+*/
+#define MYSQL_SLAVE_NOT_RUN 0
+#define MYSQL_SLAVE_RUN_NOT_CONNECT 1
+#define MYSQL_SLAVE_RUN_CONNECT 2
+
/****************************************************************************
Replication SQL Thread
@@ -248,7 +263,8 @@ typedef struct st_relay_log_info
/* if not set, the value of other members of the structure are undefined */
bool inited;
- volatile bool abort_slave, slave_running;
+ volatile bool abort_slave;
+ volatile uint slave_running;
/*
Condition and its parameters from START SLAVE UNTIL clause.
@@ -383,7 +399,8 @@ typedef struct st_master_info
int events_till_abort;
#endif
bool inited;
- volatile bool abort_slave, slave_running;
+ volatile bool abort_slave;
+ volatile uint slave_running;
volatile ulong slave_run_id;
/*
The difference in seconds between the clock of the master and the clock of
@@ -462,7 +479,7 @@ int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex,
pthread_mutex_t* cond_lock,
pthread_cond_t* term_cond,
- volatile bool* slave_running);
+ volatile uint* slave_running);
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname, int thread_mask);
@@ -475,7 +492,7 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
pthread_mutex_t *cond_lock,
pthread_cond_t* start_cond,
- volatile bool *slave_running,
+ volatile uint *slave_running,
volatile ulong *slave_run_id,
MASTER_INFO* mi,
bool high_priority);
@@ -517,7 +534,7 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...);
void end_slave(); /* clean up */
void init_master_info_with_options(MASTER_INFO* mi);
void clear_until_condition(RELAY_LOG_INFO* rli);
-void clear_slave_error_timestamp(RELAY_LOG_INFO* rli);
+void clear_slave_error(RELAY_LOG_INFO* rli);
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
bool abort_if_no_master_info_file,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index d33faffb2c2..81419d64e15 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -26,7 +26,6 @@
*/
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "hash_filo.h"
#ifdef HAVE_REPLICATION
#include "sql_repl.h" //for tables_ok()
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 2500769ee30..250da2981ff 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -18,7 +18,6 @@
/* Basic functions needed by many modules */
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "sql_select.h"
#include "sp_head.h"
#include "sql_trigger.h"
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 39ee8f61f1a..26b1eff49e7 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -300,7 +300,6 @@ TODO list:
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
-#include "sql_acl.h"
#include "ha_myisammrg.h"
#ifndef MASTER
#include "../srclib/myisammrg/myrg_def.h"
@@ -375,7 +374,7 @@ inline Query_cache_block * Query_cache_block_table::block()
return (Query_cache_block *)(((byte*)this) -
ALIGN_SIZE(sizeof(Query_cache_block_table)*n) -
ALIGN_SIZE(sizeof(Query_cache_block)));
-};
+}
/*****************************************************************************
Query_cache_block method(s)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index cc178a3121b..d369e85d775 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -27,7 +27,6 @@
#endif
#include "mysql_priv.h"
-#include "sql_acl.h"
#include <m_ctype.h>
#include <sys/stat.h>
#include <thr_alarm.h>
@@ -1025,7 +1024,7 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
return -1;
}
/* Create the file world readable */
- if ((file= my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
+ if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
return file;
#ifdef HAVE_FCHMOD
(void) fchmod(file, 0666); // Because of umask()
@@ -1307,9 +1306,10 @@ bool select_singlerow_subselect::send_data(List<Item> &items)
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_max_min_finder_subselect::send_data");
- Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
+ Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
List_iterator_fast<Item> li(items);
Item *val_item= li++;
+ it->register_value();
if (it->assigned())
{
cache->store(val_item);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 6cec2c2c787..149d12225a3 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1371,9 +1371,11 @@ class select_insert :public select_result_interceptor {
COPY_INFO info;
bool insert_into_view;
- select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
- List<Item> *fields_par, enum_duplicates duplic,
- bool ignore_check_option_errors);
+ select_insert(TABLE_LIST *table_list_par,
+ TABLE *table_par, List<Item> *fields_par,
+ List<Item> *update_fields, List<Item> *update_values,
+ enum_duplicates duplic,
+ bool ignore_check_option_errors);
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index ea81013a401..d3b30de0bcd 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -19,7 +19,6 @@
#include "mysql_priv.h"
#include <mysys_err.h>
-#include "sql_acl.h"
#include "sp.h"
#include <my_dir.h>
#include <m_ctype.h>
@@ -399,7 +398,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- // do not create database if another thread is holding read lock
+ /* do not create database if another thread is holding read lock */
if (wait_if_global_read_lock(thd, 0, 1))
{
error= -1;
@@ -522,7 +521,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- // do not alter database if another thread is holding read lock
+ /* do not alter database if another thread is holding read lock */
if ((error=wait_if_global_read_lock(thd,0,1)))
goto exit2;
@@ -549,9 +548,11 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
Query_log_event qinfo(thd, thd->query, thd->query_length, 0,
/* suppress_use */ TRUE);
- // Write should use the database being created as the "current
- // database" and not the threads current database, which is the
- // default.
+ /*
+ Write should use the database being created as the "current
+ database" and not the threads current database, which is the
+ default.
+ */
qinfo.db = db;
qinfo.db_len = strlen(db);
@@ -595,7 +596,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- // do not drop database if another thread is holding read lock
+ /* do not drop database if another thread is holding read lock */
if (wait_if_global_read_lock(thd, 0, 1))
{
error= -1;
@@ -662,10 +663,11 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
Query_log_event qinfo(thd, query, query_length, 0,
/* suppress_use */ TRUE);
-
- // Write should use the database being created as the "current
- // database" and not the threads current database, which is the
- // default.
+ /*
+ Write should use the database being created as the "current
+ database" and not the threads current database, which is the
+ default.
+ */
qinfo.db = db;
qinfo.db_len = strlen(db);
@@ -799,7 +801,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
found_other_files++;
continue;
}
- // just for safety we use files_charset_info
+ /* just for safety we use files_charset_info */
if (db && !my_strcasecmp(files_charset_info,
extension, reg_ext))
{
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 1d4b911bb65..520393f8544 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -23,7 +23,6 @@
#include "mysql_priv.h"
#include "sql_select.h"
-#include "sql_acl.h"
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 3f34835c2c9..e37f3e86dda 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -18,7 +18,6 @@
/* Execute DO statement */
#include "mysql_priv.h"
-#include "sql_acl.h"
bool mysql_do(THD *thd, List<Item> &values)
{
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 853b3dd37c6..2ee7734e4f3 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -409,7 +409,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- if (cond && (cond->fix_fields(thd, tables, &cond) || cond->check_cols(1)))
+ if (cond && ((!cond->fixed &&
+ cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
goto err0;
table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
@@ -494,7 +495,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
// 'item' can be changed by fix_fields() call
- if (item->fix_fields(thd, tables, it_ke.ref()) ||
+ if ((!item->fixed &&
+ item->fix_fields(thd, tables, it_ke.ref())) ||
(item= *it_ke.ref())->check_cols(1))
goto err;
if (item->used_tables() & ~RAND_TABLE_BIT)
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index f71e9a7133a..99273b42f2a 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -556,7 +556,8 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables,
TABLE *table, int *error)
{
- cond->fix_fields(thd, tables, &cond); // can never fail
+ if (!cond->fixed)
+ cond->fix_fields(thd, tables, &cond); // can never fail
SQL_SELECT *res= make_select(table,0,0,cond,error);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)))
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 0814c7a747e..e2b7ee93905 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -18,7 +18,6 @@
/* Insert of records */
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "sp_head.h"
#include "sql_trigger.h"
#include "sql_select.h"
@@ -244,13 +243,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->used_tables=0;
values= its++;
- if (duplic == DUP_UPDATE)
- {
- /* it should be allocated before Item::fix_fields() */
- if (table_list->set_insert_values(thd->mem_root))
- goto abort;
- }
-
if (mysql_prepare_insert(thd, table_list, table, fields, values,
update_fields, update_values, duplic))
goto abort;
@@ -666,26 +658,33 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
*/
bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
- List<Item> &fields, List_item *values,
- List<Item> &update_fields, List<Item> &update_values,
- enum_duplicates duplic)
+ List<Item> &fields, List_item *values,
+ List<Item> &update_fields, List<Item> &update_values,
+ enum_duplicates duplic)
{
bool insert_into_view= (table_list->view != 0);
/* TODO: use this condition for 'WITH CHECK OPTION' */
Item *unused_conds= 0;
bool res;
DBUG_ENTER("mysql_prepare_insert");
-
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
+
+ if (duplic == DUP_UPDATE)
+ {
+ /* it should be allocated before Item::fix_fields() */
+ if (table_list->set_insert_values(thd->mem_root))
+ goto abort;
+ }
+
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds,
FALSE))
DBUG_RETURN(TRUE);
- if (check_insert_fields(thd, table_list, fields, *values, 1,
- !insert_into_view) ||
- setup_fields(thd, 0, table_list, *values, 0, 0, 0) ||
+ if ((values && check_insert_fields(thd, table_list, fields, *values, 1,
+ !insert_into_view)) ||
+ (values && setup_fields(thd, 0, table_list, *values, 0, 0, 0)) ||
(duplic == DUP_UPDATE &&
((thd->lex->select_lex.no_wrap_view_item= 1,
(res= setup_fields(thd, 0, table_list, update_fields, 1, 0, 0)),
@@ -697,7 +696,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
if (!table)
table= table_list->table;
- if (unique_table(table_list, table_list->next_global))
+ if ((thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->sql_command == SQLCOM_REPLACE) &&
+ unique_table(table_list, table_list->next_global))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(TRUE);
@@ -795,8 +796,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
that matches, is updated. If update causes a conflict again,
an error is returned
*/
+ DBUG_ASSERT(table->insert_values != NULL);
store_record(table,insert_values);
restore_record(table,record[1]);
+ DBUG_ASSERT(info->update_fields->elements == info->update_values->elements);
if (fill_record(thd, *info->update_fields, *info->update_values, 0))
goto err;
@@ -1753,17 +1756,21 @@ bool mysql_insert_select_prepare(THD *thd)
select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
- List<Item> *fields_par, enum_duplicates duplic,
+ List<Item> *fields_par,
+ List<Item> *update_fields, List<Item> *update_values,
+ enum_duplicates duplic,
bool ignore_check_option_errors)
:table_list(table_list_par), table(table_par), fields(fields_par),
last_insert_id(0),
insert_into_view(table_list_par && table_list_par->view != 0)
{
bzero((char*) &info,sizeof(info));
- info.handle_duplicates=duplic;
+ info.handle_duplicates= duplic;
+ info.ignore= ignore_check_option_errors;
+ info.update_fields= update_fields;
+ info.update_values= update_values;
if (table_list_par)
info.view= (table_list_par->view ? table_list_par : 0);
- info.ignore= ignore_check_option_errors;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 2205ec504e9..ece960c5d1c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -129,6 +129,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->thd= lex->unit.thd= thd;
lex->select_lex.init_query();
lex->value_list.empty();
+ lex->update_list.empty();
lex->param_list.empty();
lex->view_list.empty();
lex->unit.next= lex->unit.master=
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7a4ef0b98e5..3ef475b89b0 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -682,7 +682,7 @@ typedef struct st_lex
List<LEX_COLUMN> columns;
List<Key> key_list;
List<create_field> create_list;
- List<Item> *insert_list,field_list,value_list;
+ List<Item> *insert_list,field_list,value_list,update_list;
List<List_item> many_values;
List<set_var_base> var_list;
List<Item_param> param_list;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 01e80653372..b5b0d76dcf3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -15,7 +15,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "sql_repl.h"
#include "repl_failsafe.h"
#include <m_ctype.h>
@@ -1129,13 +1128,26 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
- uint length=(uint) strlen(buff);
- if (buff[length-1]!='\n' && !feof(file))
- {
- net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
- thd->fatal_error();
- break;
- }
+ ulong length= (ulong) strlen(buff);
+ while (buff[length-1] != '\n' && !feof(file))
+ {
+ /*
+ We got only a part of the current string. Will try to increase
+ net buffer then read the rest of the current string.
+ */
+ if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
+ {
+ net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
+ thd->fatal_error();
+ break;
+ }
+ buff= (char*) thd->net.buff;
+ fgets(buff + length, thd->net.max_packet - length, file);
+ length+= (ulong) strlen(buff + length);
+ }
+ if (thd->is_fatal_error)
+ break;
+
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
buff[length-1] == ';'))
length--;
@@ -2817,7 +2829,9 @@ create_error:
check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
&first_table->grant.privilege, 0, 0))
goto error;
- res = mysqld_show_create(thd, first_table);
+ if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
+ goto error;
+ res= mysqld_show_create(thd, first_table);
break;
}
#endif
@@ -2945,7 +2959,7 @@ create_error:
if ((res= insert_precheck(thd, all_tables)))
break;
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
- select_lex->item_list, lex->value_list,
+ lex->update_list, lex->value_list,
(lex->value_list.elements ?
DUP_UPDATE : lex->duplicates));
if (first_table->view && !first_table->contain_auto_increment)
@@ -2956,7 +2970,7 @@ create_error:
case SQLCOM_INSERT_SELECT:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if ((res= insert_select_precheck(thd, all_tables)))
+ if ((res= insert_precheck(thd, all_tables)))
break;
/* Fix lock for first table */
@@ -2969,19 +2983,23 @@ create_error:
select_result *result;
unit->set_limit(select_lex, select_lex);
- if (!(res= open_and_lock_tables(thd, all_tables)))
+ if (!(res= open_and_lock_tables(thd, all_tables)) &&
+ !(res= mysql_prepare_insert(thd, tables, first_local_table,
+ tables->table, lex->field_list, 0,
+ lex->update_list, lex->value_list,
+ lex->duplicates)))
{
+ TABLE *table= tables->table;
/* Skip first table, which is the table we are inserting in */
lex->select_lex.table_list.first= (byte*)first_table->next_local;
res= mysql_insert_select_prepare(thd);
if (!res && (result= new select_insert(first_table, first_table->table,
&lex->field_list,
+ &lex->update_list, &lex->value_list,
lex->duplicates,
lex->duplicates == DUP_IGNORE)))
{
- TABLE_LIST *first_select_table;
-
/*
insert/replace from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
@@ -2990,6 +3008,7 @@ create_error:
res= handle_select(thd, lex, result);
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result;
+ table->insert_values= 0;
}
/* revert changes for SP */
lex->select_lex.table_list.first= (byte*) first_table;
@@ -3355,7 +3374,13 @@ create_error:
}
case SQLCOM_ALTER_DB:
{
- if (!strip_sp(lex->name) || check_db_name(lex->name))
+ char *db= lex->name ? lex->name : thd->db;
+ if (!db)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ break;
+ }
+ if (!strip_sp(db) || check_db_name(db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
@@ -3369,14 +3394,14 @@ create_error:
*/
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
- (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
- !db_ok_with_wild_table(lex->name)))
+ (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
+ !db_ok_with_wild_table(db)))
{
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
- if (check_access(thd,ALTER_ACL,lex->name,0,1,0))
+ if (check_access(thd, ALTER_ACL, db, 0, 1, 0))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -3384,7 +3409,7 @@ create_error:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res=mysql_alter_db(thd,lex->name,&lex->create_info);
+ res= mysql_alter_db(thd, db, &lex->create_info);
break;
}
case SQLCOM_SHOW_CREATE_DB:
@@ -3396,12 +3421,6 @@ create_error:
}
if (check_access(thd,SELECT_ACL,lex->name,0,1,0))
break;
- if (thd->locked_tables || thd->active_transaction())
- {
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- goto error;
- }
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
break;
}
@@ -4093,7 +4112,7 @@ error:
/*
Check grants for commands which work only with one table and all other
- tables belong to subselects.
+ tables belonging to subselects or implicitly opened tables.
SYNOPSIS
check_one_table_access()
@@ -4116,7 +4135,7 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
return 1;
- /* Check rights on tables of subselect (if exists) */
+ /* Check rights on tables of subselects and implictly opened tables */
TABLE_LIST *subselects_tables;
if ((subselects_tables= all_tables->next_global))
{
@@ -5977,9 +5996,9 @@ Item * all_any_subquery_creator(Item *left_expr,
Item_allany_subselect *it=
new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
if (all)
- return it->upper_not= new Item_func_not_all(it); /* ALL */
+ return it->upper_item= new Item_func_not_all(it); /* ALL */
- return it; /* ANY/SOME */
+ return it->upper_item= new Item_func_nop_all(it); /* ANY/SOME */
}
@@ -6083,6 +6102,9 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
DBUG_PRINT("info",("Checking sub query list"));
for (table= tables; table; table= table->next_global)
{
+ if (my_tz_check_n_skip_implicit_tables(&table,
+ lex->time_zone_tables_used))
+ continue;
if (!table->table_in_first_from_clause && table->derived)
{
if (check_access(thd, SELECT_ACL, table->db,
@@ -6168,32 +6190,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
/*
- INSERT ... SELECT query pre-check
-
- SYNOPSIS
- insert_delete_precheck()
- thd Thread handler
- tables Global table list
-
- RETURN VALUE
- FALSE OK
- TRUE Error
-*/
-
-bool insert_select_precheck(THD *thd, TABLE_LIST *tables)
-{
- DBUG_ENTER("insert_select_precheck");
- /*
- Check that we have modify privileges for the first table and
- select privileges for the rest
- */
- ulong privilege= (thd->lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
- DBUG_RETURN(check_one_table_access(thd, privilege, tables));
-}
-
-
-/*
simple UPDATE query pre-check
SYNOPSIS
@@ -6261,6 +6257,10 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
LEX *lex= thd->lex;
DBUG_ENTER("insert_precheck");
+ /*
+ Check that we have modify privileges for the first table and
+ select privileges for the rest
+ */
ulong privilege= (INSERT_ACL |
(lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
(lex->value_list.elements ? UPDATE_ACL : 0));
@@ -6268,7 +6268,7 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
if (check_one_table_access(thd, privilege, tables))
DBUG_RETURN(TRUE);
- if (lex->select_lex.item_list.elements != lex->value_list.elements)
+ if (lex->update_list.elements != lex->value_list.elements)
{
my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
DBUG_RETURN(TRUE);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 8afefe3cae8..e4e61dc8d31 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -68,7 +68,6 @@ Long data handling:
***********************************************************************/
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "sql_select.h" // for JOIN
#include <m_ctype.h> // for isspace()
#include "sp_head.h"
@@ -1387,7 +1386,7 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
{
int res;
LEX *lex= stmt->lex;
- if ((res= insert_select_precheck(stmt->thd, tables)))
+ if ((res= insert_precheck(stmt->thd, tables)))
return res;
TABLE_LIST *first_local_table=
(TABLE_LIST *)lex->select_lex.table_list.first;
@@ -1584,6 +1583,27 @@ static bool init_param_array(Prepared_statement *stmt)
}
+/* Init statement before execution */
+
+static void cleanup_stmt_for_execute(Prepared_statement *stmt)
+{
+ THD *thd= stmt->thd;
+ LEX *lex= stmt->lex;
+ SELECT_LEX *sl= lex->all_selects_list;
+
+ for (; sl; sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first;
+ tables;
+ tables= tables->next)
+ {
+ if (tables->table)
+ tables->table->insert_values= 0;
+ }
+ }
+}
+
+
/*
Given a query string with parameter markers, create a Prepared Statement
from it and send PS info back to the client.
@@ -1678,6 +1698,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
if (!error)
error= check_prepared_statement(stmt, test(name));
+ cleanup_stmt_for_execute(stmt);
/* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -2038,6 +2059,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup);
+ cleanup_stmt_for_execute(stmt);
thd->cleanup_after_query();
if (stmt->state == Item_arena::PREPARED)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 0d1a7f3890d..9f083e19146 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -18,7 +18,6 @@
#ifdef HAVE_REPLICATION
#include "sql_repl.h"
-#include "sql_acl.h"
#include "log_event.h"
#include <my_dir.h>
@@ -977,10 +976,10 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
*/
init_master_info_with_options(mi);
/*
- Reset errors, and master timestamp (the idea is that we forget about the
+ Reset errors (the idea is that we forget about the
old master).
*/
- clear_slave_error_timestamp(&mi->rli);
+ clear_slave_error(&mi->rli);
clear_until_condition(&mi->rli);
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
@@ -1240,8 +1239,8 @@ bool change_master(THD* thd, MASTER_INFO* mi)
pthread_mutex_lock(&mi->rli.data_lock);
mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
- /* Clear the errors, for a clean start, and master timestamp */
- clear_slave_error_timestamp(&mi->rli);
+ /* Clear the errors, for a clean start */
+ clear_slave_error(&mi->rli);
clear_until_condition(&mi->rli);
/*
If we don't write new coordinates to disk now, then old will remain in
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 570774c8054..44eb411ed44 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1543,7 +1543,7 @@ JOIN::exec()
WHERE clause for any tables after the sorted one.
*/
JOIN_TAB *curr_table= &curr_join->join_tab[curr_join->const_tables+1];
- JOIN_TAB *end_table= &curr_join->join_tab[tables];
+ JOIN_TAB *end_table= &curr_join->join_tab[curr_join->tables];
for (; curr_table < end_table ; curr_table++)
{
/*
@@ -9213,7 +9213,7 @@ join_read_system(JOIN_TAB *tab)
{
if (error != HA_ERR_END_OF_FILE)
return report_error(table, error);
- table->null_row=1; // This is ok.
+ mark_as_null_row(tab->table);
empty_record(table); // Make empty record
return -1;
}
@@ -9258,7 +9258,7 @@ join_read_const(JOIN_TAB *tab)
if (error)
{
table->status= STATUS_NOT_FOUND;
- table->null_row=1;
+ mark_as_null_row(tab->table);
empty_record(table);
if (error != HA_ERR_KEY_NOT_FOUND)
return report_error(table, error);
@@ -12266,7 +12266,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
if (thd->is_fatal_error)
DBUG_RETURN(TRUE);
- cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond);
+ if (!cond->fixed)
+ cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond);
if (join_tab->select)
{
error=(int) cond->add(join_tab->select->cond);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 826bd2038f9..986f8027df2 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -19,7 +19,6 @@
#include "mysql_priv.h"
#include "sql_select.h" // For select_describe
-#include "sql_acl.h"
#include "repl_failsafe.h"
#include "sp_head.h"
#include <my_dir.h>
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6629122a1fa..3cc421b1312 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -491,44 +491,45 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
- if ((sql_field->sql_type == FIELD_TYPE_SET ||
- sql_field->sql_type == FIELD_TYPE_ENUM) && !sql_field->interval)
+ if (sql_field->sql_type == FIELD_TYPE_SET ||
+ sql_field->sql_type == FIELD_TYPE_ENUM)
{
uint32 dummy;
CHARSET_INFO *cs= sql_field->charset;
- TYPELIB *interval;
+ TYPELIB *interval= sql_field->interval;
/*
Create typelib from interval_list, and if necessary
convert strings from client character set to the
column character set.
*/
-
- interval= sql_field->interval= typelib(sql_field->interval_list);
- List_iterator<String> it(sql_field->interval_list);
- String conv, *tmp;
- for (uint i= 0; (tmp= it++); i++)
+ if (!interval)
{
- if (String::needs_conversion(tmp->length(), tmp->charset(), cs,
- &dummy))
+ interval= sql_field->interval= typelib(sql_field->interval_list);
+ List_iterator<String> it(sql_field->interval_list);
+ String conv, *tmp;
+ for (uint i= 0; (tmp= it++); i++)
{
- uint cnv_errs;
- conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
- char *buf= (char*) sql_alloc(conv.length()+1);
- memcpy(buf, conv.ptr(), conv.length());
- buf[conv.length()]= '\0';
- interval->type_names[i]= buf;
- interval->type_lengths[i]= conv.length();
- }
+ if (String::needs_conversion(tmp->length(), tmp->charset(),
+ cs, &dummy))
+ {
+ uint cnv_errs;
+ conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
+ char *buf= (char*) sql_alloc(conv.length()+1);
+ memcpy(buf, conv.ptr(), conv.length());
+ buf[conv.length()]= '\0';
+ interval->type_names[i]= buf;
+ interval->type_lengths[i]= conv.length();
+ }
- // Strip trailing spaces.
- uint lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
- interval->type_lengths[i]);
- interval->type_lengths[i]= lengthsp;
- ((uchar *)interval->type_names[i])[lengthsp]= '\0';
+ // Strip trailing spaces.
+ uint lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
+ interval->type_lengths[i]);
+ interval->type_lengths[i]= lengthsp;
+ ((uchar *)interval->type_names[i])[lengthsp]= '\0';
+ }
+ sql_field->interval_list.empty(); // Don't need interval_list anymore
}
- sql_field->interval_list.empty(); // Don't need interval_list anymore
-
/*
Convert the default value from client character
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 815e04c0111..d0a33163a38 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -398,6 +398,8 @@ bool st_select_lex_unit::exec()
if (uncacheable || !item || !item->assigned() || describe)
{
+ if (item)
+ item->reset_value_registration();
if (optimized && item)
{
if (item->assigned())
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 9613e39d403..fa4acce31f7 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -21,7 +21,6 @@
*/
#include "mysql_priv.h"
-#include "sql_acl.h"
#include "sql_select.h"
#include "sp_head.h"
#include "sql_trigger.h"
@@ -225,7 +224,7 @@ int mysql_update(THD *thd,
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
#endif
- if (setup_fields(thd, 0, table_list, values, 0, 0, 0))
+ if (setup_fields(thd, 0, table_list, values, 1, 0, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@@ -740,6 +739,19 @@ bool mysql_multi_update_prepare(THD *thd)
}
if (!using_lock_tables)
tl->table->reginfo.lock_type= tl->lock_type;
+
+ /* Check access privileges for table */
+ {
+ TABLE_LIST *save= tl->next;
+ bool res;
+ tl->next= 0;
+ res= (check_access(thd, tl->updating ? UPDATE_ACL : SELECT_ACL,
+ tl->db, &tl->grant.privilege, 0, 0) ||
+ (grant_option && check_grant(thd, wants, tl, 0, 0, 0)));
+ tl->next= save;
+ if (res)
+ DBUG_RETURN(TRUE);
+ }
}
/* check single table update for view compound from several tables */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 99b8caed784..1c2dde5d278 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -32,7 +32,6 @@
#define Select Lex->current_select
#include "mysql_priv.h"
#include "slave.h"
-#include "sql_acl.h"
#include "lex_symbol.h"
#include "item_create.h"
#include "sp_head.h"
@@ -675,7 +674,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <simple_string>
remember_name remember_end opt_ident opt_db text_or_password
- opt_constraint constraint
+ opt_constraint constraint ident_or_empty
%type <string>
text_string opt_gconcat_separator
@@ -3236,7 +3235,7 @@ alter:
}
alter_list
{}
- | ALTER DATABASE ident
+ | ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
@@ -3245,7 +3244,7 @@ alter:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_ALTER_DB;
- lex->name=$3.str;
+ lex->name= $3;
}
| ALTER PROCEDURE sp_name
{
@@ -3289,6 +3288,10 @@ alter:
{}
;
+ident_or_empty:
+ /* empty */ { $$= 0; }
+ | ident { $$= $1.str; };
+
alter_list:
| DISCARD TABLESPACE { Lex->alter_info.tablespace_op= DISCARD_TABLESPACE; }
| IMPORT TABLESPACE { Lex->alter_info.tablespace_op= IMPORT_TABLESPACE; }
@@ -5714,19 +5717,7 @@ expr_or_default:
opt_insert_update:
/* empty */
| ON DUPLICATE_SYM
- {
- LEX *lex= Lex;
- /*
- For simplicity, let's forget about INSERT ... SELECT ... UPDATE
- for a moment.
- */
- if (lex->sql_command != SQLCOM_INSERT)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
- }
- KEY_SYM UPDATE_SYM update_list
+ KEY_SYM UPDATE_SYM insert_update_list
;
/* Update rows in a table */
@@ -5762,16 +5753,26 @@ update:
;
update_list:
- update_list ',' simple_ident_nospvar equal expr_or_default
+ update_list ',' update_elem
+ | update_elem;
+
+update_elem:
+ simple_ident_nospvar equal expr_or_default
+ {
+ };
+
+insert_update_list:
+ insert_update_list ',' insert_update_elem
+ | insert_update_elem;
+
+insert_update_elem:
+ simple_ident_nospvar equal expr_or_default
{
- if (add_item_to_list(YYTHD, $3) || add_value_to_list(YYTHD, $5))
+ LEX *lex= Lex;
+ if (lex->update_list.push_back($1) ||
+ lex->value_list.push_back($3))
YYABORT;
- }
- | simple_ident_nospvar equal expr_or_default
- {
- if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
- YYABORT;
- };
+ };
opt_low_priority:
/* empty */ { $$= YYTHD->update_lock_default; }
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 2253f48e558..777b3851294 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -53,8 +53,22 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
{
const char *pos= start;
uint var_len;
+ int mblen= 1;
- for (; pos != end && *pos != field_separator; pos++) ;
+ if (cs && cs->mbminlen > 1)
+ {
+ for ( ; pos < end; pos+= mblen)
+ {
+ my_wc_t wc;
+ if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos,
+ (const uchar *) end)) < 1)
+ mblen= 1; // Not to hang on a wrong multibyte sequence
+ if (wc == (my_wc_t) field_separator)
+ break;
+ }
+ }
+ else
+ for (; pos != end && *pos != field_separator; pos++) ;
var_len= (uint) (pos - start);
uint find= cs ? find_type2(lib, start, var_len, cs) :
find_type(lib, start, var_len, (bool) 0);
@@ -66,9 +80,9 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
}
else
found|= ((longlong) 1 << (find - 1));
- if (pos == end)
+ if (pos >= end)
break;
- start= pos + 1;
+ start= pos + mblen;
}
}
return found;
diff --git a/sql/table.cc b/sql/table.cc
index c18a2557337..a37186287b4 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -509,6 +509,32 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
charset= outparam->table_charset;
bzero((char*) &comment, sizeof(comment));
}
+
+ if (interval_nr && charset->mbminlen > 1)
+ {
+ /* Unescape UCS2 intervals from HEX notation */
+ TYPELIB *interval= outparam->intervals + interval_nr - 1;
+ for (uint pos= 0; pos < interval->count; pos++)
+ {
+ char *from, *to;
+ for (from= to= (char*) interval->type_names[pos]; *from; )
+ {
+ /*
+ Note, hexchar_to_int(*from++) doesn't work
+ one some compilers, e.g. IRIX. Looks like a compiler
+ bug in inline functions in combination with arguments
+ that have a side effect. So, let's use from[0] and from[1]
+ and increment 'from' by two later.
+ */
+
+ *to++= (char) (hexchar_to_int(from[0]) << 4) +
+ hexchar_to_int(from[1]);
+ from+= 2;
+ }
+ interval->type_lengths[pos] /= 2;
+ }
+ }
+
*field_ptr=reg_field=
make_field(record+recpos,
(uint32) field_length,
diff --git a/sql/table.h b/sql/table.h
index a804376ee3c..871b96165b2 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -145,8 +145,14 @@ struct st_table {
int current_lock; /* Type of lock on table */
enum tmp_table_type tmp_table;
my_bool copy_blobs; /* copy_blobs when storing */
- my_bool null_row; /* All columns are null */
- my_bool maybe_null,outer_join; /* Used with OUTER JOIN */
+ /*
+ Used in outer joins: if true, all columns are considered to have NULL
+ values, including columns declared as "not null".
+ */
+ my_bool null_row;
+ /* 0 or JOIN_TYPE_{LEFT|RIGHT}, same as TABLE_LIST::outer_join */
+ my_bool outer_join;
+ my_bool maybe_null; /* true if (outer_join != 0) */
my_bool force_index;
my_bool distinct,const_table,no_rows;
my_bool key_read;
diff --git a/sql/tztime.h b/sql/tztime.h
index 6d2388bb160..8b26c8fa378 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -66,8 +66,8 @@ extern void my_tz_free();
/*
- Check if we have pointer to the beggining of list of implictly used
- time zone tables and fast-forward to its end.
+ Check if we have pointer to the begining of list of implicitly used time
+ zone tables, set SELECT_ACL for them and fast-forward to its end.
SYNOPSIS
my_tz_check_n_skip_implicit_tables()
@@ -87,6 +87,8 @@ inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table,
{
if (*table == tz_tables)
{
+ for (int i= 0; i < 4; i++)
+ (*table)[i].grant.privilege= SELECT_ACL;
(*table)+= 3;
return TRUE;
}
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index f0f33ed6fd7..a186b4fbf6c 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -619,10 +619,12 @@ my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
return 1;
}
bzero(initid->ptr,sizeof(longlong));
- // Fool MySQL to think that this function is a constant
- // This will ensure that MySQL only evalutes the function
- // when the rows are sent to the client and not before any ORDER BY
- // clauses
+ /*
+ Fool MySQL to think that this function is a constant
+ This will ensure that MySQL only evalutes the function
+ when the rows are sent to the client and not before any ORDER BY
+ clauses
+ */
initid->const_item=1;
return 0;
}
@@ -639,9 +641,10 @@ longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
ulonglong val=0;
if (args->arg_count)
val= *((longlong*) args->args[0]);
- return ++ *((longlong*) initid->ptr) + val;
+ return ++*((longlong*) initid->ptr) + val;
}
+
/****************************************************************************
** Some functions that handles IP and hostname conversions
** The orignal function was from Zeev Suraski.
diff --git a/sql/unireg.cc b/sql/unireg.cc
index dbd3da58a33..a16439530fc 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -423,6 +423,28 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
if (field->interval)
{
uint old_int_count=int_count;
+
+ if (field->charset->mbminlen > 1)
+ {
+ /* Escape UCS2 intervals using HEX notation */
+ for (uint pos= 0; pos < field->interval->count; pos++)
+ {
+ char *dst;
+ uint length= field->interval->type_lengths[pos], hex_length;
+ const char *src= field->interval->type_names[pos];
+ const char *srcend= src + length;
+ hex_length= length * 2;
+ field->interval->type_lengths[pos]= hex_length;
+ field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
+ for ( ; src < srcend; src++)
+ {
+ *dst++= _dig_vec_upper[((uchar) *src) >> 4];
+ *dst++= _dig_vec_upper[((uchar) *src) & 15];
+ }
+ *dst= '\0';
+ }
+ }
+
field->interval_id=get_interval_id(&int_count,create_fields,field);
if (old_int_count != int_count)
{