summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <svoj@mysql.com>2005-06-28 16:07:16 +0500
committerunknown <svoj@mysql.com>2005-06-28 16:07:16 +0500
commitdc9bf5450508b862b11229bd5f48e14403c90849 (patch)
tree2a9be970ca27eec9fade7fd4f85fbb737c699b24 /sql
parent290b841147d7f5538a847c560e11f535eb875001 (diff)
parentba2261e3fdd753f39ca00ed647a357aab4b1b8d6 (diff)
downloadmariadb-git-dc9bf5450508b862b11229bd5f48e14403c90849.tar.gz
Merge svojtovich@bk-internal.mysql.com:/home/bk/mysql-5.1
into mysql.com:/home/svoj/devel/mysql/WL2535-mysql-5.1 storage/myisam/ft_boolean_search.c: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am13
-rw-r--r--sql/field.cc83
-rw-r--r--sql/field.h7
-rw-r--r--sql/filesort.cc10
-rw-r--r--sql/gstream.cc4
-rw-r--r--sql/ha_berkeley.cc73
-rw-r--r--sql/ha_federated.cc12
-rw-r--r--sql/ha_heap.h1
-rw-r--r--sql/ha_innodb.cc105
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/ha_myisammrg.cc2
-rw-r--r--sql/ha_ndbcluster.cc59
-rw-r--r--sql/handler.cc15
-rw-r--r--sql/handler.h3
-rw-r--r--sql/item.cc69
-rw-r--r--sql/item.h89
-rw-r--r--sql/item_buff.cc43
-rw-r--r--sql/item_cmpfunc.cc39
-rw-r--r--sql/item_func.cc60
-rw-r--r--sql/item_func.h49
-rw-r--r--sql/item_strfunc.cc42
-rw-r--r--sql/item_strfunc.h2
-rw-r--r--sql/item_subselect.cc8
-rw-r--r--sql/item_sum.cc22
-rw-r--r--sql/item_sum.h46
-rw-r--r--sql/item_timefunc.cc4
-rw-r--r--sql/item_timefunc.h6
-rw-r--r--sql/item_uniq.h2
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/my_decimal.h5
-rw-r--r--sql/mysql_priv.h129
-rw-r--r--sql/mysqld.cc68
-rw-r--r--sql/opt_range.cc28
-rw-r--r--sql/password.c8
-rw-r--r--sql/set_var.cc7
-rw-r--r--sql/set_var.h3
-rw-r--r--sql/share/errmsg.txt8
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sp_head.cc128
-rw-r--r--sql/sp_head.h7
-rw-r--r--sql/sp_rcontext.cc12
-rw-r--r--sql/sp_rcontext.h7
-rw-r--r--sql/sql_acl.cc16
-rw-r--r--sql/sql_base.cc76
-rw-r--r--sql/sql_class.cc123
-rw-r--r--sql/sql_class.h91
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_derived.cc8
-rw-r--r--sql/sql_error.cc14
-rw-r--r--sql/sql_handler.cc51
-rw-r--r--sql/sql_insert.cc29
-rw-r--r--sql/sql_lex.cc43
-rw-r--r--sql/sql_lex.h33
-rw-r--r--sql/sql_map.cc2
-rw-r--r--sql/sql_parse.cc178
-rw-r--r--sql/sql_prepare.cc728
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_repl.cc6
-rw-r--r--sql/sql_select.cc156
-rw-r--r--sql/sql_select.h11
-rw-r--r--sql/sql_show.cc57
-rw-r--r--sql/sql_table.cc91
-rw-r--r--sql/sql_union.cc6
-rw-r--r--sql/sql_view.cc82
-rw-r--r--sql/sql_yacc.yy135
-rw-r--r--sql/structs.h2
-rw-r--r--sql/table.cc18
-rw-r--r--sql/unireg.cc2
69 files changed, 1878 insertions, 1370 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index b9a9bdaec74..0b6610fab55 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -112,8 +112,8 @@ DEFS = -DMYSQL_SERVER \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
@DEFS@
-# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion
-BUILT_SOURCES = sql_yacc.cc sql_yacc.h
+
+BUILT_SOURCES = sql_yacc.cc sql_yacc.h lex_hash.h
EXTRA_DIST = udf_example.cc $(BUILT_SOURCES)
DISTCLEANFILES = lex_hash.h
AM_YFLAGS = -d
@@ -132,9 +132,6 @@ link_sources: mysql_tzinfo_to_sql.cc
rm -f my_time.c
@LN_CP_F@ ../sql-common/my_time.c my_time.c
-gen_lex_hash.o: gen_lex_hash.cc lex.h
- $(CXXCOMPILE) -c $(INCLUDES) $<
-
mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES)
$(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $<
@@ -149,13 +146,9 @@ sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS)
@echo "If it fails, re-run configure with --with-low-memory"
$(CXXCOMPILE) $(LM_CFLAGS) -c $<
-lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h
- $(MAKE) gen_lex_hash$(EXEEXT)
+lex_hash.h: gen_lex_hash$(EXEEXT)
./gen_lex_hash$(EXEEXT) > $@
-# Hack to ensure that lex_hash.h is built early
-sql_lex.o: lex_hash.h
-
# For testing of udf_example.so; Works on platforms with gcc
# (This is not part of our build process but only provided as an example)
udf_example.so: udf_example.cc
diff --git a/sql/field.cc b/sql/field.cc
index 78b08fa3cd9..16bf63e96fc 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -38,7 +38,7 @@
Instansiate templates and static variables
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<create_field>;
template class List_iterator<create_field>;
#endif
@@ -982,6 +982,39 @@ Item_result Field::result_merge_type(enum_field_types field_type)
Static help functions
*****************************************************************************/
+
+/*
+ Check whether a field type can be partially indexed by a key
+
+ This is a static method, rather than a virtual function, because we need
+ to check the type of a non-Field in mysql_alter_table().
+
+ SYNOPSIS
+ type_can_have_key_part()
+ type field type
+
+ RETURN
+ TRUE Type can have a prefixed key
+ FALSE Type can not have a prefixed key
+*/
+
+bool Field::type_can_have_key_part(enum enum_field_types type)
+{
+ switch (type) {
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+
/*
Numeric fields base class constructor
*/
@@ -1888,7 +1921,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
int_digits_added_zeros=0;
}
}
- tmp_uint= (tmp_dec+(int_digits_end-int_digits_from)+
+ tmp_uint= (uint) (tmp_dec+(int_digits_end-int_digits_from)+
(uint)(frac_digits_from-int_digits_tail_from)+
int_digits_added_zeros);
}
@@ -2447,7 +2480,7 @@ int Field_new_decimal::store(longlong nr)
int err;
if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
- nr, unsigned_flag, &decimal_value)))
+ nr, false, &decimal_value)))
{
if (check_overflow(err))
set_value_on_overflow(&decimal_value, decimal_value.sign());
@@ -5924,14 +5957,6 @@ longlong Field_string::val_int(void)
}
-my_decimal *Field_longstr::val_decimal(my_decimal *decimal_value)
-{
- str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
- decimal_value);
- return decimal_value;
-}
-
-
String *Field_string::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@@ -5943,6 +5968,14 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
}
+my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
+{
+ str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
+ decimal_value);
+ return decimal_value;
+}
+
+
int Field_string::cmp(const char *a_ptr, const char *b_ptr)
{
uint a_len, b_len;
@@ -6256,6 +6289,15 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
}
+my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
+{
+ uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ str2my_decimal(E_DEC_FATAL_ERROR, ptr+length_bytes, length, charset(),
+ decimal_value);
+ return decimal_value;
+}
+
+
int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
{
uint a_length, b_length;
@@ -6874,6 +6916,18 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
}
+my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
+{
+ char *blob;
+ memcpy_fixed(&blob, ptr+packlength, sizeof(char*));
+ if (!blob)
+ blob= "";
+ str2my_decimal(E_DEC_FATAL_ERROR, blob, get_length(ptr), charset(),
+ decimal_value);
+ return decimal_value;
+}
+
+
int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
uint32 b_length)
{
@@ -7702,9 +7756,9 @@ bool Field_enum::eq_def(Field *field)
for (uint i=0 ; i < from_lib->count ; i++)
if (my_strnncoll(field_charset,
(const uchar*)typelib->type_names[i],
- strlen(typelib->type_names[i]),
+ (uint) strlen(typelib->type_names[i]),
(const uchar*)from_lib->type_names[i],
- strlen(from_lib->type_names[i])))
+ (uint) strlen(from_lib->type_names[i])))
return 0;
return 1;
}
@@ -8562,7 +8616,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{
char str_nr[22];
char *str_end= longlong10_to_str(nr, str_nr, -10);
- make_truncated_value_warning(table->in_use, str_nr, str_end - str_nr,
+ make_truncated_value_warning(table->in_use, str_nr,
+ (uint) (str_end - str_nr),
ts_type, field_name);
}
}
diff --git a/sql/field.h b/sql/field.h
index b99acd43123..f297b17fd67 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -25,6 +25,7 @@
#endif
#define NOT_FIXED_DEC 31
+#define DATETIME_DEC 6
class Send_field;
class Protocol;
@@ -123,6 +124,7 @@ public:
virtual Item_result result_type () const=0;
virtual Item_result cmp_type () const { return result_type(); }
virtual Item_result cast_to_int_type () const { return result_type(); }
+ static bool type_can_have_key_part(enum_field_types);
static enum_field_types field_type_merge(enum_field_types, enum_field_types);
static Item_result result_merge_type(enum_field_types);
bool eq(Field *field)
@@ -384,7 +386,6 @@ public:
field_name_arg, table_arg, charset)
{}
- my_decimal *val_decimal(my_decimal *);
int store_decimal(const my_decimal *d);
};
@@ -945,6 +946,7 @@ public:
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
#endif
enum Item_result cmp_type () const { return INT_RESULT; }
+ uint decimals() const { return DATETIME_DEC; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
@@ -996,6 +998,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
+ my_decimal *val_decimal(my_decimal *);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
void sql_type(String &str) const;
@@ -1054,6 +1057,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
+ my_decimal *val_decimal(my_decimal *);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
void get_key_image(char *buff,uint length, imagetype type);
@@ -1109,6 +1113,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
+ my_decimal *val_decimal(my_decimal *);
int cmp(const char *,const char*);
int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length);
int cmp_binary(const char *a,const char *b, uint32 max_length=~0L);
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 30ebd8d59e1..75da43afed5 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -631,7 +631,7 @@ static void make_sortkey(register SORTPARAM *param,
*to++=1;
/* All item->str() to use some extra byte for end null.. */
String tmp((char*) to,sort_field->length+4,cs);
- String *res=item->val_str(&tmp);
+ String *res= item->str_result(&tmp);
if (!res)
{
if (maybe_null)
@@ -673,8 +673,8 @@ static void make_sortkey(register SORTPARAM *param,
}
case INT_RESULT:
{
- longlong value=item->val_int();
- if (maybe_null)
+ longlong value= item->val_int_result();
+ if (maybe_null)
{
*to++=1; /* purecov: inspected */
if (item->null_value)
@@ -715,7 +715,7 @@ static void make_sortkey(register SORTPARAM *param,
}
case DECIMAL_RESULT:
{
- my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf);
+ my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
if (maybe_null)
{
if (item->null_value)
@@ -733,7 +733,7 @@ static void make_sortkey(register SORTPARAM *param,
}
case REAL_RESULT:
{
- double value= item->val_real();
+ double value= item->val_result();
if (maybe_null)
{
if (item->null_value)
diff --git a/sql/gstream.cc b/sql/gstream.cc
index f7d11d76b0c..4083cb2fe71 100644
--- a/sql/gstream.cc
+++ b/sql/gstream.cc
@@ -83,7 +83,7 @@ bool Gis_read_stream::get_next_number(double *d)
}
*d = my_strntod(m_charset, (char *)m_cur,
- m_limit-m_cur, &endptr, &err);
+ (uint) (m_limit-m_cur), &endptr, &err);
if (err)
return 1;
if (endptr)
@@ -115,6 +115,6 @@ bool Gis_read_stream::check_next_symbol(char symbol)
void Gis_read_stream::set_error_msg(const char *msg)
{
size_t len= strlen(msg); // ok in this context
- m_err_msg= (char *) my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR));
+ m_err_msg= (char *) my_realloc(m_err_msg, (uint) len + 1, MYF(MY_ALLOW_ZERO_PTR));
memcpy(m_err_msg, msg, len + 1);
}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 16cbd782f0c..568fb727e63 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -948,12 +948,6 @@ int ha_berkeley::write_row(byte * record)
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
key_map changed_keys(0);
- if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
- {
- if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
- break; /* purecov: deadcode */
- DBUG_PRINT("trans",("starting subtransaction")); /* purecov: deadcode */
- }
if (!(error=file->put(file, sub_trans, create_key(&prim_key, primary_key,
key_buff, record),
&row, key_type[primary_key])))
@@ -983,12 +977,7 @@ int ha_berkeley::write_row(byte * record)
if (using_ignore)
{
int new_error = 0;
- if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)
- {
- DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
- new_error=txn_abort(sub_trans); /* purecov: deadcode */
- }
- else if (!changed_keys.is_clear_all())
+ if (!changed_keys.is_clear_all())
{
new_error = 0;
for (uint keynr=0;
@@ -1010,11 +999,6 @@ int ha_berkeley::write_row(byte * record)
}
}
}
- else if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
- {
- DBUG_PRINT("trans",("committing subtransaction")); /* purecov: deadcode */
- error=txn_commit(sub_trans, 0); /* purecov: deadcode */
- }
if (error != DB_LOCK_DEADLOCK)
break;
}
@@ -1090,8 +1074,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed,
{
// Probably a duplicated key; restore old key and row if needed
last_dup_key=primary_key;
- if (local_using_ignore &&
- !(thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
+ if (local_using_ignore)
{
int new_error;
if ((new_error=pack_row(&row, old_row, 0)) ||
@@ -1202,12 +1185,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
key_map changed_keys(0);
- if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
- {
- if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
- break; /* purecov: deadcode */
- DBUG_PRINT("trans",("starting subtransaction")); /* purecov: deadcode */
- }
/* Start by updating the primary key */
if (!(error=update_primary_key(sub_trans, primary_key_changed,
old_row, &old_prim_key,
@@ -1223,15 +1200,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
{
if ((error=remove_key(sub_trans, keynr, old_row, &old_prim_key)))
{
- if (using_ignore && /* purecov: inspected */
- (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
- {
- int new_error;
- DBUG_PRINT("trans",("aborting subtransaction"));
- new_error=txn_abort(sub_trans);
- if (new_error)
- error = new_error;
- }
table->insert_or_update= 0;
DBUG_RETURN(error); // Fatal error /* purecov: inspected */
}
@@ -1254,12 +1222,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
if (using_ignore)
{
int new_error = 0;
- if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)
- {
- DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
- new_error=txn_abort(sub_trans); /* purecov: deadcode */
- }
- else if (!changed_keys.is_clear_all())
+ if (!changed_keys.is_clear_all())
new_error=restore_keys(transaction, &changed_keys, primary_key,
old_row, &old_prim_key, new_row, &prim_key,
thd_options);
@@ -1271,11 +1234,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
}
}
}
- else if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
- {
- DBUG_PRINT("trans",("committing subtransaction")); /* purecov: deadcode */
- error=txn_commit(sub_trans, 0); /* purecov: deadcode */
- }
if (error != DB_LOCK_DEADLOCK)
break;
}
@@ -1385,34 +1343,11 @@ int ha_berkeley::delete_row(const byte * record)
DB_TXN *sub_trans = transaction;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
- if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)
- {
- if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
- break; /* purecov: deadcode */
- DBUG_PRINT("trans",("starting sub transaction")); /* purecov: deadcode */
- }
error=remove_keys(sub_trans, record, &row, &prim_key, &keys);
- if (!error && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
- {
- DBUG_PRINT("trans",("ending sub transaction")); /* purecov: deadcode */
- error=txn_commit(sub_trans, 0); /* purecov: deadcode */
- }
if (error)
{ /* purecov: inspected */
DBUG_PRINT("error",("Got error %d",error));
- if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)
- {
- /* retry */
- int new_error;
- DBUG_PRINT("trans",("aborting subtransaction"));
- if ((new_error=txn_abort(sub_trans)))
- {
- error=new_error; // This shouldn't happen
- break;
- }
- }
- else
- break; // No retry - return error
+ break; // No retry - return error
}
if (error != DB_LOCK_DEADLOCK)
break;
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 844612e0643..c18ca5d7915 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -462,6 +462,12 @@ static int check_foreign_data_source(FEDERATED_SHARE *share)
}
else
{
+ /*
+ Since we do not support transactions at this version, we can let the client
+ API silently reconnect. For future versions, we will need more logic to deal
+ with transactions
+ */
+ mysql->reconnect= 1;
/*
Note: I am not using INORMATION_SCHEMA because this needs to work with < 5.0
if we can connect, then make sure the table exists
@@ -988,6 +994,12 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_CONNECT_TO_MASTER);
}
+ /*
+ Since we do not support transactions at this version, we can let the client
+ API silently reconnect. For future versions, we will need more logic to deal
+ with transactions
+ */
+ mysql->reconnect= 1;
DBUG_RETURN(0);
}
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 5d50270ec5b..2aa065e0d96 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -57,6 +57,7 @@ public:
}
const key_map *keys_to_use_for_scanning() { return &btree_keys; }
uint max_supported_keys() const { return MAX_KEY; }
+ uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
double scan_time() { return (double) (records+deleted) / 20.0+10; }
double read_time(uint index, uint ranges, ha_rows rows)
{ return (double) rows / 20.0+1; }
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 0210e2b768f..78b70d9876a 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -146,8 +146,7 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_buffer_pool_awe_mem_mb,
innobase_buffer_pool_size, innobase_additional_mem_pool_size,
innobase_file_io_threads, innobase_lock_wait_timeout,
- innobase_thread_concurrency, innobase_force_recovery,
- innobase_open_files;
+ innobase_force_recovery, innobase_open_files;
/* The default values for the following char* start-up parameters
are determined in innobase_init below: */
@@ -327,7 +326,7 @@ innodb_srv_conc_enter_innodb(
/*=========================*/
trx_t* trx) /* in: transaction handle */
{
- if (srv_thread_concurrency >= 500) {
+ if (UNIV_LIKELY(srv_thread_concurrency >= 20)) {
return;
}
@@ -344,7 +343,7 @@ innodb_srv_conc_exit_innodb(
/*========================*/
trx_t* trx) /* in: transaction handle */
{
- if (srv_thread_concurrency >= 500) {
+ if (UNIV_LIKELY(srv_thread_concurrency >= 20)) {
return;
}
@@ -564,7 +563,7 @@ innobase_mysql_print_thd(
thd = (const THD*) input_thd;
fprintf(f, "MySQL thread id %lu, query id %lu",
- thd->thread_id, thd->query_id);
+ thd->thread_id, (ulong) thd->query_id);
if (thd->host) {
putc(' ', f);
fputs(thd->host, f);
@@ -1041,7 +1040,19 @@ mysql_get_identifier_quote_char(
return(EOF);
}
return(get_quote_char_for_identifier((THD*) trx->mysql_thd,
- name, namelen));
+ name, (int) namelen));
+}
+
+/**************************************************************************
+Determines if the currently running transaction has been interrupted. */
+extern "C"
+ibool
+trx_is_interrupted(
+/*===============*/
+ /* out: TRUE if interrupted */
+ trx_t* trx) /* in: transaction */
+{
+ return(trx && trx->mysql_thd && ((THD*) trx->mysql_thd)->killed);
}
/**************************************************************************
@@ -1302,8 +1313,8 @@ innobase_init(void)
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
- data_mysql_latin1_swedish_charset_coll =
- (ulint)my_charset_latin1.number;
+ ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL ==
+ my_charset_latin1.number);
/* Store the latin1_swedish_ci character ordering table to InnoDB. For
non-latin1_swedish_ci charsets we use the MySQL comparison functions,
@@ -1794,7 +1805,7 @@ try_again:
fprintf(stderr,
"InnoDB: This transaction needs it to be sent up to\n"
"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name,
- (uint)trx->repl_wait_binlog_pos);
+ (ulong)trx->repl_wait_binlog_pos);
innobase_repl_state = 0;
@@ -2022,7 +2033,7 @@ innobase_rollback_to_savepoint(
longlong2str((ulonglong)savepoint, name, 36);
- error = trx_rollback_to_savepoint_for_mysql(trx, name,
+ error = (int) trx_rollback_to_savepoint_for_mysql(trx, name,
&mysql_binlog_cache_pos);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
@@ -2051,7 +2062,7 @@ innobase_release_savepoint(
longlong2str((ulonglong)savepoint, name, 36);
- error = trx_release_savepoint_for_mysql(trx, name);
+ error = (int) trx_release_savepoint_for_mysql(trx, name);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
@@ -2092,7 +2103,7 @@ innobase_savepoint(
char name[64];
longlong2str((ulonglong)savepoint,name,36);
- error = trx_savepoint_for_mysql(trx, name, (ib_longlong)0);
+ error = (int) trx_savepoint_for_mysql(trx, name, (ib_longlong)0);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
@@ -2663,7 +2674,7 @@ innobase_read_from_2_little_endian(
/* out: value */
const mysql_byte* buf) /* in: from where to read */
{
- return((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
+ return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
}
/***********************************************************************
@@ -2867,6 +2878,8 @@ build_template(
ibool fetch_all_in_key = FALSE;
ibool fetch_primary_key_cols = FALSE;
ulint i;
+ /* byte offset of the end of last requested column */
+ ulint mysql_prefix_len = 0;
if (prebuilt->select_lock_type == LOCK_X) {
/* We always retrieve the whole clustered index record if we
@@ -2988,6 +3001,11 @@ build_template(
get_field_offset(table, field);
templ->mysql_col_len = (ulint) field->pack_length();
+ if (mysql_prefix_len < templ->mysql_col_offset
+ + templ->mysql_col_len) {
+ mysql_prefix_len = templ->mysql_col_offset
+ + templ->mysql_col_len;
+ }
templ->type = index->table->cols[i].type.mtype;
templ->mysql_type = (ulint)field->type();
@@ -3010,6 +3028,7 @@ skip_field:
}
prebuilt->n_template = n_requested_fields;
+ prebuilt->mysql_prefix_len = mysql_prefix_len;
if (index != clust_index && prebuilt->need_to_access_clustered) {
/* Change rec_field_no's to correspond to the clustered index
@@ -3081,7 +3100,7 @@ ha_innobase::write_row(
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
dict_table_t* src_table;
- ibool mode;
+ ulint mode;
num_write_row = 0;
@@ -3744,7 +3763,7 @@ ha_innobase::index_read(
match_mode = ROW_SEL_EXACT_PREFIX;
}
- last_match_mode = match_mode;
+ last_match_mode = (uint) match_mode;
innodb_srv_conc_enter_innodb(prebuilt->trx);
@@ -3764,7 +3783,7 @@ ha_innobase::index_read(
error = HA_ERR_KEY_NOT_FOUND;
table->status = STATUS_NOT_FOUND;
} else {
- error = convert_error_code_to_mysql(ret, user_thd);
+ error = convert_error_code_to_mysql((int) ret, user_thd);
table->status = STATUS_NOT_FOUND;
}
@@ -3916,7 +3935,7 @@ ha_innobase::general_fetch(
error = HA_ERR_END_OF_FILE;
table->status = STATUS_NOT_FOUND;
} else {
- error = convert_error_code_to_mysql(ret, user_thd);
+ error = convert_error_code_to_mysql((int) ret, user_thd);
table->status = STATUS_NOT_FOUND;
}
@@ -4865,7 +4884,7 @@ innobase_drop_database(
}
ptr++;
- namebuf = my_malloc(len + 2, MYF(0));
+ namebuf = my_malloc((uint) len + 2, MYF(0));
memcpy(namebuf, ptr, len);
namebuf[len] = '/';
@@ -5431,7 +5450,7 @@ ha_innobase::update_table_comment(
info on foreign keys */
const char* comment)/* in: table comment defined by user */
{
- uint length = strlen(comment);
+ uint length = (uint) strlen(comment);
char* str;
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
@@ -5483,7 +5502,7 @@ ha_innobase::update_table_comment(
*pos++ = ' ';
}
rewind(file);
- flen = fread(pos, 1, flen, file);
+ flen = (uint) fread(pos, 1, flen, file);
pos[flen] = 0;
}
@@ -5546,7 +5565,7 @@ ha_innobase::get_foreign_key_create_info(void)
if (str) {
rewind(file);
- flen = fread(str, 1, flen, file);
+ flen = (uint) fread(str, 1, flen, file);
str[flen] = 0;
}
@@ -5586,8 +5605,8 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
while (tmp_buff[i] != '/')
i++;
tmp_buff+= i + 1;
- f_key_info.forein_id= make_lex_string(thd, 0,
- tmp_buff, strlen(tmp_buff), 1);
+ f_key_info.forein_id= make_lex_string(thd, 0, tmp_buff,
+ (uint) strlen(tmp_buff), 1);
tmp_buff= foreign->referenced_table_name;
i= 0;
while (tmp_buff[i] != '/')
@@ -5595,16 +5614,16 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
f_key_info.referenced_db= make_lex_string(thd, 0,
tmp_buff, i, 1);
tmp_buff+= i + 1;
- f_key_info.referenced_table= make_lex_string(thd, 0,
- tmp_buff, strlen(tmp_buff), 1);
+ f_key_info.referenced_table= make_lex_string(thd, 0, tmp_buff,
+ (uint) strlen(tmp_buff), 1);
for (i= 0;;)
{
tmp_buff= foreign->foreign_col_names[i];
- name= make_lex_string(thd, name, tmp_buff, strlen(tmp_buff), 1);
+ name= make_lex_string(thd, name, tmp_buff, (uint) strlen(tmp_buff), 1);
f_key_info.foreign_fields.push_back(name);
tmp_buff= foreign->referenced_col_names[i];
- name= make_lex_string(thd, name, tmp_buff, strlen(tmp_buff), 1);
+ name= make_lex_string(thd, name, tmp_buff, (uint) strlen(tmp_buff), 1);
f_key_info.referenced_fields.push_back(name);
if (++i >= foreign->n_fields)
break;
@@ -5992,12 +6011,12 @@ ha_innobase::external_lock(
ulint error;
error = row_lock_table_for_mysql(prebuilt,
- NULL, LOCK_TABLE_EXP);
+ NULL, 0);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(
- error, user_thd);
- DBUG_RETURN(error);
+ (int) error, user_thd);
+ DBUG_RETURN((int) error);
}
}
@@ -6012,9 +6031,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
- if (trx->n_lock_table_exp) {
- row_unlock_tables_for_mysql(trx);
- }
/* If the MySQL lock count drops to zero we know that the current SQL
statement has ended */
@@ -6056,7 +6072,7 @@ user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */
int
ha_innobase::transactional_table_lock(
/*==================================*/
- /* out: 0 */
+ /* out: error code */
THD* thd, /* in: handle to the user thread */
int lock_type) /* in: lock type */
{
@@ -6120,12 +6136,11 @@ ha_innobase::transactional_table_lock(
if (thd->in_lock_tables && thd->variables.innodb_table_locks) {
ulint error = DB_SUCCESS;
- error = row_lock_table_for_mysql(prebuilt,NULL,
- LOCK_TABLE_TRANSACTIONAL);
+ error = row_lock_table_for_mysql(prebuilt, NULL, 0);
if (error != DB_SUCCESS) {
- error = convert_error_code_to_mysql(error, user_thd);
- DBUG_RETURN(error);
+ error = convert_error_code_to_mysql((int) error, user_thd);
+ DBUG_RETURN((int) error);
}
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
@@ -6215,22 +6230,22 @@ innodb_show_status(
rewind(srv_monitor_file);
if (flen < MAX_STATUS_SIZE) {
/* Display the entire output. */
- flen = fread(str, 1, flen, srv_monitor_file);
+ flen = (long) fread(str, 1, flen, srv_monitor_file);
} else if (trx_list_end < (ulint) flen
&& trx_list_start < trx_list_end
&& trx_list_start + (flen - trx_list_end)
< MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
/* Omit the beginning of the list of active transactions. */
- long len = fread(str, 1, trx_list_start, srv_monitor_file);
+ long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
len += sizeof truncated_msg - 1;
usable_len = (MAX_STATUS_SIZE - 1) - len;
fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
- len += fread(str + len, 1, usable_len, srv_monitor_file);
+ len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
flen = len;
} else {
/* Omit the end of the output. */
- flen = fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
+ flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
}
mutex_exit_noninline(&srv_monitor_file_mutex);
@@ -6792,7 +6807,7 @@ innobase_get_at_most_n_mbchars(
ulint n_chars; /* number of characters in prefix */
CHARSET_INFO* charset; /* charset used in the field */
- charset = get_charset(charset_id, MYF(MY_WME));
+ charset = get_charset((uint) charset_id, MYF(MY_WME));
ut_ad(charset);
ut_ad(charset->mbmaxlen);
@@ -6826,7 +6841,7 @@ innobase_get_at_most_n_mbchars(
whole string. */
char_length = my_charpos(charset, str,
- str + data_len, n_chars);
+ str + data_len, (int) n_chars);
if (char_length > data_len) {
char_length = data_len;
}
@@ -6949,7 +6964,7 @@ innobase_xa_prepare(
ut_ad(trx->active_trans);
- error = trx_prepare_for_mysql(trx);
+ error = (int) trx_prepare_for_mysql(trx);
} else {
/* We just mark the SQL statement ended and do not do a
transaction prepare */
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index f18d527e6b3..98496e748b4 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -228,7 +228,7 @@ extern long innobase_log_file_size, innobase_log_buffer_size;
extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size;
extern long innobase_buffer_pool_awe_mem_mb;
extern long innobase_file_io_threads, innobase_lock_wait_timeout;
-extern long innobase_force_recovery, innobase_thread_concurrency;
+extern long innobase_force_recovery;
extern long innobase_open_files;
extern char *innobase_data_home_dir, *innobase_data_file_path;
extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 3f756eab0ee..27023ba4c64 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -1068,7 +1068,7 @@ bool ha_myisam::check_and_repair(THD *thd)
old_query_length= thd->query_length;
pthread_mutex_lock(&LOCK_thread_count);
thd->query= (char*) table->s->table_name;
- thd->query_length= strlen(table->s->table_name);
+ thd->query_length= (uint32) strlen(table->s->table_name);
pthread_mutex_unlock(&LOCK_thread_count);
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index ec185c43fb8..794f1c62dd7 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -466,7 +466,7 @@ void ha_myisammrg::append_create_info(String *packet)
MYRG_TABLE *open_table,*first;
current_db= table->s->db;
- db_length= strlen(current_db);
+ db_length= (uint) strlen(current_db);
for (first=open_table=file->open_tables ;
open_table != file->end_table ;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index f823dc97356..f1dbedc1af1 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -41,7 +41,7 @@ static const int parallelism= 0;
// Default value for max number of transactions
// createable against NDB from this handler
-static const int max_transactions= 256;
+static const int max_transactions= 3; // should really be 2 but there is a transaction to much allocated when loch table is used
static const char *ha_ndb_ext=".ndb";
@@ -511,8 +511,13 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans)
DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
err.code, res));
if (res == HA_ERR_FOUND_DUPP_KEY)
- m_dupkey= table->s->primary_key;
-
+ {
+ if (m_rows_to_insert == 1)
+ m_dupkey= table->s->primary_key;
+ else
+ // We are batching inserts, offending key is not available
+ m_dupkey= (uint) -1;
+ }
DBUG_RETURN(res);
}
@@ -540,13 +545,12 @@ bool ha_ndbcluster::get_error_message(int error,
}
+#ifndef DBUG_OFF
/*
Check if type is supported by NDB.
- TODO Use this once in open(), not in every operation
-
*/
-static inline bool ndb_supported_type(enum_field_types type)
+static bool ndb_supported_type(enum_field_types type)
{
switch (type) {
case MYSQL_TYPE_TINY:
@@ -581,6 +585,7 @@ static inline bool ndb_supported_type(enum_field_types type)
}
return FALSE;
}
+#endif /* !DBUG_OFF */
/*
@@ -610,15 +615,10 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field,
pack_len));
DBUG_DUMP("key", (char*)field_ptr, pack_len);
- if (ndb_supported_type(field->type()))
- {
- if (! (field->flags & BLOB_FLAG))
- // Common implementation for most field types
- DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
- }
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
+ DBUG_ASSERT(ndb_supported_type(field->type()));
+ DBUG_ASSERT(! (field->flags & BLOB_FLAG));
+ // Common implementation for most field types
+ DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
}
@@ -637,7 +637,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
pack_len, field->is_null()?"Y":"N"));
DBUG_DUMP("value", (char*) field_ptr, pack_len);
- if (ndb_supported_type(field->type()))
+ DBUG_ASSERT(ndb_supported_type(field->type()));
{
// ndb currently does not support size 0
uint32 empty_field;
@@ -715,9 +715,6 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
}
DBUG_RETURN(1);
}
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
}
@@ -812,9 +809,8 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
if (field != NULL)
{
- DBUG_ASSERT(buf);
- if (ndb_supported_type(field->type()))
- {
+ DBUG_ASSERT(buf);
+ DBUG_ASSERT(ndb_supported_type(field->type()));
DBUG_ASSERT(field->ptr != NULL);
if (! (field->flags & BLOB_FLAG))
{
@@ -845,10 +841,6 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
DBUG_RETURN(ndb_blob->setActiveHook(g_get_ndb_blobs_value, arg) != 0);
}
DBUG_RETURN(1);
- }
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
}
// Used for hidden key only
@@ -3040,6 +3032,13 @@ double ha_ndbcluster::scan_time()
DBUG_RETURN(res);
}
+/*
+ Convert MySQL table locks into locks supported by Ndb Cluster.
+ Note that MySQL Cluster does currently not support distributed
+ table locks, so to be safe one should set cluster in Single
+ User Mode, before relying on table locks when updating tables
+ from several MySQL servers
+*/
THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
THR_LOCK_DATA **to,
@@ -3055,7 +3054,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
/* Since NDB does not currently have table locks
this is treated as a ordinary lock */
- if ((lock_type >= TL_WRITE_ALLOW_WRITE &&
+ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
lock_type <= TL_WRITE) && !thd->in_lock_tables)
lock_type= TL_WRITE_ALLOW_WRITE;
@@ -4611,7 +4610,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
List_iterator_fast<char> it2(create_list);
while ((file_name=it2++))
{
- DBUG_PRINT("info", ("Table %s need discovery", name));
+ DBUG_PRINT("info", ("Table %s need discovery", file_name));
if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0)
files->push_back(thd->strdup(file_name));
}
@@ -6302,6 +6301,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
case(REAL_RESULT):
context->expect_only(Item::REAL_ITEM);
context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::INT_ITEM);
break;
case(INT_RESULT):
context->expect_only(Item::INT_ITEM);
@@ -6310,6 +6310,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
case(DECIMAL_RESULT):
context->expect_only(Item::DECIMAL_ITEM);
context->expect(Item::REAL_ITEM);
+ context->expect(Item::INT_ITEM);
break;
default:
break;
@@ -6712,6 +6713,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
// We have not seen the field argument yet
context->expect_only(Item::FIELD_ITEM);
context->expect_only_field_result(INT_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
}
else
{
diff --git a/sql/handler.cc b/sql/handler.cc
index 555b6ccc1cb..06a1c09fcc8 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -165,12 +165,22 @@ my_bool ha_storage_engine_is_enabled(enum db_type database_type)
/* Use other database handler if databasehandler is not incompiled */
-enum db_type ha_checktype(enum db_type database_type)
+enum db_type ha_checktype(THD *thd, enum db_type database_type,
+ bool no_substitute, bool report_error)
{
- THD *thd;
if (ha_storage_engine_is_enabled(database_type))
return database_type;
+ if (no_substitute)
+ {
+ if (report_error)
+ {
+ const char *engine_name= ha_get_storage_engine(database_type);
+ my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name);
+ }
+ return DB_TYPE_UNKNOWN;
+ }
+
switch (database_type) {
#ifndef NO_HASH
case DB_TYPE_HASH:
@@ -182,7 +192,6 @@ enum db_type ha_checktype(enum db_type database_type)
break;
}
- thd= current_thd;
return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ?
(enum db_type) thd->variables.table_type :
((enum db_type) global_system_variables.table_type !=
diff --git a/sql/handler.h b/sql/handler.h
index 0013013cdf8..f4efdd0ed8a 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1029,7 +1029,8 @@ extern ulong total_ha, total_ha_2pc;
enum db_type ha_resolve_by_name(const char *name, uint namelen);
const char *ha_get_storage_engine(enum db_type db_type);
handler *get_new_handler(TABLE *table, enum db_type db_type);
-enum db_type ha_checktype(enum db_type database_type);
+enum db_type ha_checktype(THD *thd, enum db_type database_type,
+ bool no_substitute, bool report_error);
/* basic stuff */
int ha_init(void);
diff --git a/sql/item.cc b/sql/item.cc
index 0e68ba48118..ec685982304 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -307,13 +307,14 @@ void *Item::operator new(size_t size, Item *reuse, uint *rsize)
return (void *)reuse;
}
if (rsize)
- (*rsize)= size;
+ (*rsize)= (uint) size;
return (void *)sql_alloc((uint)size);
}
Item::Item():
rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
+ is_autogenerated_name(TRUE),
collation(&my_charset_bin, DERIVATION_COERCIBLE)
{
marker= 0;
@@ -337,6 +338,7 @@ Item::Item():
place == IN_HAVING)
thd->lex->current_select->select_n_having_items++;
}
+ item_flags= 0;
}
/*
@@ -357,7 +359,8 @@ Item::Item(THD *thd, Item *item):
unsigned_flag(item->unsigned_flag),
with_sum_func(item->with_sum_func),
fixed(item->fixed),
- collation(item->collation)
+ collation(item->collation),
+ item_flags(item->item_flags)
{
next= thd->free_list; // Put in free list
thd->free_list= this;
@@ -382,7 +385,7 @@ void Item::print_item_w_name(String *str)
{
THD *thd= current_thd;
str->append(" AS ", 4);
- append_identifier(thd, str, name, strlen(name));
+ append_identifier(thd, str, name, (uint) strlen(name));
}
}
@@ -1132,27 +1135,27 @@ void Item_ident::print(String *str)
if (!table_name || !field_name)
{
const char *nm= field_name ? field_name : name ? name : "tmp_field";
- append_identifier(thd, str, nm, strlen(nm));
+ append_identifier(thd, str, nm, (uint) strlen(nm));
return;
}
if (db_name && db_name[0] && !alias_name_used)
{
- append_identifier(thd, str, d_name, strlen(d_name));
+ append_identifier(thd, str, d_name, (uint) strlen(d_name));
str->append('.');
- append_identifier(thd, str, t_name, strlen(t_name));
+ append_identifier(thd, str, t_name, (uint) strlen(t_name));
str->append('.');
- append_identifier(thd, str, field_name, strlen(field_name));
+ append_identifier(thd, str, field_name, (uint) strlen(field_name));
}
else
{
if (table_name[0])
{
- append_identifier(thd, str, t_name, strlen(t_name));
+ append_identifier(thd, str, t_name, (uint) strlen(t_name));
str->append('.');
- append_identifier(thd, str, field_name, strlen(field_name));
+ append_identifier(thd, str, field_name, (uint) strlen(field_name));
}
else
- append_identifier(thd, str, field_name, strlen(field_name));
+ append_identifier(thd, str, field_name, (uint) strlen(field_name));
}
}
@@ -2179,7 +2182,7 @@ const String *Item_param::query_val_str(String* str) const
ptr+= escape_string_for_mysql(str_value.charset(), ptr, 0,
str_value.ptr(), str_value.length());
*ptr++= '\'';
- str->length(ptr - buf);
+ str->length((uint32) (ptr - buf));
break;
}
case NULL_VALUE:
@@ -4365,6 +4368,28 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
return val;
}
+int Item_ref::save_in_field(Field *to, bool no_conversions)
+{
+ int res;
+ if(result_field){
+ if (result_field->is_null())
+ {
+ null_value= 1;
+ return set_field_to_null_with_conversions(to, no_conversions);
+ }
+ else
+ {
+ to->set_notnull();
+ field_conv(to, result_field);
+ null_value= 0;
+ }
+ return 0;
+ }
+ res= (*ref)->save_in_field(to, no_conversions);
+ null_value= (*ref)->null_value;
+ return res;
+}
+
void Item_ref_null_helper::print(String *str)
{
@@ -4448,6 +4473,7 @@ bool Item_default_value::fix_fields(THD *thd,
struct st_table_list *table_list,
Item **items)
{
+ Item *real_arg;
Item_field *field_arg;
Field *def_field;
DBUG_ASSERT(fixed == 0);
@@ -4459,17 +4485,15 @@ bool Item_default_value::fix_fields(THD *thd,
}
if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return TRUE;
-
- if (arg->type() == REF_ITEM)
+
+ real_arg= arg->real_item();
+ if (real_arg->type() != FIELD_ITEM)
{
- Item_ref *ref= (Item_ref *)arg;
- if (ref->ref[0]->type() != FIELD_ITEM)
- {
- return TRUE;
- }
- arg= ref->ref[0];
+ my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name);
+ return TRUE;
}
- field_arg= (Item_field *)arg;
+
+ field_arg= (Item_field *)real_arg;
if (field_arg->field->flags & NO_DEFAULT_VALUE_FLAG)
{
my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name);
@@ -4602,7 +4626,8 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
Try to find field by its name and if it will be found
set field_idx properly.
*/
- (void)find_field_in_real_table(thd, table, field_name, strlen(field_name),
+ (void)find_field_in_real_table(thd, table, field_name,
+ (uint) strlen(field_name),
0, 0, &field_idx);
thd->set_query_id= save_set_query_id;
triggers= table->triggers;
@@ -5392,7 +5417,7 @@ void Item_result_field::cleanup()
** Instantiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<Item>;
template class List_iterator<Item>;
template class List_iterator_fast<Item>;
diff --git a/sql/item.h b/sql/item.h
index 1d8f44d4e29..c8180b4932a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -225,6 +225,11 @@ typedef Item* (Item::*Item_transformer) (byte *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
+/*
+ See comments for sql_yacc.yy: insert_update_elem rule
+ */
+#define MY_ITEM_PREFER_1ST_TABLE 1
+
class Item {
Item(const Item &); /* Prevent use of these */
void operator=(Item &);
@@ -269,7 +274,10 @@ public:
my_bool unsigned_flag;
my_bool with_sum_func;
my_bool fixed; /* If item fixed with fix_fields */
+ my_bool is_autogenerated_name; /* indicate was name of this Item
+ autogenerated or set by user */
DTCollation collation;
+ uint8 item_flags; /* Flags on how item should be processed */
// alloc & destruct is done as start of select using sql_alloc
Item();
@@ -288,7 +296,7 @@ public:
name=0;
#endif
} /*lint -e1509 */
- void set_name(const char *str,uint length, CHARSET_INFO *cs);
+ void set_name(const char *str, uint length, CHARSET_INFO *cs);
void rename(char *new_name);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup();
@@ -337,6 +345,11 @@ public:
*/
virtual longlong val_int()=0;
/*
+ This is just a shortcut to avoid the cast. You should still use
+ unsigned_flag to check the sign of the item.
+ */
+ inline ulonglong val_uint() { return (ulonglong) val_int(); }
+ /*
Return string representation of this item object.
SYNOPSIS
@@ -463,6 +476,18 @@ public:
*/
virtual bool const_during_execution() const
{ return (used_tables() & ~PARAM_TABLE_BIT) == 0; }
+ /*
+ This is an essential method for correct functioning of VIEWS.
+ To save a view in an .frm file we need its unequivocal
+ definition in SQL that takes into account sql_mode and
+ environmental settings. Currently such definition is restored
+ by traversing through the parsed tree of a view and
+ print()'ing SQL syntax of every node to a String buffer. This
+ method is used to print the SQL definition of an item. The
+ second use of this method is for EXPLAIN EXTENDED, to print
+ the SQL of a query after all optimizations of the parsed tree
+ have been done.
+ */
virtual void print(String *str_arg) { str_arg->append(full_name()); }
void print_item_w_name(String *);
virtual void update_used_tables() {}
@@ -565,6 +590,11 @@ public:
cleanup();
delete this;
}
+ virtual bool set_flags_processor(byte *args)
+ {
+ this->item_flags|= *((uint8*)args);
+ return false;
+ }
virtual bool is_splocal() { return 0; } /* Needed for error checking */
};
@@ -625,7 +655,7 @@ public:
Item *it= this_item();
if (name)
- it->set_name(name, strlen(name), system_charset_info);
+ it->set_name(name, (uint) strlen(name), system_charset_info);
else
it->set_name(m_name.str, m_name.length, system_charset_info);
it->make_field(field);
@@ -699,10 +729,6 @@ public:
void cleanup();
bool remove_dependence_processor(byte * arg);
void print(String *str);
-
- friend bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
- const char *table_name, List_iterator<Item> *it,
- bool any_privileges, bool allocate_view_names);
};
class Item_equal;
@@ -980,10 +1006,10 @@ public:
longlong value;
Item_int(int32 i,uint length=11) :value((longlong) i)
{ max_length=length; fixed= 1; }
-#ifdef HAVE_LONG_LONG
Item_int(longlong i,uint length=21) :value(i)
{ max_length=length; fixed= 1; }
-#endif
+ Item_int(ulonglong i, uint length= 21) :value((longlong)i)
+ { max_length=length; fixed= 1; unsigned_flag= 1; }
Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg; fixed= 1; }
Item_int(const char *str_arg, uint length=64);
@@ -1021,9 +1047,8 @@ class Item_uint :public Item_int
{
public:
Item_uint(const char *str_arg, uint length);
+ Item_uint(uint32 i) :Item_int((ulonglong) i, 10) {}
Item_uint(const char *str_arg, longlong i, uint length);
- Item_uint(uint32 i) :Item_int((longlong) i, 10)
- { unsigned_flag= 1; }
double val_real()
{ DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
String *val_str(String*);
@@ -1154,7 +1179,7 @@ public:
collation.set(cs, dv);
str_value.set_or_copy_aligned(str,length,cs);
max_length= str_value.numchars()*cs->mbmaxlen;
- set_name(name_par,0,cs);
+ set_name(name_par, 0, cs);
decimals=NOT_FIXED_DEC;
// it is constant => can be used without fix_fields (and frequently used)
fixed= 1;
@@ -1331,8 +1356,7 @@ public:
bool send(Protocol *prot, String *tmp);
void make_field(Send_field *field) { (*ref)->make_field(field); }
bool fix_fields(THD *, struct st_table_list *, Item **);
- int save_in_field(Field *field, bool no_conversions)
- { return (*ref)->save_in_field(field, no_conversions); }
+ int save_in_field(Field *field, bool no_conversions);
void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
enum Item_result result_type () const { return (*ref)->result_type(); }
enum_field_types field_type() const { return (*ref)->field_type(); }
@@ -1348,7 +1372,10 @@ public:
{
(*ref)->save_in_field(result_field, no_conversions);
}
- Item *real_item() { return *ref; }
+ Item *real_item()
+ {
+ return (*ref)->real_item();
+ }
bool walk(Item_processor processor, byte *arg)
{ return (*ref)->walk(processor, arg); }
void print(String *str);
@@ -1474,7 +1501,7 @@ public:
str_value.length(), &end_not_used, &err_not_used));
}
longlong val_int()
- {
+ {
int err;
return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err);
}
@@ -1489,62 +1516,62 @@ public:
};
-class Item_buff :public Sql_alloc
+class Cached_item :public Sql_alloc
{
public:
my_bool null_value;
- Item_buff() :null_value(0) {}
+ Cached_item() :null_value(0) {}
virtual bool cmp(void)=0;
- virtual ~Item_buff(); /*line -e1509 */
+ virtual ~Cached_item(); /*line -e1509 */
};
-class Item_str_buff :public Item_buff
+class Cached_item_str :public Cached_item
{
Item *item;
String value,tmp_value;
public:
- Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {}
+ Cached_item_str(THD *thd, Item *arg);
bool cmp(void);
- ~Item_str_buff(); // Deallocate String:s
+ ~Cached_item_str(); // Deallocate String:s
};
-class Item_real_buff :public Item_buff
+class Cached_item_real :public Cached_item
{
Item *item;
double value;
public:
- Item_real_buff(Item *item_par) :item(item_par),value(0.0) {}
+ Cached_item_real(Item *item_par) :item(item_par),value(0.0) {}
bool cmp(void);
};
-class Item_int_buff :public Item_buff
+class Cached_item_int :public Cached_item
{
Item *item;
longlong value;
public:
- Item_int_buff(Item *item_par) :item(item_par),value(0) {}
+ Cached_item_int(Item *item_par) :item(item_par),value(0) {}
bool cmp(void);
};
-class Item_decimal_buff :public Item_buff
+class Cached_item_decimal :public Cached_item
{
Item *item;
my_decimal value;
public:
- Item_decimal_buff(Item *item_par);
+ Cached_item_decimal(Item *item_par);
bool cmp(void);
};
-class Item_field_buff :public Item_buff
+class Cached_item_field :public Cached_item
{
char *buff;
Field *field;
uint length;
public:
- Item_field_buff(Item_field *item)
+ Cached_item_field(Item_field *item)
{
field=item->field;
buff= (char*) sql_calloc(length=field->pack_length());
@@ -1566,7 +1593,7 @@ public:
void print(String *str);
int save_in_field(Field *field_arg, bool no_conversions);
table_map used_tables() const { return (table_map)0L; }
-
+
bool walk(Item_processor processor, byte *args)
{
return arg->walk(processor, args) ||
@@ -1872,7 +1899,7 @@ void mark_select_range_as_dependent(THD *thd,
Field *found_field, Item *found_item,
Item_ident *resolved_item);
-extern Item_buff *new_Item_buff(Item *item);
+extern Cached_item *new_Cached_item(THD *thd, Item *item);
extern Item_result item_cmp_type(Item_result a,Item_result b);
extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
extern bool field_is_equal_to_item(Field *field,Item *item);
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index af17d377e31..a67e420170a 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -20,23 +20,23 @@
#include "mysql_priv.h"
/*
-** Create right type of item_buffer for an item
+** Create right type of Cached_item for an item
*/
-Item_buff *new_Item_buff(Item *item)
+Cached_item *new_Cached_item(THD *thd, Item *item)
{
if (item->type() == Item::FIELD_ITEM &&
!(((Item_field *) item)->field->flags & BLOB_FLAG))
- return new Item_field_buff((Item_field *) item);
+ return new Cached_item_field((Item_field *) item);
switch (item->result_type()) {
case STRING_RESULT:
- return new Item_str_buff((Item_field *) item);
+ return new Cached_item_str(thd, (Item_field *) item);
case INT_RESULT:
- return new Item_int_buff((Item_field *) item);
+ return new Cached_item_int((Item_field *) item);
case REAL_RESULT:
- return new Item_real_buff(item);
+ return new Cached_item_real(item);
case DECIMAL_RESULT:
- return new Item_decimal_buff(item);
+ return new Cached_item_decimal(item);
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@@ -44,19 +44,24 @@ Item_buff *new_Item_buff(Item *item)
}
}
-Item_buff::~Item_buff() {}
+Cached_item::~Cached_item() {}
/*
** Compare with old value and replace value with new value
** Return true if values have changed
*/
-bool Item_str_buff::cmp(void)
+Cached_item_str::Cached_item_str(THD *thd, Item *arg)
+ :item(arg), value(min(arg->max_length, thd->variables.max_sort_length))
+{}
+
+bool Cached_item_str::cmp(void)
{
String *res;
bool tmp;
- res=item->val_str(&tmp_value);
+ if ((res=item->val_str(&tmp_value)))
+ res->length(min(res->length(), value.alloced_length()));
if (null_value != item->null_value)
{
if ((null_value= item->null_value))
@@ -72,12 +77,12 @@ bool Item_str_buff::cmp(void)
return tmp;
}
-Item_str_buff::~Item_str_buff()
+Cached_item_str::~Cached_item_str()
{
item=0; // Safety
}
-bool Item_real_buff::cmp(void)
+bool Cached_item_real::cmp(void)
{
double nr= item->val_real();
if (null_value != item->null_value || nr != value)
@@ -89,7 +94,7 @@ bool Item_real_buff::cmp(void)
return FALSE;
}
-bool Item_int_buff::cmp(void)
+bool Cached_item_int::cmp(void)
{
longlong nr=item->val_int();
if (null_value != item->null_value || nr != value)
@@ -102,7 +107,7 @@ bool Item_int_buff::cmp(void)
}
-bool Item_field_buff::cmp(void)
+bool Cached_item_field::cmp(void)
{
bool tmp= field->cmp(buff) != 0; // This is not a blob!
if (tmp)
@@ -116,14 +121,14 @@ bool Item_field_buff::cmp(void)
}
-Item_decimal_buff::Item_decimal_buff(Item *it)
+Cached_item_decimal::Cached_item_decimal(Item *it)
:item(it)
{
my_decimal_set_zero(&value);
}
-bool Item_decimal_buff::cmp()
+bool Cached_item_decimal::cmp()
{
my_decimal tmp;
my_decimal *ptmp= item->val_decimal(&tmp);
@@ -141,7 +146,7 @@ bool Item_decimal_buff::cmp()
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
-template class List<Item_buff>;
-template class List_iterator<Item_buff>;
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+template class List<Cached_item>;
+template class List_iterator<Cached_item>;
#endif
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 28ab38c5aed..5a2e14eef2e 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -649,7 +649,7 @@ bool Item_in_optimizer::fix_left(THD *thd,
If it is preparation PS only then we do not know values of parameters =>
cant't get there values and do not need that values.
*/
- if (!thd->only_prepare())
+ if (!thd->current_arena->is_stmt_prepare())
cache->store(args[0]);
if (cache->cols() == 1)
{
@@ -1109,12 +1109,14 @@ void Item_func_between::print(String *str)
void
Item_func_ifnull::fix_length_and_dec()
{
+ agg_result_type(&hybrid_type, args, 2);
maybe_null=args[1]->maybe_null;
decimals= max(args[0]->decimals, args[1]->decimals);
- max_length= (max(args[0]->max_length - args[0]->decimals,
- args[1]->max_length - args[1]->decimals) +
- decimals);
- agg_result_type(&hybrid_type, args, 2);
+ max_length= (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) ?
+ (max(args[0]->max_length - args[0]->decimals,
+ args[1]->max_length - args[1]->decimals) + decimals) :
+ max(args[0]->max_length, args[1]->max_length);
+
switch (hybrid_type) {
case STRING_RESULT:
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
@@ -1225,16 +1227,7 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
- if (decimals == NOT_FIXED_DEC)
- {
- max_length= max(args[1]->max_length, args[2]->max_length);
- }
- else
- {
- max_length= (max(args[1]->max_length - args[1]->decimals,
- args[2]->max_length - args[2]->decimals) +
- decimals);
- }
+
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
bool null1=args[1]->const_item() && args[1]->null_value;
@@ -1263,6 +1256,11 @@ Item_func_if::fix_length_and_dec()
collation.set(&my_charset_bin); // Number
}
}
+ max_length=
+ (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
+ (max(args[1]->max_length - args[1]->decimals,
+ args[2]->max_length - args[2]->decimals) + decimals) :
+ max(args[1]->max_length, args[2]->max_length);
}
@@ -1408,9 +1406,7 @@ Item_func_nullif::val_decimal(my_decimal * decimal_value)
bool
Item_func_nullif::is_null()
{
- if (!cmp.compare())
- return (null_value=1);
- return 0;
+ return (null_value= (!cmp.compare() ? 1 : args[0]->null_value));
}
/*
@@ -2796,10 +2792,11 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
if (canDoTurboBM)
{
pattern = first + 1;
- pattern_len = len - 2;
+ pattern_len = (int) len - 2;
DBUG_PRINT("info", ("Initializing pattern: '%s'", first));
- int *suff = (int*) thd->alloc(sizeof(int)*((pattern_len + 1)*2+
- alphabet_size));
+ int *suff = (int*) thd->alloc((int) (sizeof(int)*
+ ((pattern_len + 1)*2+
+ alphabet_size)));
bmGs = suff + pattern_len + 1;
bmBc = bmGs + pattern_len + 1;
turboBM_compute_good_suffix_shifts(suff);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 68292859504..57f68bbc2a0 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -161,7 +161,7 @@ bool Item_func::agg_arg_charsets(DTCollation &coll,
}
THD *thd= current_thd;
- Item_arena *arena, backup;
+ Query_arena *arena, backup;
bool res= FALSE;
/*
In case we're in statement prepare, create conversion item
@@ -879,11 +879,11 @@ longlong Item_func_numhybrid::val_int()
return (longlong)real_op();
case STRING_RESULT:
{
- char *end_not_used;
int err_not_used;
String *res= str_op(&str_value);
+ char *end= (char*) res->ptr() + res->length();
CHARSET_INFO *cs= str_value.charset();
- return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end_not_used,
+ return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end,
&err_not_used) : 0);
}
default:
@@ -1022,7 +1022,8 @@ longlong Item_func_unsigned::val_int()
String *Item_decimal_typecast::val_str(String *str)
{
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
- my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf);
+ if (null_value)
+ return NULL;
my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str);
return str;
}
@@ -1032,6 +1033,8 @@ double Item_decimal_typecast::val_real()
{
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
double res;
+ if (null_value)
+ return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res);
return res;
}
@@ -1041,6 +1044,8 @@ longlong Item_decimal_typecast::val_int()
{
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
longlong res;
+ if (null_value)
+ return 0;
my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res);
return res;
}
@@ -1049,11 +1054,21 @@ longlong Item_decimal_typecast::val_int()
my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
{
my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf);
+ if ((null_value= args[0]->null_value))
+ return NULL;
my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec);
return dec;
}
+void Item_decimal_typecast::print(String *str)
+{
+ str->append("cast(", 5);
+ args[0]->print(str);
+ str->append(" as decimal)", 12);
+}
+
+
double Item_func_plus::real_op()
{
double value= args[0]->val_real() + args[1]->val_real();
@@ -1876,7 +1891,8 @@ void Item_func_round::fix_length_and_dec()
max_length= float_length(decimals);
break;
case INT_RESULT:
- if (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
+ if ((decimals_to_set==0) &&
+ (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)))
{
/* Here we can keep INT_RESULT */
hybrid_type= INT_RESULT;
@@ -1890,18 +1906,12 @@ void Item_func_round::fix_length_and_dec()
hybrid_type= DECIMAL_RESULT;
int decimals_delta= args[0]->decimals - decimals_to_set;
int precision= args[0]->decimal_precision();
- if (decimals_delta > 0)
- {
- int length_increase= truncate ? 0:1;
- precision-= decimals_delta - length_increase;
- decimals= decimals_to_set;
- }
- else
- /* Decimals to set is bigger that the original scale */
- /* we keep original decimals value */
- decimals= args[0]->decimals;
+ int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1;
+
+ precision-= decimals_delta - length_increase;
+ decimals= decimals_to_set;
max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ unsigned_flag);
break;
}
default:
@@ -4109,7 +4119,7 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
return 1; // Same item is same.
/* Check if other type is also a get_user_var() object */
if (item->type() != FUNC_ITEM ||
- ((Item_func*) item)->func_name() != func_name())
+ ((Item_func*) item)->functype() != functype())
return 0;
Item_func_get_user_var *other=(Item_func_get_user_var*) item;
return (name.length == other->name.length &&
@@ -4610,7 +4620,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
if (!(item=var->item(thd, var_type, &null_lex_string)))
return 0; // Impossible
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- item->set_name(item_name, 0, system_charset_info); // Will use original name
+ item->set_name(item_name, 0, system_charset_info); // Will use original name
return item;
}
@@ -4697,6 +4707,16 @@ Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list)
dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
}
+void
+Item_func_sp::cleanup()
+{
+ if (result_field)
+ {
+ delete result_field;
+ result_field= NULL;
+ }
+ Item_func::cleanup();
+}
const char *
Item_func_sp::func_name() const
@@ -4723,6 +4743,7 @@ Item_func_sp::func_name() const
Field *
Item_func_sp::sp_result_field(void) const
{
+ Field *field;
DBUG_ENTER("Item_func_sp::sp_result_field");
if (!m_sp)
@@ -4744,7 +4765,8 @@ Item_func_sp::sp_result_field(void) const
share->table_cache_key = empty_name;
share->table_name = empty_name;
}
- DBUG_RETURN(m_sp->make_field(max_length, name, dummy_table));
+ field= m_sp->make_field(max_length, name, dummy_table);
+ DBUG_RETURN(field);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index f0c7e25ad53..e0f14ceac75 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -54,7 +54,8 @@ public:
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
NOT_FUNC, NOT_ALL_FUNC,
NOW_FUNC, TRIG_COND_FUNC,
- GUSERVAR_FUNC};
+ GUSERVAR_FUNC, COLLATE_FUNC,
+ EXTRACT_FUNC, CHAR_TYPECAST_FUNC };
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
OPTIMIZE_EQUAL };
enum Type type() const { return FUNC_ITEM; }
@@ -123,7 +124,17 @@ public:
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
virtual bool have_rev_func() const { return 0; }
virtual Item *key_item() const { return args[0]; }
- virtual const char *func_name() const { return "?"; }
+ /*
+ This method is used for debug purposes to print the name of an
+ item to the debug log. The second use of this method is as
+ a helper function of print(), where it is applicable.
+ To suit both goals it should return a meaningful,
+ distinguishable and sintactically correct string. This method
+ should not be used for runtime type identification, use enum
+ {Sum}Functype and Item_func::functype()/Item_sum::sum_func()
+ instead.
+ */
+ virtual const char *func_name() const= 0;
virtual bool const_item() const { return const_item_cache; }
inline Item **arguments() const { return args; }
void set_arguments(List<Item> &list);
@@ -306,6 +317,8 @@ public:
enum Item_result result_type () const { return DECIMAL_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
void fix_length_and_dec() {};
+ const char *func_name() const { return "decimal_typecast"; }
+ void print(String *);
};
@@ -506,7 +519,7 @@ public:
class Item_func_acos :public Item_dec_func
{
- public:
+public:
Item_func_acos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "acos"; }
@@ -514,7 +527,7 @@ class Item_func_acos :public Item_dec_func
class Item_func_asin :public Item_dec_func
{
- public:
+public:
Item_func_asin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "asin"; }
@@ -522,7 +535,7 @@ class Item_func_asin :public Item_dec_func
class Item_func_atan :public Item_dec_func
{
- public:
+public:
Item_func_atan(Item *a) :Item_dec_func(a) {}
Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
@@ -531,7 +544,7 @@ class Item_func_atan :public Item_dec_func
class Item_func_cos :public Item_dec_func
{
- public:
+public:
Item_func_cos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "cos"; }
@@ -539,7 +552,7 @@ class Item_func_cos :public Item_dec_func
class Item_func_sin :public Item_dec_func
{
- public:
+public:
Item_func_sin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sin"; }
@@ -547,7 +560,7 @@ class Item_func_sin :public Item_dec_func
class Item_func_tan :public Item_dec_func
{
- public:
+public:
Item_func_tan(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "tan"; }
@@ -634,7 +647,7 @@ class Item_func_units :public Item_real_func
{
char *name;
double mul,add;
- public:
+public:
Item_func_units(char *name_arg,Item *a,double mul_arg,double add_arg)
:Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {}
double val_real();
@@ -853,7 +866,7 @@ public:
class Item_func_benchmark :public Item_int_func
{
ulong loop_count;
- public:
+public:
Item_func_benchmark(ulong loop_count_arg,Item *expr)
:Item_int_func(expr), loop_count(loop_count_arg)
{}
@@ -868,7 +881,7 @@ class Item_func_benchmark :public Item_int_func
class Item_udf_func :public Item_func
{
- protected:
+protected:
udf_handler udf;
public:
@@ -1046,7 +1059,7 @@ class Item_func_get_lock :public Item_int_func
class Item_func_release_lock :public Item_int_func
{
String value;
- public:
+public:
Item_func_release_lock(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "release_lock"; }
@@ -1058,7 +1071,7 @@ class Item_func_release_lock :public Item_int_func
class Item_master_pos_wait :public Item_int_func
{
String value;
- public:
+public:
Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {}
Item_master_pos_wait(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {}
longlong val_int();
@@ -1308,13 +1321,7 @@ public:
virtual ~Item_func_sp()
{}
- void cleanup()
- {
- if (result_field)
- delete result_field;
- Item_func::cleanup();
- result_field= NULL;
- }
+ void cleanup();
const char *func_name() const;
@@ -1330,7 +1337,7 @@ public:
{
if (execute(&result_field))
return (longlong) 0;
- return result_field->val_int();
+ return result_field->val_int();
}
double val_real()
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index d3327a0e41f..9f7a44f6f47 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1668,22 +1668,36 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
String *Item_func_format::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- double nr= args[0]->val_real();
- uint32 length,str_length,dec;
+ uint32 length, str_length ,dec;
int diff;
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- nr= my_double_round(nr, decimals, FALSE);
+ DBUG_ASSERT(fixed == 1);
dec= decimals ? decimals+1 : 0;
- /* Here default_charset() is right as this is not an automatic conversion */
- str->set(nr,decimals, default_charset());
- if (isnan(nr))
- return str;
- str_length=str->length();
- if (nr < 0)
- str_length--; // Don't count sign
+ if (args[0]->result_type() == DECIMAL_RESULT ||
+ args[0]->result_type() == INT_RESULT)
+ {
+ my_decimal dec_val, rnd_dec, *res;
+ res= args[0]->val_decimal(&dec_val);
+ my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, &rnd_dec);
+ my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
+ str_length= str->length();
+ if (rnd_dec.sign())
+ str_length--;
+ }
+ else
+ {
+ double nr= args[0]->val_real();
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ nr= my_double_round(nr, decimals, FALSE);
+ /* Here default_charset() is right as this is not an automatic conversion */
+ str->set(nr,decimals, default_charset());
+ if (isnan(nr))
+ return str;
+ str_length=str->length();
+ if (nr < 0)
+ str_length--; // Don't count sign
+ }
/* We need this test to handle 'nan' values */
if (str_length >= dec+4)
{
@@ -2283,7 +2297,7 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
return 0;
Item_func *item_func=(Item_func*) item;
if (arg_count != item_func->arg_count ||
- func_name() != item_func->func_name())
+ functype() != item_func->functype())
return 0;
Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item;
if (collation.collation != item_func_sc->collation.collation)
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 6df90cebdff..8d2eb269915 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -573,6 +573,7 @@ public:
max_length=args[0]->max_length;
}
void print(String *str);
+ const char *func_name() const { return "cast_as_binary"; }
};
@@ -648,6 +649,7 @@ public:
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "collate"; }
+ enum Functype func_type() const { return COLLATE_FUNC; }
void print(String *str);
Item_field *filed_for_view_update()
{
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 1569b6f2f12..393cb87c113 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -340,7 +340,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
return RES_OK;
SELECT_LEX *select_lex= join->select_lex;
- Item_arena *arena= thd->current_arena;
+ Query_arena *arena= thd->current_arena;
if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
@@ -600,8 +600,8 @@ void Item_exists_subselect::fix_length_and_dec()
decimals= 0;
max_length= 1;
max_columns= engine->cols();
- /* We need only 1 row to determinate existence */
- unit->global_parameters->select_limit= 1;
+ /* We need only 1 row to determine existence */
+ unit->global_parameters->select_limit= new Item_int((int32) 1);
}
double Item_exists_subselect::val_real()
@@ -1164,7 +1164,7 @@ Item_in_subselect::select_transformer(JOIN *join)
Item_subselect::trans_res
Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func)
{
- Item_arena *arena, backup;
+ Query_arena *arena, backup;
SELECT_LEX *current= thd->lex->current_select, *up;
const char *save_where= thd->where;
Item_subselect::trans_res res= RES_ERROR;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index f7a158ceb5a..76f94801b49 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -86,7 +86,6 @@ void Item_sum::make_field(Send_field *tmp_field)
void Item_sum::print(String *str)
{
str->append(func_name());
- str->append('(');
for (uint i=0 ; i < arg_count ; i++)
{
if (i)
@@ -2425,13 +2424,6 @@ longlong Item_sum_count_distinct::val_int()
}
-void Item_sum_count_distinct::print(String *str)
-{
- str->append("count(distinct ", 15);
- args[0]->print(str);
- str->append(')');
-}
-
/****************************************************************************
** Functions to handle dynamic loadable aggregates
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
@@ -2466,6 +2458,20 @@ void Item_udf_sum::cleanup()
}
+void Item_udf_sum::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (i)
+ str->append(',');
+ args[i]->print(str);
+ }
+ str->append(')');
+}
+
+
Item *Item_sum_udf_float::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_udf_float(thd, this);
diff --git a/sql/item_sum.h b/sql/item_sum.h
index bb5d31b4b4f..b9a90ee5de5 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -81,7 +81,22 @@ public:
virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
- virtual const char *func_name() const { return "?"; }
+ /*
+ This method is used for debug purposes to print the name of an
+ item to the debug log. The second use of this method is as
+ a helper function of print(), where it is applicable.
+ To suit both goals it should return a meaningful,
+ distinguishable and sintactically correct string. This method
+ should not be used for runtime type identification, use enum
+ {Sum}Functype and Item_func::functype()/Item_sum::sum_func()
+ instead.
+
+ NOTE: for Items inherited from Item_sum, func_name() return part of
+ function name till first argument (including '(') to make difference in
+ names for functions with 'distinct' clause and without 'distinct' and
+ also to make printing of items inherited from Item_sum uniform.
+ */
+ virtual const char *func_name() const= 0;
virtual Item *result_item(Field *field)
{ return new Item_field(field);}
table_map used_tables() const { return ~(table_map) 0; } /* Not used */
@@ -159,7 +174,7 @@ public:
void reset_field();
void update_field();
void no_rows_in_result() {}
- const char *func_name() const { return "sum"; }
+ const char *func_name() const { return "sum("; }
Item *copy_or_same(THD* thd);
};
@@ -200,7 +215,6 @@ public:
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
void reset_field() {} // not used
void update_field() {} // not used
- const char *func_name() const { return "sum_distinct"; }
virtual void no_rows_in_result() {}
void fix_length_and_dec();
enum Item_result result_type () const { return val.traits->type(); }
@@ -224,7 +238,7 @@ public:
Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
- const char *func_name() const { return "sum_distinct"; }
+ const char *func_name() const { return "sum(distinct "; }
Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
};
@@ -243,7 +257,7 @@ public:
void fix_length_and_dec();
virtual void calculate_val_and_count();
enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
- const char *func_name() const { return "avg_distinct"; }
+ const char *func_name() const { return "avg(distinct "; }
Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
};
@@ -272,7 +286,7 @@ class Item_sum_count :public Item_sum_int
void reset_field();
void cleanup();
void update_field();
- const char *func_name() const { return "count"; }
+ const char *func_name() const { return "count("; }
Item *copy_or_same(THD* thd);
};
@@ -326,12 +340,11 @@ public:
longlong val_int();
void reset_field() { return ;} // Never called
void update_field() { return ; } // Never called
- const char *func_name() const { return "count_distinct"; }
+ const char *func_name() const { return "count(distinct "; }
bool setup(THD *thd);
void make_unique();
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
- void print(String *str);
};
@@ -389,7 +402,7 @@ public:
Item *result_item(Field *field)
{ return new Item_avg_field(hybrid_type, this); }
void no_rows_in_result() {}
- const char *func_name() const { return "avg"; }
+ const char *func_name() const { return "avg("; }
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
};
@@ -466,7 +479,7 @@ public:
Item *result_item(Field *field)
{ return new Item_variance_field(this); }
void no_rows_in_result() {}
- const char *func_name() const { return "variance"; }
+ const char *func_name() const { return "variance("; }
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
enum Item_result result_type () const { return hybrid_type; }
@@ -501,7 +514,7 @@ class Item_sum_std :public Item_sum_variance
double val_real();
Item *result_item(Field *field)
{ return new Item_std_field(this); }
- const char *func_name() const { return "std"; }
+ const char *func_name() const { return "std("; }
Item *copy_or_same(THD* thd);
enum Item_result result_type () const { return REAL_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
@@ -565,7 +578,7 @@ public:
enum Sumfunctype sum_func () const {return MIN_FUNC;}
bool add();
- const char *func_name() const { return "min"; }
+ const char *func_name() const { return "min("; }
Item *copy_or_same(THD* thd);
};
@@ -578,7 +591,7 @@ public:
enum Sumfunctype sum_func () const {return MAX_FUNC;}
bool add();
- const char *func_name() const { return "max"; }
+ const char *func_name() const { return "max("; }
Item *copy_or_same(THD* thd);
};
@@ -609,7 +622,7 @@ public:
Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {}
bool add();
- const char *func_name() const { return "bit_or"; }
+ const char *func_name() const { return "bit_or("; }
Item *copy_or_same(THD* thd);
};
@@ -620,7 +633,7 @@ class Item_sum_and :public Item_sum_bit
Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {}
Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {}
bool add();
- const char *func_name() const { return "bit_and"; }
+ const char *func_name() const { return "bit_and("; }
Item *copy_or_same(THD* thd);
};
@@ -630,7 +643,7 @@ class Item_sum_xor :public Item_sum_bit
Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {}
bool add();
- const char *func_name() const { return "bit_xor"; }
+ const char *func_name() const { return "bit_xor("; }
Item *copy_or_same(THD* thd);
};
@@ -668,6 +681,7 @@ public:
void reset_field() {};
void update_field() {};
void cleanup();
+ void print(String *str);
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 564c5e4b9cc..19386c15835 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2158,7 +2158,7 @@ bool Item_extract::eq(const Item *item, bool binary_cmp) const
if (this == item)
return 1;
if (item->type() != FUNC_ITEM ||
- func_name() != ((Item_func*)item)->func_name())
+ functype() != ((Item_func*)item)->functype())
return 0;
Item_extract* ie= (Item_extract*)item;
@@ -2176,7 +2176,7 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
if (this == item)
return 1;
if (item->type() != FUNC_ITEM ||
- func_name() != ((Item_func*)item)->func_name())
+ functype() != ((Item_func*)item)->functype())
return 0;
Item_char_typecast *cast= (Item_char_typecast*)item;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index c8fb2b39836..a6dd9f7da91 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -503,7 +503,8 @@ public:
Item_func_date_format(Item *a,Item *b,bool is_time_format_arg)
:Item_str_func(a,b),is_time_format(is_time_format_arg) {}
String *val_str(String *str);
- const char *func_name() const { return "date_format"; }
+ const char *func_name() const
+ { return is_time_format ? "time_format" : "date_format"; }
void fix_length_and_dec();
uint format_length(const String *format);
};
@@ -637,6 +638,7 @@ class Item_extract :public Item_int_func
Item_extract(interval_type type_arg, Item *a)
:Item_int_func(a), int_type(type_arg) {}
longlong val_int();
+ enum Functype functype() const { return EXTRACT_FUNC; }
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
@@ -689,6 +691,7 @@ class Item_char_typecast :public Item_typecast
public:
Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg)
:Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {}
+ enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "cast_as_char"; }
const char* cast_type() const { return "char"; };
@@ -790,6 +793,7 @@ public:
return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin));
}
void print(String *str);
+ const char *func_name() const { return "add_time"; }
};
class Item_func_timediff :public Item_str_func
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index 14b2e8d53bb..e95aa35101e 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -30,6 +30,7 @@ public:
double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
void fix_length_and_dec() { decimals=0; max_length=6; }
void print(String *str) { str->append("0.0", 3); }
+ const char *func_name() const { return "unique_users"; }
};
@@ -58,4 +59,5 @@ public:
}
void print(String *str) { str->append("0.0", 3); }
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
+ const char *func_name() const { return "sum_unique_users"; }
};
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 3b6b3cda0b4..08aedfb3f63 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -708,7 +708,7 @@ failed my_b_read"));
Log_event *res= 0;
#ifndef max_allowed_packet
THD *thd=current_thd;
- uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~0;
+ uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0;
#endif
if (data_len > max_allowed_packet)
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index 27fd33cffbe..b65e6aedaa2 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -290,6 +290,11 @@ int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
inline
void my_decimal_neg(decimal_t *arg)
{
+ if (decimal_is_zero(arg))
+ {
+ arg->sign= 0;
+ return;
+ }
decimal_neg(arg);
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index c5753a7f114..2b185dbc13b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -218,66 +218,75 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */
#define TEST_NO_STACKTRACE 512
#define TEST_SIGINT 1024 /* Allow sigint on threads */
-#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in some
- places */
+#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in
+ some places */
#endif
-/*
+/*
This is included in the server and in the client.
Options for select set by the yacc parser (stored in lex->options).
- None of the 32 defines below should have its value changed, or this will
- break replication.
+
+ XXX:
+ log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD
+ options list are written into binlog. These options can NOT change their
+ values, or it will break replication between version.
+
+ context is encoded as following:
+ SELECT - SELECT_LEX_NODE::options
+ THD - THD::options
+ intern - neither. used only as
+ func(..., select_node->options | thd->options | OPTION_XXX, ...)
+
+ TODO: separate three contexts above, move them to separate bitfields.
*/
-#define SELECT_DISTINCT (1L << 0)
-#define SELECT_STRAIGHT_JOIN (1L << 1)
-#define SELECT_DESCRIBE (1L << 2)
-#define SELECT_SMALL_RESULT (1L << 3)
-#define SELECT_BIG_RESULT (1L << 4)
-#define OPTION_FOUND_ROWS (1L << 5)
-#define OPTION_TO_QUERY_CACHE (1L << 6)
-#define SELECT_NO_JOIN_CACHE (1L << 7) /* Intern */
-#define OPTION_BIG_TABLES (1L << 8) /* for SQL OPTION */
-#define OPTION_BIG_SELECTS (1L << 9) /* for SQL OPTION */
-#define OPTION_LOG_OFF (1L << 10)
-#define OPTION_UPDATE_LOG (1L << 11) /* update log flag */
-#define TMP_TABLE_ALL_COLUMNS (1L << 12)
-#define OPTION_WARNINGS (1L << 13)
-#define OPTION_AUTO_IS_NULL (1L << 14)
-#define OPTION_FOUND_COMMENT (1L << 15)
-#define OPTION_SAFE_UPDATES (1L << 16)
-#define OPTION_BUFFER_RESULT (1L << 17)
-#define OPTION_BIN_LOG (1L << 18)
-#define OPTION_NOT_AUTOCOMMIT (1L << 19)
-#define OPTION_BEGIN (1L << 20)
-#define OPTION_TABLE_LOCK (1L << 21)
-#define OPTION_QUICK (1L << 22)
-#define OPTION_QUOTE_SHOW_CREATE (1L << 23)
-#define OPTION_INTERNAL_SUBTRANSACTIONS (1L << 24)
+#define SELECT_DISTINCT (1L << 0) // SELECT, user
+#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user
+#define SELECT_DESCRIBE (1L << 2) // SELECT, user
+#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user
+#define SELECT_BIG_RESULT (1L << 4) // SELECT, user
+#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user
+#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user
+#define SELECT_NO_JOIN_CACHE (1L << 7) // intern
+#define OPTION_BIG_TABLES (1L << 8) // THD, user
+#define OPTION_BIG_SELECTS (1L << 9) // THD, user
+#define OPTION_LOG_OFF (1L << 10) // THD, user
+#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused
+#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern
+#define OPTION_WARNINGS (1L << 13) // THD, user
+#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog
+#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser
+#define OPTION_SAFE_UPDATES (1L << 16) // THD, user
+#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user
+#define OPTION_BIN_LOG (1L << 18) // THD, user
+#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user
+#define OPTION_BEGIN (1L << 20) // THD, intern
+#define OPTION_TABLE_LOCK (1L << 21) // THD, intern
+#define OPTION_QUICK (1L << 22) // SELECT (for DELETE)
+#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user
+
+/* Thr following is used to detect a conflict with DISTINCT
+ in the user query has requested */
+#define SELECT_ALL (1L << 24) // SELECT, user, parser
/* Set if we are updating a non-transaction safe table */
-#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25)
+#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern
/* The following can be set when importing tables in a 'wrong order'
to suppress foreign key checks */
-#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26)
+#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog
/* The following speeds up inserts to InnoDB tables by suppressing unique
key checks in some cases */
-#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27)
-#define SELECT_NO_UNLOCK (1L << 28)
-#define OPTION_SCHEMA_TABLE (1L << 29)
+#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog
+#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern
+#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern
/* Flag set if setup_tables already done */
-#define OPTION_SETUP_TABLES_DONE (1L << 30)
-
-/* Options for select set by the yacc parser (stored in lex->options2). */
-
-
-/* The following is used to detect a conflict with DISTINCT
- in the user query has requested */
-#define SELECT_ALL (1L << 0)
+#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern
+/* If not set then the thread will ignore all warnings with level notes. */
+#define OPTION_SQL_NOTES (1L << 31) // THD, user
-/*
- Maximum length of time zone name that we support
+/*
+ Maximum length of time zone name that we support
(Time zone name is char(64) in db). mysqlbinlog needs it.
*/
#define MAX_TIME_ZONE_NAME_LENGTH 72
@@ -285,13 +294,10 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
/* The rest of the file is included in the server only */
#ifndef MYSQL_CLIENT
-/* If not set then the thread will ignore all warnings with level notes. */
-#define OPTION_SQL_NOTES (1L << 31)
-
/* Bits for different SQL modes modes (including ANSI mode) */
-#define MODE_REAL_AS_FLOAT 1
-#define MODE_PIPES_AS_CONCAT 2
-#define MODE_ANSI_QUOTES 4
+#define MODE_REAL_AS_FLOAT 1
+#define MODE_PIPES_AS_CONCAT 2
+#define MODE_ANSI_QUOTES 4
#define MODE_IGNORE_SPACE 8
#define MODE_NOT_USED 16
#define MODE_ONLY_FULL_GROUP_BY 32
@@ -319,6 +325,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
+#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
use strictly more than 64 bits by adding one more define above, you should
@@ -340,6 +347,8 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define UNCACHEABLE_SIDEEFFECT 4
// forcing to save JOIN for explain
#define UNCACHEABLE_EXPLAIN 8
+/* Don't evaluate subqueries in prepare even if they're not correlated */
+#define UNCACHEABLE_PREPARE 16
#ifdef EXTRA_DEBUG
/*
@@ -484,7 +493,7 @@ bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
-bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
bool mysql_multi_update_prepare(THD *thd);
bool mysql_multi_delete_prepare(THD *thd);
bool mysql_insert_select_prepare(THD *thd);
@@ -551,8 +560,6 @@ struct Query_cache_query_flags
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
#endif /*HAVE_QUERY_CACHE*/
-#define prepare_execute(A) ((A)->command == COM_EXECUTE)
-
bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -579,6 +586,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
+bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void init_max_user_conn(void);
void init_update_queries(void);
void free_max_user_conn(void);
@@ -590,6 +598,7 @@ bool mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
+void log_slow_statement(THD *thd);
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
bool table_cache_init(void);
@@ -832,10 +841,10 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name);
void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length);
-void mysql_stmt_free(THD *thd, char *packet);
+void mysql_stmt_close(THD *thd, char *packet);
void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
-void reset_stmt_for_execute(THD *thd, LEX *lex);
+void reinit_stmt_before_use(THD *thd, LEX *lex);
void init_stmt_after_parse(THD*, LEX*);
/* sql_handler.cc */
@@ -885,8 +894,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
- List_iterator<Item> *it, bool any_privileges,
- bool allocate_view_names);
+ List_iterator<Item> *it, bool any_privileges);
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
TABLE_LIST **leaves, bool select_insert);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
@@ -1107,6 +1115,7 @@ extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_readonly, lower_case_file_system;
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
extern my_bool opt_secure_auth;
+extern my_bool opt_log_slow_admin_statements;
extern my_bool sp_automatic_privileges, opt_noacl;
extern my_bool opt_old_style_user_limits, trust_routine_creators;
extern uint opt_crash_binlog_innodb;
@@ -1220,7 +1229,7 @@ int openfrm(THD *thd, const char *name,const char *alias,uint filestat,
int readfrm(const char *name, const void** data, uint* length);
int writefrm(const char* name, const void* data, uint len);
int closefrm(TABLE *table);
-db_type get_table_type(const char *name);
+db_type get_table_type(THD *thd, const char *name);
int read_string(File file, gptr *to, uint length);
void free_blobs(TABLE *table);
int set_zone(int nr,int min_zone,int max_zone);
@@ -1277,7 +1286,7 @@ ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
ulong next_io_size(ulong pos);
void append_unescaped(String *res, const char *pos, uint length);
-int create_frm(char *name,uint reclength,uchar *fileinfo,
+int create_frm(THD *thd, char *name,uint reclength,uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys);
void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
int rename_file_ext(const char * from,const char * to,const char * ext);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 69aba3abd42..6a1d04fa69a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -230,6 +230,7 @@ static const char *sql_mode_names[] =
"NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES", "STRICT_ALL_TABLES",
"NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO",
"TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE",
+ "NO_ENGINE_SUBSTITUTION",
NullS
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
@@ -327,6 +328,7 @@ ulong opt_ndb_nodeid;
my_bool opt_readonly, use_temp_pool, relay_log_purge;
my_bool opt_sync_frm, opt_allow_suspicious_udfs;
my_bool opt_secure_auth= 0;
+my_bool opt_log_slow_admin_statements= 0;
my_bool lower_case_file_system= 0;
my_bool opt_large_pages= 0;
uint opt_large_page_size= 0;
@@ -1272,19 +1274,6 @@ static void server_init(void)
int arg=1;
DBUG_ENTER("server_init");
-#ifdef __WIN__
- if (!opt_disable_networking)
- {
- WSADATA WsaData;
- if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
- {
- /* errors are not read yet, so we use test here */
- my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
- unireg_abort(1);
- }
- }
-#endif /* __WIN__ */
-
set_ports();
if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap)
@@ -3018,6 +3007,21 @@ int main(int argc, char **argv)
}
#endif
+#ifdef __WIN__
+/* Before performing any socket operation (like retrieving hostname */
+/* in init_common_variables we have to call WSAStartup */
+ if (!opt_disable_networking)
+ {
+ WSADATA WsaData;
+ if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
+ {
+ /* errors are not read yet, so we use test here */
+ my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
+ unireg_abort(1);
+ }
+ }
+#endif /* __WIN__ */
+
if (init_common_variables(MYSQL_CONFIG_NAME,
argc, argv, load_default_groups))
unireg_abort(1); // Will do exit
@@ -3098,6 +3102,11 @@ You should consider changing lower_case_table_names to 1 or 2",
lower_case_table_names= 0;
}
+ /* Reset table_alias_charset, now that lower_case_table_names is set. */
+ table_alias_charset= (lower_case_table_names ?
+ files_charset_info :
+ &my_charset_bin);
+
select_thread=pthread_self();
select_thread_in_use=1;
init_ssl();
@@ -4328,7 +4337,8 @@ enum options_mysqld
OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET,
OPT_ENABLE_LARGE_PAGES,
OPT_TIMED_MUTEXES,
- OPT_OLD_STYLE_USER_LIMITS
+ OPT_OLD_STYLE_USER_LIMITS,
+ OPT_LOG_SLOW_ADMIN_STATEMENTS
};
@@ -4653,7 +4663,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
"Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES,
- "Log queries that are executed without benefit of any index.",
+ "Log queries that are executed without benefit of any index to the slow log if it is open.",
(gptr*) &opt_log_queries_not_using_indexes, (gptr*) &opt_log_queries_not_using_indexes,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-short-format", OPT_SHORT_LOG_FORMAT,
@@ -4664,8 +4674,13 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
"Tells the slave to log the updates from the slave thread to the binary log. You will need to turn it on if you plan to daisy-chain the slaves.",
(gptr*) &opt_log_slave_updates, (gptr*) &opt_log_slave_updates, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"log-slow-admin-statements", OPT_LOG_SLOW_ADMIN_STATEMENTS,
+ "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to the slow log if it is open.",
+ (gptr*) &opt_log_slow_admin_statements,
+ (gptr*) &opt_log_slow_admin_statements,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-slow-queries", OPT_SLOW_QUERY_LOG,
- "Log slow queries to this log file. Defaults logging to hostname-slow.log file.",
+ "Log slow queries to this log file. Defaults logging to hostname-slow.log file. Must be enabled to activate other slow log options.",
(gptr*) &opt_slow_logname, (gptr*) &opt_slow_logname, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"log-tc", OPT_LOG_TC,
@@ -5225,7 +5240,7 @@ log and this option does nothing anymore.",
{"innodb_thread_concurrency", OPT_INNODB_THREAD_CONCURRENCY,
"Helps in performance tuning in heavily concurrent environments.",
(gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency,
- 0, GET_LONG, REQUIRED_ARG, 8, 1, 1000, 0, 1, 0},
+ 0, GET_LONG, REQUIRED_ARG, 20, 1, 1000, 0, 1, 0},
{"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
" disable a sleep",
@@ -5376,7 +5391,7 @@ The minimum value for this variable is 4096.",
(gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
6, 2, 8, 0, 1, 0},
{"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
- "Depricated option",
+ "Deprecated option",
(gptr*) &global_system_variables.myisam_max_extra_sort_file_size,
(gptr*) &max_system_variables.myisam_max_extra_sort_file_size,
0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH,
@@ -5713,6 +5728,12 @@ struct show_var_st status_vars[]= {
{"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
{"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
{"Com_slave_stop", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_STOP]), SHOW_LONG_STATUS},
+ {"Com_stmt_prepare", (char*) offsetof(STATUS_VAR, com_stmt_prepare), SHOW_LONG_STATUS},
+ {"Com_stmt_execute", (char*) offsetof(STATUS_VAR, com_stmt_execute), SHOW_LONG_STATUS},
+ {"Com_stmt_fetch", (char*) offsetof(STATUS_VAR, com_stmt_fetch), SHOW_LONG_STATUS},
+ {"Com_stmt_send_long_data", (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS},
+ {"Com_stmt_reset", (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS},
+ {"Com_stmt_close", (char*) offsetof(STATUS_VAR, com_stmt_close), SHOW_LONG_STATUS},
{"Com_truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS},
{"Com_unlock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNLOCK_TABLES]), SHOW_LONG_STATUS},
{"Com_update", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UPDATE]), SHOW_LONG_STATUS},
@@ -6314,6 +6335,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_SLOW_QUERY_LOG:
opt_slow_log=1;
break;
+ case (int) OPT_LOG_SLOW_ADMIN_STATEMENTS:
+ opt_log_slow_admin_statements= 1;
+ break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
@@ -6702,6 +6726,9 @@ static void get_options(int argc,char **argv)
if (opt_bdb)
sql_print_warning("this binary does not contain BDB storage engine");
#endif
+ if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes) &&
+ !opt_slow_log)
+ sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set");
/*
Check that the default storage engine is actually available.
@@ -6771,9 +6798,6 @@ static void get_options(int argc,char **argv)
/* Set global variables based on startup options */
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
- table_alias_charset= (lower_case_table_names ?
- files_charset_info :
- &my_charset_bin);
if (opt_short_log_format)
opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT;
@@ -7025,7 +7049,7 @@ static void create_pid_file()
Instantiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/* Used templates */
template class I_List<THD>;
template class I_List_iterator<THD>;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index da359b0aebd..7645ce39eea 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2598,12 +2598,12 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
{
tuple_arg= scan->sel_arg;
/* Here we use the length of the first key part */
- tuple_arg->store_min(key_part->length, &key_ptr, 0);
+ tuple_arg->store_min(key_part->store_length, &key_ptr, 0);
}
while (tuple_arg->next_key_part != sel_arg)
{
tuple_arg= tuple_arg->next_key_part;
- tuple_arg->store_min(key_part[tuple_arg->part].length, &key_ptr, 0);
+ tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0);
}
min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val);
records= (info->param->table->file->
@@ -7617,8 +7617,8 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
*records= num_groups;
DBUG_PRINT("info",
- ("records=%u, keys/block=%u, keys/group=%u, records=%u, blocks=%u",
- table_records, keys_per_block, keys_per_group, records,
+ ("table rows=%u, keys/block=%u, keys/group=%u, result rows=%u, blocks=%u",
+ table_records, keys_per_block, keys_per_group, *records,
num_blocks));
DBUG_VOID_RETURN;
}
@@ -8125,6 +8125,15 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
DBUG_ASSERT((have_max && !have_min) ||
(have_max && have_min && (max_res == 0)));
}
+ /*
+ If this is a just a GROUP BY or DISTINCT without MIN or MAX and there
+ are equality predicates for the key parts after the group, find the
+ first sub-group with the extended prefix.
+ */
+ if (!have_min && !have_max && key_infix_len > 0)
+ result= file->index_read(record, group_prefix, real_prefix_len,
+ HA_READ_KEY_EXACT);
+
result= have_min ? min_res : have_max ? max_res : result;
}
while (result == HA_ERR_KEY_NOT_FOUND && is_last_prefix != 0);
@@ -8151,9 +8160,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
QUICK_GROUP_MIN_MAX_SELECT::next_min()
DESCRIPTION
- Load the prefix of the next group into group_prefix and find the minimal
- key within this group such that the key satisfies the query conditions and
- NULL semantics. The found key is loaded into this->record.
+ Find the minimal key within this group such that the key satisfies the query
+ conditions and NULL semantics. The found key is loaded into this->record.
IMPLEMENTATION
Depending on the values of min_max_ranges.elements, key_infix_len, and
@@ -8237,9 +8245,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
QUICK_GROUP_MIN_MAX_SELECT::next_max()
DESCRIPTION
- If there was no previous next_min call to determine the next group prefix,
- then load the next prefix into group_prefix, then lookup the maximal key of
- the group, and store it into this->record.
+ Lookup the maximal key of the group, and store it into this->record.
RETURN
0 on success
@@ -8917,7 +8923,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
** Instantiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<QUICK_RANGE>;
template class List_iterator<QUICK_RANGE>;
#endif
diff --git a/sql/password.c b/sql/password.c
index 79675ade30b..60cc0ac0c97 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -146,7 +146,7 @@ void hash_password(ulong *result, const char *password, uint password_len)
void make_scrambled_password_323(char *to, const char *password)
{
ulong hash_res[2];
- hash_password(hash_res, password, strlen(password));
+ hash_password(hash_res, password, (uint) strlen(password));
sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]);
}
@@ -172,7 +172,7 @@ void scramble_323(char *to, const char *message, const char *password)
{
char extra, *to_start=to;
const char *message_end= message + SCRAMBLE_LENGTH_323;
- hash_password(hash_pass,password, strlen(password));
+ hash_password(hash_pass,password, (uint) strlen(password));
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
@@ -394,7 +394,7 @@ make_scrambled_password(char *to, const char *password)
sha1_reset(&sha1_context);
/* stage 1: hash password */
- sha1_input(&sha1_context, (uint8 *) password, strlen(password));
+ sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
sha1_result(&sha1_context, (uint8 *) to);
/* stage 2: hash stage1 output */
sha1_reset(&sha1_context);
@@ -433,7 +433,7 @@ scramble(char *to, const char *message, const char *password)
sha1_reset(&sha1_context);
/* stage 1: hash password */
- sha1_input(&sha1_context, (uint8 *) password, strlen(password));
+ sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
sha1_result(&sha1_context, hash_stage1);
/* stage 2: hash stage 1; note that hash_stage2 is stored in the database */
sha1_reset(&sha1_context);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 3f8c8ea2508..1c0de702e4e 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1616,7 +1616,10 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
if (var->value->result_type() == STRING_RESULT)
{
if (!(res= var->value->val_str(&str)))
+ {
+ strmake(buff, "NULL", 4);
goto err;
+ }
var->save_result.ulong_value= ((ulong)
find_set(enum_names, res->c_ptr(),
res->length(),
@@ -3128,7 +3131,7 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
if (!(res=var->value->val_str(&str)) ||
!(var->save_result.ulong_value=
(ulong) (db_type= ha_resolve_by_name(res->ptr(), res->length()))) ||
- ha_checktype(db_type) != db_type)
+ ha_checktype(thd, db_type, 1, 0) != db_type)
{
value= res ? res->c_ptr() : "NULL";
goto err;
@@ -3403,7 +3406,7 @@ bool process_key_caches(int (* func) (const char *name, KEY_CACHE *))
Used templates
****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<set_var_base>;
template class List_iterator_fast<set_var_base>;
template class I_List_iterator<NAMED_LIST>;
diff --git a/sql/set_var.h b/sql/set_var.h
index 56690c46131..a6532323b34 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -786,7 +786,8 @@ public:
if (value_arg && value_arg->type() == Item::FIELD_ITEM)
{
Item_field *item= (Item_field*) value_arg;
- if (!(value=new Item_string(item->field_name, strlen(item->field_name),
+ if (!(value=new Item_string(item->field_name,
+ (uint) strlen(item->field_name),
item->collation.collation)))
value=value_arg; /* Give error message later */
}
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index a020cadc084..fcc04c950aa 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5347,14 +5347,14 @@ ER_SP_NO_RETSET_IN_FUNC 0A000
ER_CANT_CREATE_GEOMETRY_OBJECT 22003
eng "Cannot get geometry object from data you send to the GEOMETRY field"
ER_FAILED_ROUTINE_BREAK_BINLOG
- eng "A routine failed and is declared to modify data and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
+ eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
ER_BINLOG_UNSAFE_ROUTINE
- eng "This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
+ eng "This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
ER_BINLOG_CREATE_ROUTINE_NEED_SUPER
- eng "You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
+ eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
ER_EXEC_STMT_WITH_OPEN_CURSOR
eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it."
ER_STMT_HAS_NO_OPEN_CURSOR
- eng "The statement (%d) has no open cursor."
+ eng "The statement (%lu) has no open cursor."
ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
eng "Explicit or implicit commit is not allowed in stored function or trigger."
diff --git a/sql/slave.cc b/sql/slave.cc
index 46b028cc431..a0779543148 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -4617,7 +4617,7 @@ end:
}
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
#endif
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 1e5bd5b5b8c..29cee6da4d3 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -310,16 +310,16 @@ sp_head::operator delete(void *ptr, size_t size)
sp_head::sp_head()
- :Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE),
+ :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
+ m_returns_cs(NULL), m_has_return(FALSE),
m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE)
{
extern byte *
sp_table_key(const byte *ptr, uint *plen, my_bool first);
- extern byte
+ extern byte
*sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
- state= INITIALIZED;
m_backpatch.empty();
m_lex.empty();
hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
@@ -533,17 +533,35 @@ sp_head::destroy()
}
+/*
+ * This is only used for result fields from functions (both during
+ * fix_length_and_dec() and evaluation).
+ *
+ * Since the current mem_root during a will be freed and the result
+ * field will be used by the caller, we have to put it in the caller's
+ * or main mem_root.
+ */
Field *
sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
{
Field *field;
+ MEM_ROOT *tmp_mem_root;
+ THD *thd;
DBUG_ENTER("sp_head::make_field");
+
+ thd= current_thd;
+ tmp_mem_root= thd->mem_root;
+ if (thd->spcont && thd->spcont->callers_mem_root)
+ thd->mem_root= thd->spcont->callers_mem_root;
+ else
+ thd->mem_root= &thd->main_mem_root;
field= ::make_field((char *)0,
!m_returns_len ? max_length : m_returns_len,
(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
(enum Field::geometry_type)0, Field::NONE,
m_returns_typelib,
name ? name : (const char *)m_name.str, dummy);
+ thd->mem_root= tmp_mem_root;
DBUG_RETURN(field);
}
@@ -556,7 +574,7 @@ sp_head::execute(THD *thd)
sp_rcontext *ctx;
int ret= 0;
uint ip= 0;
- Item_arena *old_arena;
+ Query_arena *old_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
LEX *old_lex;
@@ -618,7 +636,21 @@ sp_head::execute(THD *thd)
break;
DBUG_PRINT("execute", ("Instruction %u", ip));
thd->set_time(); // Make current_time() et al work
- ret= i->execute(thd, &ip);
+ {
+ /*
+ We have to substitute free_list of executing statement to
+ current_arena to store there all new items created during execution
+ (for example '*' expanding, or items made during permanent subquery
+ transformation)
+ Note: Every statement have to have all its items listed in free_list
+ for correct cleaning them up
+ */
+ Item *save_free_list= thd->current_arena->free_list;
+ thd->current_arena->free_list= i->free_list;
+ ret= i->execute(thd, &ip);
+ i->free_list= thd->current_arena->free_list;
+ thd->current_arena->free_list= save_free_list;
+ }
if (i->free_list)
cleanup_items(i->free_list);
// Check if an exception has occurred and a handler has been found
@@ -664,6 +696,7 @@ sp_head::execute(THD *thd)
cleanup_items(thd->current_arena->free_list);
thd->current_arena= old_arena;
+ state= EXECUTED;
done:
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
@@ -695,6 +728,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
sp_rcontext *nctx = NULL;
uint i;
int ret;
+ MEM_ROOT *old_mem_root, call_mem_root;
+ Item *old_free_list, *call_free_list;
if (argcount != params)
{
@@ -705,9 +740,16 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
DBUG_RETURN(-1);
}
+ init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+ old_mem_root= thd->mem_root;
+ thd->mem_root= &call_mem_root;
+ old_free_list= thd->free_list; // Keep the old list
+ thd->free_list= NULL; // Start a new one
+
// QQ Should have some error checking here? (types, etc...)
nctx= new sp_rcontext(csize, hmax, cmax);
- for (i= 0 ; i < params && i < argcount ; i++)
+ nctx->callers_mem_root= old_mem_root;
+ for (i= 0 ; i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL);
@@ -735,13 +777,20 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
ret= execute(thd);
+ // Partially restore context now.
+ // We still need the call mem root and free list for processing
+ // of the result.
+ call_free_list= thd->free_list;
+ thd->free_list= old_free_list;
+ thd->mem_root= old_mem_root;
+
if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
/* We need result only in function but not in trigger */
Item *it= nctx->get_result();
if (it)
- *resp= it;
+ *resp= sp_eval_func_item(thd, &it, m_returns, NULL);
else
{
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
@@ -751,6 +800,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
nctx->pop_all_cursors(); // To avoid memory leaks after an error
thd->spcont= octx;
+
+ // Now get rid of the rest of the callee context
+ cleanup_items(call_free_list);
+ free_items(call_free_list);
+ free_root(&call_mem_root, MYF(0));
+
DBUG_RETURN(ret);
}
@@ -780,6 +835,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
+ MEM_ROOT *old_mem_root, call_mem_root;
+ Item *old_free_list, *call_free_list;
if (args->elements != params)
{
@@ -788,6 +845,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
DBUG_RETURN(-1);
}
+ init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+ old_mem_root= thd->mem_root;
+ thd->mem_root= &call_mem_root;
+ old_free_list= thd->free_list; // Keep the old list
+ thd->free_list= NULL; // Start a new one
+
if (csize > 0 || hmax > 0 || cmax > 0)
{
Item_null *nit= NULL; // Re-use this, and only create if needed
@@ -853,9 +916,16 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (! ret)
ret= execute(thd);
+ // Partially restore context now.
+ // We still need the call mem root and free list for processing
+ // of out parameters.
+ call_free_list= thd->free_list;
+ thd->free_list= old_free_list;
+ thd->mem_root= old_mem_root;
+
if (!ret && csize > 0)
{
- List_iterator_fast<Item> li(*args);
+ List_iterator<Item> li(*args);
Item *it;
// Copy back all OUT or INOUT values to the previous frame, or
@@ -867,8 +937,34 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (pvar->mode != sp_param_in)
{
if (it->is_splocal())
- octx->set_item(static_cast<Item_splocal *>(it)->get_offset(),
- nctx->get_item(i));
+ {
+ // Have to copy the item to the caller's mem_root
+ Item *copy;
+ uint offset= static_cast<Item_splocal *>(it)->get_offset();
+ Item *val= nctx->get_item(i);
+ Item *orig= octx->get_item(offset);
+ Item *o_item_next;
+ Item *o_free_list= thd->free_list;
+ LINT_INIT(o_item_next);
+
+ if (orig)
+ o_item_next= orig->next;
+ copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy
+ if (!copy)
+ {
+ ret= -1;
+ break;
+ }
+ if (copy != orig)
+ octx->set_item(offset, copy);
+ if (orig && copy == orig)
+ {
+ // A reused item slot, where the constructor put it in the
+ // free_list, so we have to restore the list.
+ thd->free_list= o_free_list;
+ copy->next= o_item_next;
+ }
+ }
else
{
Item_func_get_user_var *guv= item_is_user_var(it);
@@ -899,6 +995,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
nctx->pop_all_cursors(); // To avoid memory leaks after an error
thd->spcont= octx;
+ // Now get rid of the rest of the callee context
+ cleanup_items(call_free_list);
+ free_items(call_free_list);
+ thd->lex->unit.cleanup();
+ free_root(&call_mem_root, MYF(0));
+
DBUG_RETURN(ret);
}
@@ -1077,7 +1179,7 @@ sp_head::restore_thd_mem_root(THD *thd)
DBUG_ENTER("sp_head::restore_thd_mem_root");
Item *flist= free_list; // The old list
set_item_arena(thd); // Get new free_list and mem_root
- state= INITIALIZED;
+ state= INITIALIZED_FOR_SP;
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
@@ -1355,7 +1457,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
implemented at the same time as ability not to store LEX for
instruction if it is not really used.
*/
- reset_stmt_for_execute(thd, m_lex);
+ reinit_stmt_before_use(thd, m_lex);
/*
If requested check whenever we have access to tables in LEX's table list
@@ -2225,7 +2327,7 @@ sp_head::add_used_tables_to_table_list(THD *thd,
TABLE_LIST ***query_tables_last_ptr)
{
uint i;
- Item_arena *arena, backup;
+ Query_arena *arena, backup;
bool result= FALSE;
DBUG_ENTER("sp_head::add_used_tables_to_table_list");
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 49eabce246b..2c75a320f30 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -74,11 +74,12 @@ sp_name *
sp_name_current_db_new(THD *thd, LEX_STRING name);
-class sp_head :private Item_arena
+class sp_head :private Query_arena
{
sp_head(const sp_head &); /* Prevent use of these */
void operator=(sp_head &);
+ MEM_ROOT main_mem_root;
public:
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
@@ -377,6 +378,10 @@ public:
return (uint)m_lex->sql_command;
}
+ void disable_query_cache()
+ {
+ m_lex->safe_to_cache_query= 0;
+ }
private:
LEX *m_lex;
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 6f2165539d7..aacb9254753 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -32,6 +32,7 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
m_hfound(-1), m_ccount(0)
{
+ callers_mem_root= NULL;
in_handler= FALSE;
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
@@ -168,6 +169,17 @@ sp_rcontext::pop_cursors(uint count)
*
*/
+sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper)
+ :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
+{
+ /*
+ currsor can't be stored in QC, so we should prevent opening QC for
+ try to write results which are absent.
+ */
+ lex_keeper->disable_query_cache();
+}
+
+
/*
pre_open cursor
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index ba5fa950dc3..b188805435f 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -47,6 +47,7 @@ class sp_rcontext : public Sql_alloc
public:
+ MEM_ROOT *callers_mem_root; // Used to store result fields
bool in_handler;
sp_rcontext(uint fsize, uint hmax, uint cmax);
@@ -202,11 +203,7 @@ class sp_cursor : public Sql_alloc
{
public:
- sp_cursor(sp_lex_keeper *lex_keeper)
- : m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
- {
- /* Empty */
- }
+ sp_cursor(sp_lex_keeper *lex_keeper);
virtual ~sp_cursor()
{
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 28b841435c8..5e2df88f91e 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -187,7 +187,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
ACL_HOST host;
update_hostname(&host.host,get_field(&mem, table->field[0]));
host.db= get_field(&mem, table->field[1]);
- if (lower_case_table_names)
+ if (lower_case_table_names && host.db)
{
/*
convert db to lower case and give a warning if the db wasn't
@@ -209,7 +209,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
sql_print_warning("'host' entry '%s|%s' "
"ignored in --skip-name-resolve mode.",
- host.host.hostname, host.db, host.host.hostname);
+ host.host.hostname, host.db?host.db:"");
continue;
}
#ifndef TO_BE_REMOVED
@@ -277,7 +277,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
sql_print_warning("'user' entry '%s@%s' "
"ignored in --skip-name-resolve mode.",
- user.user, user.host.hostname, user.host.hostname);
+ user.user, user.host.hostname);
continue;
}
@@ -413,7 +413,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
sql_print_warning("'db' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- db.db, db.user, db.host.hostname, db.host.hostname);
+ db.db, db.user, db.host.hostname);
continue;
}
db.access=get_access(table,3);
@@ -3232,7 +3232,7 @@ my_bool grant_init(THD *org_thd)
sql_print_warning("'procs_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
mem_check->tname, mem_check->user,
- mem_check->host, mem_check->host);
+ mem_check->host);
continue;
}
}
@@ -5172,7 +5172,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
grant_proc->db,
grant_proc->tname,
is_proc,
- ~0, 1))
+ ~(ulong)0, 1))
{
revoked= 1;
continue;
@@ -5240,7 +5240,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
lex_user.host.length= strlen(grant_proc->host.hostname);
if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
grant_proc->db, grant_proc->tname,
- is_proc, ~0, 1))
+ is_proc, ~(ulong)0, 1))
{
revoked= 1;
continue;
@@ -5325,7 +5325,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
Instantiate used templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator<LEX_COLUMN>;
template class List_iterator<LEX_USER>;
template class List<LEX_COLUMN>;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1d49b47761b..b112ca971c3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
TABLE_LIST *table_desc, MEM_ROOT *mem_root);
-static void relink_tables_for_multidelete(THD *thd);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
@@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
(thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(TRUE); /* purecov: inspected */
- relink_tables_for_multidelete(thd);
DBUG_RETURN(0);
}
@@ -2119,37 +2117,11 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
if (open_tables(thd, &tables, &counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); /* purecov: inspected */
- relink_tables_for_multidelete(thd); // Not really needed, but
DBUG_RETURN(0);
}
/*
- Let us propagate pointers to open tables from global table list
- to table lists for multi-delete
-*/
-
-static void relink_tables_for_multidelete(THD *thd)
-{
- if (thd->lex->all_selects_list->next_select_in_list())
- {
- for (SELECT_LEX *sl= thd->lex->all_selects_list;
- sl;
- sl= sl->next_select_in_list())
- {
- for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
- cursor;
- cursor=cursor->next_local)
- {
- if (cursor->correspondent_table)
- cursor->table= cursor->correspondent_table->table;
- }
- }
- }
-}
-
-
-/*
Mark all real tables in the list as free for reuse.
SYNOPSIS
@@ -2656,7 +2628,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
uint length=(uint) strlen(name);
char name_buff[NAME_LEN+1];
-
if (item->cached_table)
{
/*
@@ -2723,10 +2694,13 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
db= name_buff;
}
+ bool search_global= item->item_flags & MY_ITEM_PREFER_1ST_TABLE;
if (table_name && table_name[0])
{ /* Qualified field */
- bool found_table=0;
- for (; tables; tables= tables->next_local)
+ bool found_table=0;
+ uint table_idx= 0;
+ for (; tables; tables= search_global?tables->next_global:tables->next_local,
+ table_idx++)
{
/* TODO; Ensure that db and tables->db always points to something ! */
if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
@@ -2762,6 +2736,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) 0;
}
found=find;
+ if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE)
+ break;
}
}
}
@@ -2786,9 +2762,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) not_found_field;
return (Field*) 0;
}
-
bool allow_rowid= tables && !tables->next_local; // Only one table
- for (; tables ; tables= tables->next_local)
+ uint table_idx= 0;
+ for (; tables ; tables= search_global?tables->next_global:tables->next_local,
+ table_idx++)
{
if (!tables->table && !tables->ancestor)
{
@@ -2823,7 +2800,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
return (Field*) 0;
}
- found=field;
+ found= field;
+ if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE)
+ break;
}
}
if (found)
@@ -3050,7 +3029,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
Item *item;
List_iterator<Item> it(fields);
- Item_arena *arena, backup;
+ Query_arena *arena, backup;
DBUG_ENTER("setup_wild");
/*
@@ -3081,7 +3060,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
else if (insert_fields(thd,tables,((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it,
- any_privileges, arena != 0))
+ any_privileges))
{
if (arena)
thd->restore_backup_item_arena(arena, &backup);
@@ -3334,8 +3313,6 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
any_privileges 0 If we should ensure that we have SELECT privileges
for all columns
1 If any privilege is ok
- allocate_view_names if true view names will be copied to current Item_arena
- memory (made for SP/PS)
RETURN
0 ok
'it' is updated to point at last inserted
@@ -3345,7 +3322,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
bool
insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
const char *table_name, List_iterator<Item> *it,
- bool any_privileges, bool allocate_view_names)
+ bool any_privileges)
{
/* allocate variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
@@ -3536,25 +3513,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
field->query_id=thd->query_id;
table->used_keys.intersect(field->part_of_key);
}
- else if (allocate_view_names &&
- thd->lex->current_select->first_execution)
- {
- Item_field *item;
- if (alias_used)
- item= new Item_field(0,
- thd->strdup(tables->alias),
- thd->strdup(field_name));
- else
- item= new Item_field(thd->strdup(tables->view_db.str),
- thd->strdup(tables->view_name.str),
- thd->strdup(field_name));
- /*
- during cleunup() this item will be put in list to replace
- expression from VIEW
- */
- thd->nocheck_register_item_tree_change(it->ref(), item,
- thd->mem_root);
- }
}
/*
All fields are used in case if usual tables (in case of view used
@@ -3594,7 +3552,7 @@ err:
int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
{
SELECT_LEX *select_lex= thd->lex->current_select;
- Item_arena *arena= thd->current_arena, backup;
+ Query_arena *arena= thd->current_arena, backup;
bool save_wrapper= thd->lex->current_select->no_wrap_view_item;
TABLE_LIST *table= NULL; // For HP compilers
DBUG_ENTER("setup_conds");
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 438bfdbcb73..8abd7cbbe7d 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -49,7 +49,7 @@ char internal_table_name[2]= "*";
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/* Used templates */
template class List<Key>;
template class List_iterator<Key>;
@@ -156,9 +156,15 @@ bool foreign_key_prefix(Key *a, Key *b)
/****************************************************************************
** Thread specific functions
****************************************************************************/
+/*
+ Pass nominal parameters to Statement constructor only to ensure that
+ the destructor works OK in case of error. The main_mem_root will be
+ re-initialized in init().
+*/
THD::THD()
- :user_time(0), global_read_lock(0), is_fatal_error(0),
+ :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
+ user_time(0), global_read_lock(0), is_fatal_error(0),
rand_used(0), time_zone_used(0),
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE),
@@ -420,8 +426,6 @@ THD::~THD()
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
- /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */
- clear_alloc_root(&stmt_backup.main_mem_root);
DBUG_VOID_RETURN;
}
@@ -714,8 +718,10 @@ int THD::send_explain_fields(select_result *result)
CHARSET_INFO *cs= system_charset_info;
field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
field_list.push_back(new Item_empty_string("select_type", 19, cs));
- field_list.push_back(new Item_empty_string("table", NAME_LEN, cs));
- field_list.push_back(new Item_empty_string("type", 10, cs));
+ field_list.push_back(item= new Item_empty_string("table", NAME_LEN, cs));
+ item->maybe_null= 1;
+ field_list.push_back(item= new Item_empty_string("type", 10, cs));
+ item->maybe_null= 1;
field_list.push_back(item=new Item_empty_string("possible_keys",
NAME_LEN*MAX_KEY, cs));
item->maybe_null=1;
@@ -727,7 +733,9 @@ int THD::send_explain_fields(select_result *result)
field_list.push_back(item=new Item_empty_string("ref",
NAME_LEN*MAX_REF_PARTS, cs));
item->maybe_null=1;
- field_list.push_back(new Item_return_int("rows", 10, MYSQL_TYPE_LONGLONG));
+ field_list.push_back(item= new Item_return_int("rows", 10,
+ MYSQL_TYPE_LONGLONG));
+ item->maybe_null= 1;
field_list.push_back(new Item_empty_string("Extra", 255, cs));
return (result->send_fields(field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
@@ -1470,53 +1478,7 @@ void select_dumpvar::cleanup()
}
-/*
- Create arena for already constructed THD.
-
- SYNOPSYS
- Item_arena()
- thd - thread for which arena is created
-
- DESCRIPTION
- Create arena for already existing THD using its variables as parameters
- for memory root initialization.
-*/
-Item_arena::Item_arena(THD* thd)
- :free_list(0), mem_root(&main_mem_root),
- state(INITIALIZED)
-{
- init_sql_alloc(&main_mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
-}
-
-
-/*
- Create arena and optionally initialize memory root.
-
- SYNOPSYS
- Item_arena()
- init_mem_root - whenever we need to initialize memory root
-
- DESCRIPTION
- Create arena and optionally initialize memory root with minimal
- possible parameters.
-
- NOTE
- We use this constructor when arena is part of THD, but reinitialize
- its memory root in THD::init_for_queries() before execution of real
- statements.
-*/
-Item_arena::Item_arena(bool init_mem_root)
- :free_list(0), mem_root(&main_mem_root),
- state(CONVENTIONAL_EXECUTION)
-{
- if (init_mem_root)
- init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
-}
-
-
-Item_arena::Type Item_arena::type() const
+Query_arena::Type Query_arena::type() const
{
DBUG_ASSERT(0); /* Should never be called */
return STATEMENT;
@@ -1527,9 +1489,10 @@ Item_arena::Type Item_arena::type() const
Statement functions
*/
-Statement::Statement(THD *thd)
- :Item_arena(thd),
- id(++thd->statement_id_counter),
+Statement::Statement(enum enum_state state_arg, ulong id_arg,
+ ulong alloc_block_size, ulong prealloc_size)
+ :Query_arena(&main_mem_root, state_arg),
+ id(id_arg),
set_query_id(1),
allow_sum_func(0),
lex(&main_lex),
@@ -1538,28 +1501,11 @@ Statement::Statement(THD *thd)
cursor(0)
{
name.str= NULL;
+ init_sql_alloc(&main_mem_root, alloc_block_size, prealloc_size);
}
-/*
- This constructor is called when statement is a subobject of THD:
- Some variables are initialized in THD::init due to locking problems
- This statement object will be used to
-*/
-Statement::Statement()
- :Item_arena((bool)TRUE),
- id(0),
- set_query_id(1),
- allow_sum_func(0), /* initialized later */
- lex(&main_lex),
- query(0), /* these two are set */
- query_length(0), /* in alloc_query() */
- cursor(0)
-{
-}
-
-
-Item_arena::Type Statement::type() const
+Query_arena::Type Statement::type() const
{
return STATEMENT;
}
@@ -1607,9 +1553,9 @@ void THD::end_statement()
}
-void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
+void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup)
{
- DBUG_ENTER("Item_arena::set_n_backup_item_arena");
+ DBUG_ENTER("Query_arena::set_n_backup_item_arena");
DBUG_ASSERT(backup_arena == 0);
backup->set_item_arena(this);
set_item_arena(set);
@@ -1620,28 +1566,18 @@ void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
}
-void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
+void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup)
{
- DBUG_ENTER("Item_arena::restore_backup_item_arena");
+ DBUG_ENTER("Query_arena::restore_backup_item_arena");
set->set_item_arena(this);
set_item_arena(backup);
#ifndef DBUG_OFF
backup_arena= 0;
#endif
-#ifdef NOT_NEEDED_NOW
- /*
- Reset backup mem_root to avoid its freeing.
- Since Item_arena's mem_root is freed only when it is part of Statement
- we need this only if we use some Statement's arena as backup storage.
- But we do this only with THD::stmt_backup and this Statement is specially
- handled in this respect. So this code is not really needed now.
- */
- clear_alloc_root(&backup->mem_root);
-#endif
DBUG_VOID_RETURN;
}
-void Item_arena::set_item_arena(Item_arena *set)
+void Query_arena::set_item_arena(Query_arena *set)
{
mem_root= set->mem_root;
free_list= set->free_list;
@@ -1650,6 +1586,11 @@ void Item_arena::set_item_arena(Item_arena *set)
Statement::~Statement()
{
+ /*
+ We must free `main_mem_root', not `mem_root' (pointer), to work
+ correctly if this statement is used as a backup statement,
+ for which `mem_root' may point to some other statement.
+ */
free_root(&main_mem_root, MYF(0));
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index c258380cd3d..fbc5e5f85bf 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -632,6 +632,13 @@ typedef struct system_status_var
ulong filesort_range_count;
ulong filesort_rows;
ulong filesort_scan_count;
+ /* Ppepared statements and binary protocol */
+ ulong com_stmt_prepare;
+ ulong com_stmt_execute;
+ ulong com_stmt_send_long_data;
+ ulong com_stmt_fetch;
+ ulong com_stmt_reset;
+ ulong com_stmt_close;
double last_query_cost;
} STATUS_VAR;
@@ -641,13 +648,13 @@ typedef struct system_status_var
variable in system_status_var
*/
-#define last_system_status_var filesort_scan_count
+#define last_system_status_var com_stmt_close
void free_tmp_table(THD *thd, TABLE *entry);
-class Item_arena
+class Query_arena
{
public:
/*
@@ -655,17 +662,16 @@ public:
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
- MEM_ROOT main_mem_root;
MEM_ROOT *mem_root; // Pointer to current memroot
#ifndef DBUG_OFF
bool backup_arena;
#endif
- enum enum_state
+ enum enum_state
{
- INITIALIZED= 0, PREPARED= 1, EXECUTED= 3, CONVENTIONAL_EXECUTION= 2,
- ERROR= -1
+ INITIALIZED= 0, INITIALIZED_FOR_SP= 1, PREPARED= 2,
+ CONVENTIONAL_EXECUTION= 3, EXECUTED= 4, ERROR= -1
};
-
+
enum_state state;
/* We build without RTTI, so dynamic_cast can't be used. */
@@ -674,24 +680,20 @@ public:
STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
};
+ Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) :
+ free_list(0), mem_root(mem_root_arg), state(state_arg)
+ {}
/*
- This constructor is used only when Item_arena is created as
- backup storage for another instance of Item_arena.
- */
- Item_arena() {};
- /*
- Create arena for already constructed THD using its variables as
- parameters for memory root initialization.
- */
- Item_arena(THD *thd);
- /*
- Create arena and optionally init memory root with minimal values.
- Particularly used if Item_arena is part of Statement.
+ This constructor is used only when Query_arena is created as
+ backup storage for another instance of Query_arena.
*/
- Item_arena(bool init_mem_root);
+ Query_arena() {};
virtual Type type() const;
- virtual ~Item_arena() {};
+ virtual ~Query_arena() {};
+ inline bool is_stmt_prepare() const { return state == INITIALIZED; }
+ inline bool is_first_sp_execute() const
+ { return state == INITIALIZED_FOR_SP; }
inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
@@ -699,6 +701,7 @@ public:
{ return state == PREPARED || state == EXECUTED; }
inline bool is_conventional() const
{ return state == CONVENTIONAL_EXECUTION; }
+
inline gptr alloc(unsigned int size) { return alloc_root(mem_root,size); }
inline gptr calloc(unsigned int size)
{
@@ -721,9 +724,9 @@ public:
return ptr;
}
- void set_n_backup_item_arena(Item_arena *set, Item_arena *backup);
- void restore_backup_item_arena(Item_arena *set, Item_arena *backup);
- void set_item_arena(Item_arena *set);
+ void set_n_backup_item_arena(Query_arena *set, Query_arena *backup);
+ void restore_backup_item_arena(Query_arena *set, Query_arena *backup);
+ void set_item_arena(Query_arena *set);
};
@@ -743,12 +746,13 @@ class Cursor;
be used explicitly.
*/
-class Statement: public Item_arena
+class Statement: public Query_arena
{
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
public:
- /* FIXME: must be private */
+ /* FIXME: these must be protected */
+ MEM_ROOT main_mem_root;
LEX main_lex;
/*
@@ -813,13 +817,11 @@ public:
public:
- /*
- This constructor is called when statement is a subobject of THD:
- some variables are initialized in THD::init due to locking problems
- */
- Statement();
+ /* This constructor is called for backup statements */
+ Statement() { clear_alloc_root(&main_mem_root); }
- Statement(THD *thd);
+ Statement(enum enum_state state_arg, ulong id_arg,
+ ulong alloc_block_size, ulong prealloc_size);
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
@@ -962,11 +964,6 @@ public:
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
/*
- keeps THD state while it is used for active statement
- Note: we perform special cleanup for it in THD destructor.
- */
- Statement stmt_backup;
- /*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
*/
@@ -1046,7 +1043,7 @@ public:
#endif
struct st_my_thread_var *mysys_var;
/*
- Type of current query: COM_PREPARE, COM_QUERY, etc. Set from
+ Type of current query: COM_STMT_PREPARE, COM_QUERY, etc. Set from
first byte of the packet in do_command()
*/
enum enum_server_command command;
@@ -1114,9 +1111,9 @@ public:
Item_change_list change_list;
/*
- Current prepared Item_arena if there one, or 0
+ Current prepared Query_arena if there one, or 0
*/
- Item_arena *current_arena;
+ Query_arena *current_arena;
/*
next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc
@@ -1193,7 +1190,7 @@ public:
bool query_error, bootstrap, cleanup_done;
bool tmp_table_used;
bool charset_is_system_charset, charset_is_collation_connection;
- bool slow_command;
+ bool enable_slow_log; /* enable slow log for current statement */
bool no_trans_update, abort_on_warning;
bool got_warning; /* Set on call to push_warning() */
bool no_warnings_for_error; /* no warnings on call to my_error() */
@@ -1338,13 +1335,9 @@ public:
return 0;
#endif
}
- inline bool only_prepare()
- {
- return command == COM_PREPARE;
- }
inline bool fill_derived_tables()
{
- return !only_prepare() && !lex->only_view_structure();
+ return !current_arena->is_stmt_prepare() && !lex->only_view_structure();
}
inline gptr trans_alloc(unsigned int size)
{
@@ -1377,20 +1370,20 @@ public:
inline void fatal_error()
{
is_fatal_error= 1;
- net.report_error= 1;
+ net.report_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
- inline Item_arena *change_arena_if_needed(Item_arena *backup)
+ inline Query_arena *change_arena_if_needed(Query_arena *backup)
{
/*
use new arena if we are in a prepared statements and we have not
already changed to use this arena.
*/
if (!current_arena->is_conventional() &&
- mem_root != &current_arena->main_mem_root)
+ mem_root != current_arena->mem_root)
{
set_n_backup_item_arena(current_arena, backup);
return current_arena;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 7ad490599db..e6f980859ab 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -808,7 +808,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
if (!dont_send_ok)
{
db_type table_type;
- if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN)
+ if ((table_type=get_table_type(thd, path)) == DB_TYPE_UNKNOWN)
{
my_error(ER_NO_SUCH_TABLE, MYF(0),
table_list->db, table_list->table_name);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 2ae293c1bff..e1d701936cf 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -217,6 +217,8 @@ exit:
queries defined. After temporary table is filled, if this is not EXPLAIN,
then the entire unit / node is deleted. unit is deleted if UNION is used
for derived table and node is deleted is it is a simple SELECT.
+ If you use this function, make sure it's not called at prepare.
+ Due to evaluation of LIMIT clause it can not be used at prepared stage.
RETURN
0 ok
@@ -245,11 +247,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
}
else
{
- unit->offset_limit_cnt= first_select->offset_limit;
- unit->select_limit_cnt= first_select->select_limit+
- first_select->offset_limit;
- if (unit->select_limit_cnt < first_select->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR;
+ unit->set_limit(first_select);
if (unit->select_limit_cnt == HA_POS_ERROR)
first_select->options&= ~OPTION_FOUND_ROWS;
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 293b695d199..8a12339ccee 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -225,21 +225,21 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
MYSQL_ERROR *err;
SELECT_LEX *sel= &thd->lex->select_lex;
- ha_rows offset= sel->offset_limit, limit= sel->select_limit;
+ SELECT_LEX_UNIT *unit= &thd->lex->unit;
+ ha_rows idx= 0;
Protocol *protocol=thd->protocol;
-
+
+ unit->set_limit(sel);
+
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
while ((err= it++))
{
/* Skip levels that the user is not interested in */
if (!(levels_to_show & ((ulong) 1 << err->level)))
continue;
- if (offset)
- {
- offset--;
+ if (++idx <= unit->offset_limit_cnt)
continue;
- }
- if (limit-- == 0)
+ if (idx > unit->select_limit_cnt)
break;
protocol->prepare_for_resend();
protocol->store(warning_level_names[err->level],
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 1aa034ce61c..e905f93b860 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -321,8 +321,8 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
key_expr
ha_rkey_mode
cond
- select_limit
- offset_limit
+ select_limit_cnt
+ offset_limit_cnt
RETURN
FALSE ok
@@ -333,7 +333,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
enum enum_ha_read_modes mode, char *keyname,
List<Item> *key_expr,
enum ha_rkey_function ha_rkey_mode, Item *cond,
- ha_rows select_limit,ha_rows offset_limit)
+ ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
{
TABLE_LIST *hash_tables;
TABLE *table;
@@ -413,8 +413,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
goto err0;
- table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
-
if (keyname)
{
if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0)
@@ -422,14 +420,11 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias);
goto err0;
}
- table->file->ha_index_or_rnd_end();
- table->file->ha_index_init(keyno);
}
- if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0))
+ if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0))
goto err0;
- select_limit+=offset_limit;
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
HANDLER_TABLES_HACK(thd);
@@ -447,12 +442,25 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
table->file->init_table_handle_for_HANDLER();
- for (num_rows=0; num_rows < select_limit; )
+ for (num_rows=0; num_rows < select_limit_cnt; )
{
switch (mode) {
+ case RNEXT:
+ if (table->file->inited != handler::NONE)
+ {
+ error=keyname ?
+ table->file->index_next(table->record[0]) :
+ table->file->rnd_next(table->record[0]);
+ break;
+ }
+ /* else fall through */
case RFIRST:
if (keyname)
+ {
+ table->file->ha_index_or_rnd_end();
+ table->file->ha_index_init(keyno);
error= table->file->index_first(table->record[0]);
+ }
else
{
table->file->ha_index_or_rnd_end();
@@ -461,20 +469,21 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
mode=RNEXT;
break;
+ case RPREV:
+ DBUG_ASSERT(keyname != 0);
+ if (table->file->inited != handler::NONE)
+ {
+ error=table->file->index_prev(table->record[0]);
+ break;
+ }
+ /* else fall through */
case RLAST:
DBUG_ASSERT(keyname != 0);
+ table->file->ha_index_or_rnd_end();
+ table->file->ha_index_init(keyno);
error= table->file->index_last(table->record[0]);
mode=RPREV;
break;
- case RNEXT:
- error= (keyname ?
- table->file->index_next(table->record[0]) :
- table->file->rnd_next(table->record[0]));
- break;
- case RPREV:
- DBUG_ASSERT(keyname != 0);
- error= table->file->index_prev(table->record[0]);
- break;
case RNEXT_SAME:
/* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */
DBUG_ASSERT(keyname != 0);
@@ -509,6 +518,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
goto err;
+ table->file->ha_index_or_rnd_end();
+ table->file->ha_index_init(keyno);
key_copy(key, table->record[0], table->key_info + keyno, key_len);
error= table->file->index_read(table->record[0],
key,key_len,ha_rkey_mode);
@@ -535,7 +546,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
if (cond && !cond->val_int())
continue;
- if (num_rows >= offset_limit)
+ if (num_rows >= offset_limit_cnt)
{
Item *item;
protocol->prepare_for_resend();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c3c51afc03b..b1bb7c7e14b 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2001,10 +2001,22 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
int
select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
+ int res;
+ LEX *lex= thd->lex;
+ SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
unit= u;
- if (check_insert_fields(thd, table_list, *fields, values, !insert_into_view))
+ /*
+ Since table in which we are going to insert is added to the first
+ select, LEX::current_select should point to the first select while
+ we are fixing fields from insert list.
+ */
+ lex->current_select= &lex->select_lex;
+ res= check_insert_fields(thd, table_list, *fields, values,
+ !insert_into_view);
+ lex->current_select= lex_current_select_save;
+ if (res)
DBUG_RETURN(1);
/*
if it is INSERT into join view then check_insert_fields already found
@@ -2016,12 +2028,12 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
Is table which we are changing used somewhere in other parts of
query
*/
- if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) &&
+ if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
unique_table(table_list, table_list->next_global))
{
/* Using same table for INSERT and SELECT */
- thd->lex->current_select->options|= OPTION_BUFFER_RESULT;
- thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
+ lex->current_select->options|= OPTION_BUFFER_RESULT;
+ lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
}
else
{
@@ -2120,9 +2132,12 @@ bool select_insert::send_data(List<Item> &values)
}
if (!(error= write_record(thd, table, &info)))
{
- if (table->triggers)
+ if (table->triggers || info.handle_duplicates == DUP_UPDATE)
{
/*
+ Restore fields of the record since it is possible that they were
+ changed by ON DUPLICATE KEY UPDATE clause.
+
If triggers exist then whey can modify some fields which were not
originally touched by INSERT ... SELECT, so we have to restore
their original values for the next row.
@@ -2375,11 +2390,11 @@ void select_create::abort()
Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator_fast<List_item>;
#ifndef EMBEDDED_LIBRARY
template class I_List<delayed_insert>;
template class I_List_iterator<delayed_insert>;
template class I_List<delayed_row>;
#endif /* EMBEDDED_LIBRARY */
-#endif /* __GNUC__ */
+#endif /* HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index eb33fda02f7..08f0c3badf7 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -135,7 +135,6 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
lex->select_lex.options= 0;
- lex->select_lex.options2= 0;
lex->select_lex.init_order();
lex->select_lex.group_list.empty();
lex->describe= 0;
@@ -968,7 +967,7 @@ int yylex(void *arg, void *yythd)
{
THD* thd= (THD*)yythd;
if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) &&
- (thd->command != COM_PREPARE))
+ (thd->command != COM_STMT_PREPARE))
{
lex->safe_to_cache_query= 0;
lex->found_semicolon=(char*) lex->ptr;
@@ -1065,7 +1064,6 @@ int yylex(void *arg, void *yythd)
void st_select_lex_node::init_query()
{
options= 0;
- options2= 0;
linkage= UNSPECIFIED_TYPE;
no_error= no_table_names_allowed= 0;
uncacheable= 0;
@@ -1129,7 +1127,6 @@ void st_select_lex::init_select()
table_join_options= 0;
in_sum_expr= with_wild= 0;
options= 0;
- options2= 0;
braces= 0;
when_list.empty();
expr_list.empty();
@@ -1141,8 +1138,9 @@ void st_select_lex::init_select()
order_list.elements= 0;
order_list.first= 0;
order_list.next= (byte**) &order_list.first;
- select_limit= HA_POS_ERROR;
- offset_limit= 0;
+ /* Set limit and offset to default values */
+ select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
+ offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
}
@@ -1366,7 +1364,7 @@ ulong st_select_lex_node::get_table_join_options()
*/
bool st_select_lex::test_limit()
{
- if (select_limit != HA_POS_ERROR)
+ if (select_limit != 0)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
@@ -1486,8 +1484,8 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
We have to create array in prepared statement memory if it is
prepared statement
*/
- Item_arena *arena= thd->current_arena;
- return (ref_pointer_array=
+ Query_arena *arena= thd->current_arena;
+ return (ref_pointer_array=
(Item **)arena->alloc(sizeof(Item*) *
(item_list.elements +
select_n_having_items +
@@ -1554,24 +1552,20 @@ void st_select_lex::print_limit(THD *thd, String *str)
item->substype() == Item_subselect::IN_SUBS ||
item->substype() == Item_subselect::ALL_SUBS))
{
- DBUG_ASSERT(!item->fixed || select_limit == 1L && offset_limit == 0L);
+ DBUG_ASSERT(!item->fixed ||
+ select_limit->val_int() == LL(1) && offset_limit == 0);
return;
}
if (explicit_limit)
{
str->append(" limit ", 7);
- char buff[20];
- // latin1 is good enough for numbers
- String st(buff, sizeof(buff), &my_charset_latin1);
- st.set((ulonglong)select_limit, &my_charset_latin1);
- str->append(st);
if (offset_limit)
{
+ offset_limit->print(str);
str->append(',');
- st.set((ulonglong)select_limit, &my_charset_latin1);
- str->append(st);
}
+ select_limit->print(str);
}
}
@@ -1622,7 +1616,7 @@ bool st_lex::can_be_merged()
select_lex.with_sum_func == 0 &&
select_lex.table_list.elements >= 1 &&
!(select_lex.options & SELECT_DISTINCT) &&
- select_lex.select_limit == HA_POS_ERROR);
+ select_lex.select_limit == 0);
}
@@ -1759,11 +1753,16 @@ bool st_lex::need_correct_ident()
values - SELECT_LEX with initial values for counters
*/
-void st_select_lex_unit::set_limit(SELECT_LEX *values)
+void st_select_lex_unit::set_limit(SELECT_LEX *sl)
{
- offset_limit_cnt= values->offset_limit;
- select_limit_cnt= values->select_limit+values->offset_limit;
- if (select_limit_cnt < values->select_limit)
+ ulonglong select_limit_val;
+
+ DBUG_ASSERT(! thd->current_arena->is_stmt_prepare());
+ select_limit_val= sl->select_limit ? sl->select_limit->val_uint() :
+ HA_POS_ERROR;
+ offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0);
+ select_limit_cnt= select_limit_val + offset_limit_cnt;
+ if (select_limit_cnt < select_limit_val)
select_limit_cnt= HA_POS_ERROR; // no limit
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9dd37c65cde..86539dd8c5e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -114,6 +114,14 @@ enum enum_sp_data_access
SP_MODIFIES_SQL_DATA
};
+const LEX_STRING sp_data_access_name[]=
+{
+ { (char*) STRING_WITH_LEN("") },
+ { (char*) STRING_WITH_LEN("CONTAINS SQL") },
+ { (char*) STRING_WITH_LEN("NO SQL") },
+ { (char*) STRING_WITH_LEN("READS SQL DATA") },
+ { (char*) STRING_WITH_LEN("MODIFIES SQL DATA") }
+};
#define DERIVED_SUBQUERY 1
#define DERIVED_VIEW 2
@@ -297,13 +305,13 @@ protected:
public:
uint32 options;
- uint32 options2;
/*
result of this query can't be cached, bit field, can be :
UNCACHEABLE_DEPENDENT
UNCACHEABLE_RAND
UNCACHEABLE_SIDEEFFECT
UNCACHEABLE_EXPLAIN
+ UNCACHEABLE_PREPARE
*/
uint8 uncacheable;
enum sub_select_type linkage;
@@ -489,7 +497,7 @@ public:
List<List_item> expr_list;
List<List_item> when_list; /* WHEN clause (expression) */
SQL_LIST *gorder_list;
- ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
+ Item *select_limit, *offset_limit; /* LIMIT clause parameters */
// Arrays of pointers to top elements of all_fields list
Item **ref_pointer_array;
@@ -522,7 +530,19 @@ public:
query processing end even if we use temporary table
*/
bool subquery_in_having;
- bool first_execution; /* first execution in SP or PS */
+ /*
+ This variable is required to ensure proper work of subqueries and
+ stored procedures. Generally, one should use the states of
+ Query_arena to determine if it's a statement prepare or first
+ execution of a stored procedure. However, in case when there was an
+ error during the first execution of a stored procedure, the SP body
+ is not expelled from the SP cache. Therefore, a deeply nested
+ subquery might be left unoptimized. So we need this per-subquery
+ variable to inidicate the optimization/execution state of every
+ subquery. Prepared statements work OK in that regard, as in
+ case of an error during prepare the PS is not created.
+ */
+ bool first_execution;
bool first_cond_optimization;
/* do not wrap view fields with Item_ref */
bool no_wrap_view_item;
@@ -751,7 +771,12 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt;
- uint table_count; /* used when usual update transformed in multiupdate */
+ /*
+ In LEX representing update which were transformed to multi-update
+ stores total number of tables. For LEX representing multi-delete
+ holds number of tables from which we will delete records.
+ */
+ uint table_count;
uint8 describe;
uint8 derived_tables;
uint8 create_view_algorithm;
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 9346f3df305..56b4b765355 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -138,7 +138,7 @@ void unmap_file(mapped_files *map)
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/* Used templates */
template class I_List<mapped_files>;
template class I_List_iterator<mapped_files>;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f4ecb9c9ceb..788d12cb898 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -72,7 +72,6 @@ static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
-static void log_slow_query(THD *thd);
const char *any_db="*any*"; // Special symbol for check_access
@@ -1512,10 +1511,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->command=command;
/*
- Commands which will always take a long time should be marked with
- this so that they will not get logged to the slow query log
+ Commands which always take a long time are logged into
+ the slow log only if opt_log_slow_admin_statements is set.
*/
- thd->slow_command=FALSE;
+ thd->enable_slow_log= TRUE;
thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -1555,7 +1554,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint tbl_len= *(uchar*) (packet + db_len + 1);
statistic_increment(thd->status_var.com_other, &LOCK_status);
- thd->slow_command= TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
db= thd->alloc(db_len + tbl_len + 2);
tbl_name= strmake(db, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
@@ -1639,32 +1638,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
break;
}
- case COM_EXECUTE:
+ case COM_STMT_EXECUTE:
{
mysql_stmt_execute(thd, packet, packet_length);
break;
}
- case COM_FETCH:
+ case COM_STMT_FETCH:
{
mysql_stmt_fetch(thd, packet, packet_length);
break;
}
- case COM_LONG_DATA:
+ case COM_STMT_SEND_LONG_DATA:
{
mysql_stmt_get_longdata(thd, packet, packet_length);
break;
}
- case COM_PREPARE:
+ case COM_STMT_PREPARE:
{
mysql_stmt_prepare(thd, packet, packet_length, 0);
break;
}
- case COM_CLOSE_STMT:
+ case COM_STMT_CLOSE:
{
- mysql_stmt_free(thd, packet);
+ mysql_stmt_close(thd, packet);
break;
}
- case COM_RESET_STMT:
+ case COM_STMT_RESET:
{
mysql_stmt_reset(thd, packet);
break;
@@ -1693,7 +1692,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
ulong length= (ulong)(packet_end-packet);
- log_slow_query(thd);
+ log_slow_statement(thd);
/* Remove garbage at start of query */
while (my_isspace(thd->charset(), *packet) && length > 0)
@@ -1862,7 +1861,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint32 slave_server_id;
statistic_increment(thd->status_var.com_other,&LOCK_status);
- thd->slow_command = TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -2047,7 +2046,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->net.report_error)
net_send_error(thd);
- log_slow_query(thd);
+ log_slow_statement(thd);
thd->proc_info="cleaning up";
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
@@ -2063,13 +2062,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
-static void log_slow_query(THD *thd)
+void log_slow_statement(THD *thd)
{
time_t start_of_query=thd->start_time;
thd->end_time(); // Set start time
- /* If not reading from backup and if the query took too long */
- if (!thd->slow_command && !thd->user_time) // do not log 'slow_command' queries
+ /*
+ Do not log administrative statements unless the appropriate option is
+ set; do not log into slow log if reading from backup.
+ */
+ if (thd->enable_slow_log && !thd->user_time)
{
thd->proc_info="logging slow query";
@@ -2201,7 +2203,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/*
Read query from packet and store in thd->query
- Used in COM_QUERY and COM_PREPARE
+ Used in COM_QUERY and COM_STMT_PREPARE
DESCRIPTION
Sets the following THD variables:
@@ -2378,7 +2380,8 @@ mysql_execute_command(THD *thd)
{
SELECT_LEX *param= lex->unit.global_parameters;
if (!param->explicit_limit)
- param->select_limit= thd->variables.select_limit;
+ param->select_limit=
+ new Item_int((ulonglong)thd->variables.select_limit);
}
select_result *result=lex->result;
@@ -2502,7 +2505,7 @@ mysql_execute_command(THD *thd)
lex->prepared_stmt_name.str,
query_len, query_str));
}
- thd->command= COM_PREPARE;
+ thd->command= COM_STMT_PREPARE;
if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1,
&lex->prepared_stmt_name)))
send_ok(thd, 0L, 0L, "Statement prepared");
@@ -2523,6 +2526,8 @@ mysql_execute_command(THD *thd)
DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n",
lex->prepared_stmt_name.length,
lex->prepared_stmt_name.str));
+ /* We account deallocate in the same manner as mysql_stmt_close */
+ statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
if ((stmt= thd->stmt_map.find_by_name(&lex->prepared_stmt_name)))
{
thd->stmt_map.erase(stmt);
@@ -2640,7 +2645,7 @@ mysql_execute_command(THD *thd)
check_table_access(thd, SELECT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_backup_table(thd, first_table);
break;
@@ -2652,7 +2657,7 @@ mysql_execute_command(THD *thd)
check_table_access(thd, INSERT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_restore_table(thd, first_table);
break;
}
@@ -2767,6 +2772,20 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
+ /* If CREATE TABLE of non-temporary table, do implicit commit */
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ if (end_active_trans(thd))
+ {
+ res= -1;
+ break;
+ }
+ }
+ else
+ {
+ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
+ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
bool link_to_local;
// Skip first table, which is the table we are creating
@@ -2909,7 +2928,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
if (end_active_trans(thd))
goto error;
else
@@ -2998,7 +3017,7 @@ end_with_restore_list:
goto error;
else
{
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
first_table, lex->create_list,
@@ -3097,7 +3116,7 @@ end_with_restore_list:
if (check_db_used(thd, all_tables) ||
check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_repair_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
@@ -3117,7 +3136,7 @@ end_with_restore_list:
if (check_db_used(thd, all_tables) ||
check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_check_table(thd, first_table, &lex->check_opt);
break;
}
@@ -3127,7 +3146,7 @@ end_with_restore_list:
if (check_db_used(thd, all_tables) ||
check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_analyze_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
@@ -3148,7 +3167,7 @@ end_with_restore_list:
if (check_db_used(thd, all_tables) ||
check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
- thd->slow_command=TRUE;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
mysql_recreate_table(thd, first_table, 1) :
mysql_optimize_table(thd, first_table, &lex->check_opt);
@@ -3168,13 +3187,15 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (update_precheck(thd, all_tables))
break;
+ DBUG_ASSERT(select_lex->offset_limit == 0);
+ unit->set_limit(select_lex);
res= (result= mysql_update(thd, all_tables,
select_lex->item_list,
lex->value_list,
select_lex->where,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
+ unit->select_limit_cnt,
lex->duplicates, lex->ignore));
/* mysql_update return 2 if we need to switch to multi-update */
if (result != 2)
@@ -3259,6 +3280,11 @@ end_with_restore_list:
break;
}
case SQLCOM_TRUNCATE:
+ if (end_active_trans(thd))
+ {
+ res= -1;
+ break;
+ }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, DELETE_ACL, all_tables))
goto error;
@@ -3280,9 +3306,11 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= delete_precheck(thd, all_tables)))
break;
+ DBUG_ASSERT(select_lex->offset_limit == 0);
+ unit->set_limit(select_lex);
res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
- select_lex->select_limit, select_lex->options);
+ unit->select_limit_cnt, select_lex->options);
break;
}
case SQLCOM_DELETE_MULTI:
@@ -3290,10 +3318,9 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- uint table_count;
multi_delete *result;
- if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
+ if ((res= multi_delete_precheck(thd, all_tables)))
break;
/* condition will be TRUE on SP re-excuting */
@@ -3310,7 +3337,7 @@ end_with_restore_list:
goto error;
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
- table_count)))
+ lex->table_count)))
{
res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->get_table_list(),
@@ -3351,6 +3378,9 @@ end_with_restore_list:
*/
if (thd->slave_thread)
lex->drop_if_exists= 1;
+
+ /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
+ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
}
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
@@ -3489,6 +3519,11 @@ end_with_restore_list:
break;
case SQLCOM_CREATE_DB:
{
+ if (end_active_trans(thd))
+ {
+ res= -1;
+ break;
+ }
char *alias;
if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
{
@@ -3519,6 +3554,11 @@ end_with_restore_list:
}
case SQLCOM_DROP_DB:
{
+ if (end_active_trans(thd))
+ {
+ res= -1;
+ break;
+ }
if (check_db_name(lex->name))
{
my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
@@ -3869,9 +3909,10 @@ end_with_restore_list:
*/
if (check_db_used(thd, all_tables))
goto error;
+ unit->set_limit(select_lex);
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
- select_lex->select_limit, select_lex->offset_limit);
+ unit->select_limit_cnt, unit->offset_limit_cnt);
break;
case SQLCOM_BEGIN:
@@ -5153,7 +5194,6 @@ mysql_init_select(LEX *lex)
{
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
- select_lex->select_limit= HA_POS_ERROR;
lex->orig_sql_command= SQLCOM_END;
lex->wild= 0;
if (select_lex == &lex->select_lex)
@@ -5168,25 +5208,28 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex;
+ THD *thd= lex->thd;
DBUG_ENTER("mysql_new_select");
- if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
+ if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
- select_lex->select_number= ++lex->thd->select_number;
+ select_lex->select_number= ++thd->select_number;
select_lex->init_query();
select_lex->init_select();
select_lex->parent_lex= lex;
+ if (thd->current_arena->is_stmt_prepare())
+ select_lex->uncacheable|= UNCACHEABLE_PREPARE;
if (move_down)
{
SELECT_LEX_UNIT *unit;
lex->subqueries= TRUE;
/* first select_lex of subselect or derived table */
- if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
+ if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
DBUG_RETURN(1);
unit->init_query();
unit->init_select();
- unit->thd= lex->thd;
+ unit->thd= thd;
unit->include_down(lex->current_select);
unit->link_next= 0;
unit->link_prev= 0;
@@ -5210,14 +5253,14 @@ mysql_new_select(LEX *lex, bool move_down)
as far as we included SELECT_LEX for UNION unit should have
fake SELECT_LEX for UNION processing
*/
- if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
+ if (!(fake= unit->fake_select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
fake->make_empty_select();
fake->linkage= GLOBAL_OPTIONS_TYPE;
- fake->select_limit= HA_POS_ERROR;
+ fake->select_limit= 0;
}
}
@@ -5265,8 +5308,8 @@ void mysql_init_multi_delete(LEX *lex)
{
lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
- lex->select_lex.select_limit= lex->unit.select_limit_cnt=
- HA_POS_ERROR;
+ lex->select_lex.select_limit= 0;
+ lex->unit.select_limit_cnt= HA_POS_ERROR;
lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
lex->query_tables= 0;
@@ -6780,8 +6823,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (select_lex->order_list.elements)
msg= "ORDER BY";
- else if (select_lex->select_limit && select_lex->select_limit !=
- HA_POS_ERROR)
+ else if (select_lex->select_limit)
msg= "LIMIT";
if (msg)
{
@@ -6798,23 +6840,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
multi_delete_precheck()
thd Thread handler
tables Global/local table list
- table_count Pointer to table counter
RETURN VALUE
FALSE OK
TRUE error
*/
-bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_precheck");
- *table_count= 0;
-
/* sql_yacc guarantees that tables and aux_tables are not zero */
DBUG_ASSERT(aux_tables != 0);
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
@@ -6827,9 +6865,35 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
DBUG_RETURN(TRUE);
}
- for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local)
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Link tables in auxilary table list of multi-delete with corresponding
+ elements in main table list, and set proper locks for them.
+
+ SYNOPSIS
+ multi_delete_set_locks_and_link_aux_tables()
+ lex - pointer to LEX representing multi-delete
+
+ RETURN VALUE
+ FALSE - success
+ TRUE - error
+*/
+
+bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
+{
+ TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
+ TABLE_LIST *target_tbl;
+ DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
+
+ lex->table_count= 0;
+
+ for (target_tbl= (TABLE_LIST *)lex->auxilliary_table_list.first;
+ target_tbl; target_tbl= target_tbl->next_local)
{
- (*table_count)++;
+ lex->table_count++;
/* All tables in aux_tables must be found in FROM PART */
TABLE_LIST *walk;
for (walk= tables; walk; walk= walk->next_local)
@@ -6847,14 +6911,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
}
walk->lock_type= target_tbl->lock_type;
target_tbl->correspondent_table= walk; // Remember corresponding table
-
- /* in case of subselects, we need to set lock_type in
- * corresponding table in list of all tables */
- if (walk->correspondent_table)
- {
- target_tbl->correspondent_table= walk->correspondent_table;
- walk->correspondent_table->lock_type= walk->lock_type;
- }
}
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 1521b206e0d..eeea493d868 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -15,18 +15,18 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**********************************************************************
-This file contains the implementation of prepare and executes.
+This file contains the implementation of prepare and executes.
Prepare:
- - Server gets the query from client with command 'COM_PREPARE';
+ - Server gets the query from client with command 'COM_STMT_PREPARE';
in the following format:
- [COM_PREPARE:1] [query]
- - Parse the query and recognize any parameter markers '?' and
+ [COM_STMT_PREPARE:1] [query]
+ - Parse the query and recognize any parameter markers '?' and
store its information list in lex->param_list
- - Allocate a new statement for this prepare; and keep this in
+ - Allocate a new statement for this prepare; and keep this in
'thd->prepared_statements' pool.
- - Without executing the query, return back to client the total
+ - Without executing the query, return back to client the total
number of parameters along with result-set metadata information
(if any) in the following format:
[STMT_ID:4]
@@ -34,35 +34,36 @@ Prepare:
[Param_count:2]
[Columns meta info] (if Column_count > 0)
[Params meta info] (if Param_count > 0 ) (TODO : 4.1.1)
-
+
Prepare-execute:
- - Server gets the command 'COM_EXECUTE' to execute the
+ - Server gets the command 'COM_STMT_EXECUTE' to execute the
previously prepared query. If there is any param markers; then client
will send the data in the following format:
- [COM_EXECUTE:1]
+ [COM_STMT_EXECUTE:1]
[STMT_ID:4]
[NULL_BITS:(param_count+7)/8)]
[TYPES_SUPPLIED_BY_CLIENT(0/1):1]
[[length]data]
- [[length]data] .. [[length]data].
- (Note: Except for string/binary types; all other types will not be
+ [[length]data] .. [[length]data].
+ (Note: Except for string/binary types; all other types will not be
supplied with length field)
- - Replace the param items with this new data. If it is a first execute
+ - Replace the param items with this new data. If it is a first execute
or types altered by client; then setup the conversion routines.
- - Execute the query without re-parsing and send back the results
+ - Execute the query without re-parsing and send back the results
to client
Long data handling:
- - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
+ - Server gets the long data in pieces with command type
+ 'COM_STMT_SEND_LONG_DATA'.
- The packet recieved will have the format as:
- [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
+ [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
- data from the packet is appended to long data value buffer for this
placeholder.
- It's up to the client to check for read data ended. The server doesn't
- care; and also server doesn't notify to the client that it got the
- data or not; if there is any error; then during execute; the error
+ care; and also server doesn't notify to the client that it got the
+ data or not; if there is any error; then during execute; the error
will be returned
***********************************************************************/
@@ -97,14 +98,14 @@ public:
#else
bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
#endif
- bool (*set_params_from_vars)(Prepared_statement *stmt,
+ bool (*set_params_from_vars)(Prepared_statement *stmt,
List<LEX_STRING>& varnames,
String *expanded_query);
public:
Prepared_statement(THD *thd_arg);
virtual ~Prepared_statement();
void setup_set_params();
- virtual Item_arena::Type type() const;
+ virtual Query_arena::Type type() const;
};
static void execute_stmt(THD *thd, Prepared_statement *stmt,
@@ -132,7 +133,7 @@ find_prepared_statement(THD *thd, ulong id, const char *where)
{
Statement *stmt= thd->stmt_map.find(id);
- if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT)
+ if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT)
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf),
@@ -167,7 +168,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
Send types and names of placeholders to the client
XXX: fix this nasty upcast from List<Item_param> to List<Item>
*/
- DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
+ DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
(stmt->param_count &&
stmt->thd->protocol_simple.send_fields((List<Item> *)
&stmt->lex->param_list,
@@ -220,7 +221,7 @@ static ulong get_param_length(uchar **packet, ulong len)
}
if (len < 5)
return 0;
- (*packet)+=9; // Must be 254 when here
+ (*packet)+=9; // Must be 254 when here
/*
In our client-server protocol all numbers bigger than 2^24
stored as 8 bytes with uint8korr. Here we always know that
@@ -242,7 +243,7 @@ static ulong get_param_length(uchar **packet, ulong len)
pos input data buffer
len length of data in the buffer
- All these functions read the data from pos, convert it to requested type
+ All these functions read the data from pos, convert it to requested type
and assign to param; pos is advanced to predefined length.
Make a note that the NULL handling is examined at first execution
@@ -260,7 +261,7 @@ static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
return;
#endif
int8 value= (int8) **pos;
- param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
+ param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
(longlong) value, 4);
*pos+= 1;
}
@@ -480,7 +481,7 @@ static void set_param_str(Item_param *param, uchar **pos, ulong len)
}
-#undef get_param_length
+#undef get_param_length
static void setup_one_conversion_function(THD *thd, Item_param *param,
uchar param_type)
@@ -583,12 +584,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
#ifndef EMBEDDED_LIBRARY
/*
- Update the parameter markers by reading data from client packet
+ Update the parameter markers by reading data from client packet
and if binary/update log is set, generate the valid query.
*/
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
- uchar *read_pos, uchar *data_end,
+ uchar *read_pos, uchar *data_end,
String *query)
{
THD *thd= stmt->thd;
@@ -596,14 +597,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
Item_param **end= begin + stmt->param_count;
uint32 length= 0;
- String str;
+ String str;
const String *res;
- DBUG_ENTER("insert_params_withlog");
+ DBUG_ENTER("insert_params_withlog");
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
-
+
for (Item_param **it= begin; it < end; ++it)
{
Item_param *param= *it;
@@ -624,7 +625,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
if (query->replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1);
-
+
length+= res->length()-1;
}
DBUG_RETURN(0);
@@ -632,13 +633,13 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
- uchar *read_pos, uchar *data_end,
+ uchar *read_pos, uchar *data_end,
String *expanded_query)
{
Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count;
- DBUG_ENTER("insert_params");
+ DBUG_ENTER("insert_params");
for (Item_param **it= begin; it < end; ++it)
{
@@ -672,7 +673,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
if (*read_pos++) //types supplied / first execute
{
/*
- First execute or types altered by the client, setup the
+ First execute or types altered by the client, setup the
conversion routines for all parameters (one time)
*/
Item_param **it= stmt->param_array;
@@ -720,8 +721,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
uchar *buff= (uchar*) client_param->buffer;
param->unsigned_flag= client_param->is_unsigned;
param->set_param_func(param, &buff,
- client_param->length ?
- *client_param->length :
+ client_param->length ?
+ *client_param->length :
client_param->buffer_length);
}
}
@@ -747,7 +748,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
-
+
for (; it < end; ++it, ++client_param)
{
Item_param *param= *it;
@@ -759,10 +760,10 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
else
{
uchar *buff= (uchar*)client_param->buffer;
- param->unsigned_flag= client_param->is_unsigned;
+ param->unsigned_flag= client_param->is_unsigned;
param->set_param_func(param, &buff,
- client_param->length ?
- *client_param->length :
+ client_param->length ?
+ *client_param->length :
client_param->buffer_length);
}
}
@@ -839,7 +840,8 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
DBUG_ENTER("insert_params_from_vars");
List_iterator<LEX_STRING> var_it(varnames);
- String str;
+ String buf;
+ const String *val;
uint32 length= 0;
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
@@ -850,52 +852,56 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
varname= var_it++;
if (get_var_with_binlog(stmt->thd, *varname, &entry))
DBUG_RETURN(1);
- DBUG_ASSERT(entry != 0);
if (param->set_from_user_var(stmt->thd, entry))
DBUG_RETURN(1);
/* Insert @'escaped-varname' instead of parameter in the query */
- char *buf, *ptr;
- str.length(0);
- if (str.reserve(entry->name.length*2+3))
- DBUG_RETURN(1);
+ if (entry)
+ {
+ char *begin, *ptr;
+ buf.length(0);
+ if (buf.reserve(entry->name.length*2+3))
+ DBUG_RETURN(1);
- buf= str.c_ptr_quick();
- ptr= buf;
- *ptr++= '@';
- *ptr++= '\'';
- ptr+=
- escape_string_for_mysql(&my_charset_utf8_general_ci,
- ptr, 0, entry->name.str, entry->name.length);
- *ptr++= '\'';
- str.length(ptr - buf);
+ begin= ptr= buf.c_ptr_quick();
+ *ptr++= '@';
+ *ptr++= '\'';
+ ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci,
+ ptr, 0, entry->name.str,
+ entry->name.length);
+ *ptr++= '\'';
+ buf.length(ptr - begin);
+ val= &buf;
+ }
+ else
+ val= &my_null_string;
if (param->convert_str_value(stmt->thd))
DBUG_RETURN(1); /* out of memory */
- if (query->replace(param->pos_in_query+length, 1, str))
+ if (query->replace(param->pos_in_query+length, 1, *val))
DBUG_RETURN(1);
- length+= str.length()-1;
+ length+= val->length()-1;
}
DBUG_RETURN(0);
}
/*
- Validate INSERT statement:
+ Validate INSERT statement:
SYNOPSIS
mysql_test_insert()
- stmt prepared statemen handler
- tables global/local table list
+ stmt prepared statemen handler
+ tables global/local table list
RETURN VALUE
- FALSE OK
- TRUE error
+ FALSE success
+ TRUE error, error message is set in THD
*/
static bool mysql_test_insert(Prepared_statement *stmt,
TABLE_LIST *table_list,
- List<Item> &fields,
+ List<Item> &fields,
List<List_item> &values_list,
List<Item> &update_fields,
List<Item> &update_values,
@@ -905,11 +911,10 @@ static bool mysql_test_insert(Prepared_statement *stmt,
LEX *lex= stmt->lex;
List_iterator_fast<List_item> its(values_list);
List_item *values;
- bool res;
DBUG_ENTER("mysql_test_insert");
- if ((res= insert_precheck(thd, table_list)))
- DBUG_RETURN(res);
+ if (insert_precheck(thd, table_list))
+ goto error;
/*
open temporary memory pool for temporary data allocated by derived
@@ -920,10 +925,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
TL_WRITE_DELAYED as having two such locks can cause table corruption.
*/
if (open_normal_and_derived_tables(thd, table_list))
- {
- DBUG_RETURN(TRUE);
- }
-
+ goto error;
if ((values= its++))
{
@@ -937,17 +939,14 @@ static bool mysql_test_insert(Prepared_statement *stmt,
table_list->table->insert_values=(byte *)1;
}
- if ((res= mysql_prepare_insert(thd, table_list, table_list->table,
- fields, values, update_fields,
- update_values, duplic,
- &unused_conds, FALSE)))
+ if (mysql_prepare_insert(thd, table_list, table_list->table, fields,
+ values, update_fields, update_values, duplic,
+ &unused_conds, FALSE))
goto error;
value_count= values->elements;
its.rewind();
- res= TRUE;
-
if (table_list->lock_type == TL_WRITE_DELAYED &&
!(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
{
@@ -965,15 +964,14 @@ static bool mysql_test_insert(Prepared_statement *stmt,
goto error;
}
if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
- goto error;
+ goto error;
}
}
+ DBUG_RETURN(FALSE);
- res= FALSE;
error:
- lex->unit.cleanup();
/* insert_values is cleared in open_table */
- DBUG_RETURN(res);
+ DBUG_RETURN(TRUE);
}
@@ -982,14 +980,15 @@ error:
SYNOPSIS
mysql_test_update()
- stmt prepared statemen handler
- tables list of tables queries
+ stmt prepared statemen handler
+ tables list of tables queries
RETURN VALUE
0 success
+ 1 error, error message is set in THD
2 convert to multi_update
- 1 error
*/
+
static int mysql_test_update(Prepared_statement *stmt,
TABLE_LIST *table_list)
{
@@ -998,74 +997,65 @@ static int mysql_test_update(Prepared_statement *stmt,
uint table_count= 0;
SELECT_LEX *select= &stmt->lex->select_lex;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint want_privilege;
+ uint want_privilege;
#endif
DBUG_ENTER("mysql_test_update");
if (update_precheck(thd, table_list))
- DBUG_RETURN(1);
+ goto error;
- if (!open_tables(thd, &table_list, &table_count))
+ if (open_tables(thd, &table_list, &table_count))
+ goto error;
+
+ if (table_list->multitable_view)
{
- if (table_list->multitable_view)
- {
- DBUG_ASSERT(table_list->view != 0);
- DBUG_PRINT("info", ("Switch to multi-update"));
- /* pass counter value */
- thd->lex->table_count= table_count;
- /* convert to multiupdate */
- return 2;
- }
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ DBUG_RETURN(2);
+ }
- /*
- thd->fill_derived_tables() is false here for sure (because it is
- preparation of PS, so we even do not check it
- */
- if (lock_tables(thd, table_list, table_count) ||
- mysql_handle_derived(thd->lex, &mysql_derived_prepare))
- DBUG_RETURN(1);
+ /*
+ thd->fill_derived_tables() is false here for sure (because it is
+ preparation of PS, so we even do not check it).
+ */
+ if (lock_tables(thd, table_list, table_count) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare))
+ goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* TABLE_LIST contain right privilages request */
want_privilege= table_list->grant.want_privilege;
#endif
- if (!(res= mysql_prepare_update(thd, table_list,
- &select->where,
- select->order_list.elements,
- (ORDER *) select->order_list.first)))
- {
+ if (mysql_prepare_update(thd, table_list, &select->where,
+ select->order_list.elements,
+ (ORDER *) select->order_list.first))
+ goto error;
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table_list->grant.want_privilege=
- table_list->table->grant.want_privilege=
- want_privilege;
+ table_list->grant.want_privilege= want_privilege;
+ table_list->table->grant.want_privilege= want_privilege;
#endif
- thd->lex->select_lex.no_wrap_view_item= 1;
- if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0))
- {
- res= 1;
- thd->lex->select_lex.no_wrap_view_item= 0;
- }
- else
- {
- thd->lex->select_lex.no_wrap_view_item= 0;
+ thd->lex->select_lex.no_wrap_view_item= 1;
+ res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0);
+ thd->lex->select_lex.no_wrap_view_item= 0;
+ if (res)
+ goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* Check values */
- table_list->grant.want_privilege=
- table_list->table->grant.want_privilege=
- (SELECT_ACL & ~table_list->table->grant.privilege);
+ /* Check values */
+ table_list->grant.want_privilege=
+ table_list->table->grant.want_privilege=
+ (SELECT_ACL & ~table_list->table->grant.privilege);
#endif
- if (setup_fields(thd, 0, table_list,
- stmt->lex->value_list, 0, 0, 0))
- res= 1;
- }
- }
- stmt->lex->unit.cleanup();
- }
- else
- res= 1;
- /* TODO: here we should send types of placeholders to the client. */
- DBUG_RETURN(res);
+ if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0))
+ goto error;
+ /* TODO: here we should send types of placeholders to the client. */
+ DBUG_RETURN(0);
+error:
+ DBUG_RETURN(1);
}
@@ -1074,38 +1064,34 @@ static int mysql_test_update(Prepared_statement *stmt,
SYNOPSIS
mysql_test_delete()
- stmt prepared statemen handler
- tables list of tables queries
+ stmt prepared statemen handler
+ tables list of tables queries
RETURN VALUE
FALSE success
- TRUE error
+ TRUE error, error message is set in THD
*/
-static int mysql_test_delete(Prepared_statement *stmt,
- TABLE_LIST *table_list)
+
+static bool mysql_test_delete(Prepared_statement *stmt,
+ TABLE_LIST *table_list)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
DBUG_ENTER("mysql_test_delete");
- if (delete_precheck(thd, table_list))
- DBUG_RETURN(TRUE);
+ if (delete_precheck(thd, table_list) ||
+ open_and_lock_tables(thd, table_list))
+ goto error;
- if (!open_and_lock_tables(thd, table_list))
+ if (!table_list->table)
{
- bool res;
- if (!table_list->table)
- {
- my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
- table_list->view_db.str, table_list->view_name.str);
- DBUG_RETURN(-1);
- }
-
- res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
- lex->unit.cleanup();
- DBUG_RETURN(res);
+ my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
+ goto error;
}
- /* TODO: here we should send types of placeholders to the client. */
+
+ DBUG_RETURN(mysql_prepare_delete(thd, table_list, &lex->select_lex.where));
+error:
DBUG_RETURN(TRUE);
}
@@ -1113,25 +1099,24 @@ static int mysql_test_delete(Prepared_statement *stmt,
/*
Validate SELECT statement.
In case of success, if this query is not EXPLAIN, send column list info
- back to client.
+ back to client.
SYNOPSIS
mysql_test_select()
- stmt prepared statemen handler
- tables list of tables queries
+ stmt prepared statemen handler
+ tables list of tables queries
RETURN VALUE
FALSE success
TRUE error, sent to client
*/
-static int mysql_test_select(Prepared_statement *stmt,
- TABLE_LIST *tables, bool text_protocol)
+static bool mysql_test_select(Prepared_statement *stmt,
+ TABLE_LIST *tables, bool text_protocol)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX_UNIT *unit= &lex->unit;
- bool result;
DBUG_ENTER("mysql_test_select");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1139,19 +1124,20 @@ static int mysql_test_select(Prepared_statement *stmt,
if (tables)
{
if (check_table_access(thd, privilege, tables,0))
- DBUG_RETURN(TRUE);
+ goto error;
}
else if (check_access(thd, privilege, any_db,0,0,0))
- DBUG_RETURN(TRUE);
+ goto error;
#endif
- result= TRUE;
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
- goto err;
+ {
+ my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send));
+ goto error;
+ }
if (open_and_lock_tables(thd, tables))
- goto err;
-
+ goto error;
thd->used_tables= 0; // Updated by setup_fields
@@ -1161,15 +1147,13 @@ static int mysql_test_select(Prepared_statement *stmt,
usual, and we pass 0 as setup_tables_done_option
*/
if (unit->prepare(thd, 0, 0, ""))
- {
- goto err_prep;
- }
+ goto error;
if (!text_protocol)
{
if (lex->describe)
{
if (send_prep_stmt(stmt, 0) || thd->protocol->flush())
- goto err_prep;
+ goto error;
}
else
{
@@ -1179,7 +1163,7 @@ static int mysql_test_select(Prepared_statement *stmt,
/* Change columns if a procedure like analyse() */
if (unit->last_procedure &&
unit->last_procedure->change_columns(fields))
- goto err_prep;
+ goto error;
/*
We can use lex->result as it should've been
@@ -1188,15 +1172,12 @@ static int mysql_test_select(Prepared_statement *stmt,
if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
lex->result->send_fields(fields, Protocol::SEND_EOF) ||
thd->protocol->flush())
- goto err_prep;
+ goto error;
}
}
- result= FALSE; // ok
-
-err_prep:
- unit->cleanup();
-err:
- DBUG_RETURN(result);
+ DBUG_RETURN(FALSE);
+error:
+ DBUG_RETURN(TRUE);
}
@@ -1205,32 +1186,28 @@ err:
SYNOPSIS
mysql_test_do_fields()
- stmt prepared statemen handler
- tables list of tables queries
- values list of expressions
+ stmt prepared statemen handler
+ tables list of tables queries
+ values list of expressions
RETURN VALUE
FALSE success
- TRUE error, sent to client
+ TRUE error, error message is set in THD
*/
static bool mysql_test_do_fields(Prepared_statement *stmt,
- TABLE_LIST *tables,
- List<Item> *values)
+ TABLE_LIST *tables,
+ List<Item> *values)
{
- DBUG_ENTER("mysql_test_do_fields");
THD *thd= stmt->thd;
- bool res;
+
+ DBUG_ENTER("mysql_test_do_fields");
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
if (open_and_lock_tables(thd, tables))
- {
DBUG_RETURN(TRUE);
- }
- res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
- stmt->lex->unit.cleanup();
- DBUG_RETURN(res);
+ DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0));
}
@@ -1239,14 +1216,15 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
SYNOPSIS
mysql_test_set_fields()
- stmt prepared statemen handler
- tables list of tables queries
- values list of expressions
+ stmt prepared statemen handler
+ tables list of tables queries
+ values list of expressions
RETURN VALUE
FALSE success
TRUE error
*/
+
static bool mysql_test_set_fields(Prepared_statement *stmt,
TABLE_LIST *tables,
List<set_var_base> *var_list)
@@ -1255,25 +1233,19 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
List_iterator_fast<set_var_base> it(*var_list);
THD *thd= stmt->thd;
set_var_base *var;
- bool res;
-
- if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
- DBUG_RETURN(TRUE);
- if ((res= open_and_lock_tables(thd, tables)))
+ if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
+ open_and_lock_tables(thd, tables))
goto error;
+
while ((var= it++))
{
if (var->light_check(thd))
- {
- stmt->lex->unit.cleanup();
- res= TRUE;
goto error;
- }
}
+ DBUG_RETURN(FALSE);
error:
- stmt->lex->unit.cleanup();
- DBUG_RETURN(res);
+ DBUG_RETURN(TRUE);
}
@@ -1294,7 +1266,7 @@ error:
RETURN VALUE
FALSE success
- TRUE error
+ TRUE error, error message is set in THD
*/
static bool select_like_stmt_test(Prepared_statement *stmt,
@@ -1304,24 +1276,16 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
DBUG_ENTER("select_like_stmt_test");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
- bool res= FALSE;
- if (specific_prepare && (res= (*specific_prepare)(thd)))
- goto end;
+ if (specific_prepare && (*specific_prepare)(thd))
+ DBUG_RETURN(TRUE);
thd->used_tables= 0; // Updated by setup_fields
- // JOIN::prepare calls
- if (lex->unit.prepare(thd, 0, setup_tables_done_option, ""))
- {
- res= TRUE;
- }
-end:
- lex->unit.cleanup();
- DBUG_RETURN(res);
+ /* Calls JOIN::prepare */
+ DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, ""));
}
-
/*
Check internal SELECT of the prepared command (with opening and
locking tables used).
@@ -1365,29 +1329,30 @@ select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
SYNOPSIS
mysql_test_create_table()
- stmt prepared statemen handler
- tables list of tables queries
+ stmt prepared statemen handler
+ tables list of tables queries
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error, error message is set in THD
*/
-static int mysql_test_create_table(Prepared_statement *stmt)
+static bool mysql_test_create_table(Prepared_statement *stmt)
{
DBUG_ENTER("mysql_test_create_table");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
- int res= 0;
+ bool res= FALSE;
/* Skip first table, which is the table we are creating */
bool link_to_local;
TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
- if (!(res= create_table_precheck(thd, tables, create_table)) &&
- select_lex->item_list.elements)
+ if (create_table_precheck(thd, tables, create_table))
+ DBUG_RETURN(TRUE);
+
+ if (select_lex->item_list.elements)
{
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
@@ -1405,8 +1370,8 @@ static int mysql_test_create_table(Prepared_statement *stmt)
SYNOPSIS
mysql_test_multiupdate()
- stmt prepared statemen handler
- tables list of tables queries
+ stmt prepared statemen handler
+ tables list of tables queries
converted converted to multi-update from usual update
RETURN VALUE
@@ -1415,7 +1380,7 @@ static int mysql_test_create_table(Prepared_statement *stmt)
*/
static bool mysql_test_multiupdate(Prepared_statement *stmt,
- TABLE_LIST *tables,
+ TABLE_LIST *tables,
bool converted)
{
/* if we switched from normal update, rights are checked */
@@ -1432,37 +1397,38 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt,
SYNOPSIS
mysql_test_multidelete()
- stmt prepared statemen handler
- tables list of tables queries
+ stmt prepared statemen handler
+ tables list of tables queries
RETURN VALUE
0 success
- 1 error, sent to client
- -1 error, not sent to client
+ 1 error, error message in THD is set.
*/
-static int mysql_test_multidelete(Prepared_statement *stmt,
- TABLE_LIST *tables)
+
+static bool mysql_test_multidelete(Prepared_statement *stmt,
+ TABLE_LIST *tables)
{
- int res;
stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
if (add_item_to_list(stmt->thd, new Item_null()))
- return -1;
-
- uint fake_counter;
- if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
- return res;
- if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_multi_delete_prepare,
- OPTION_SETUP_TABLES_DONE)))
- return res;
+ {
+ my_error(ER_OUTOFMEMORY, MYF(0), 0);
+ goto error;
+ }
+
+ if (multi_delete_precheck(stmt->thd, tables) ||
+ select_like_stmt_test_with_open_n_lock(stmt, tables,
+ &mysql_multi_delete_prepare,
+ OPTION_SETUP_TABLES_DONE))
+ goto error;
if (!tables->table)
{
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
- tables->view_db.str, tables->view_name.str);
- return -1;
+ tables->view_db.str, tables->view_name.str);
+ goto error;
}
- return 0;
-
+ return FALSE;
+error:
+ return TRUE;
}
@@ -1498,8 +1464,8 @@ static bool mysql_insert_select_prepare_tester(THD *thd)
SYNOPSIS
mysql_test_insert_select()
- stmt prepared statemen handler
- tables list of tables of query
+ stmt prepared statemen handler
+ tables list of tables of query
RETURN VALUE
0 success
@@ -1508,7 +1474,7 @@ static bool mysql_insert_select_prepare_tester(THD *thd)
*/
static int mysql_test_insert_select(Prepared_statement *stmt,
- TABLE_LIST *tables)
+ TABLE_LIST *tables)
{
int res;
LEX *lex= stmt->lex;
@@ -1520,8 +1486,8 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
tables->table->insert_values=(byte *)1;
}
- if ((res= insert_precheck(stmt->thd, tables)))
- return res;
+ if (insert_precheck(stmt->thd, tables))
+ return 1;
/* store it, because mysql_insert_select_prepare_tester change it */
first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first;
@@ -1552,12 +1518,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
by calling fix_fields.
RETURN VALUE
- 0 success
- 1 error, sent to client
+ FALSE success, statement metadata is sent to client
+ TRUE error, error message is set (but not sent)
*/
-static int check_prepared_statement(Prepared_statement *stmt,
- bool text_protocol)
+static bool check_prepared_statement(Prepared_statement *stmt,
+ bool text_protocol)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
@@ -1576,14 +1542,14 @@ static int check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
res= mysql_test_insert(stmt, tables, lex->field_list,
- lex->many_values,
- select_lex->item_list, lex->value_list,
- lex->duplicates);
+ lex->many_values,
+ select_lex->item_list, lex->value_list,
+ lex->duplicates);
break;
case SQLCOM_UPDATE:
res= mysql_test_update(stmt, tables);
- /* mysql_test_update return 2 if we need to switch to multi-update */
+ /* mysql_test_update returns 2 if we need to switch to multi-update */
if (res != 2)
break;
@@ -1599,12 +1565,12 @@ static int check_prepared_statement(Prepared_statement *stmt,
if ((res= mysql_test_select(stmt, tables, text_protocol)))
goto error;
/* Statement and field info has already been sent */
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
case SQLCOM_CREATE_TABLE:
res= mysql_test_create_table(stmt);
break;
-
+
case SQLCOM_DO:
res= mysql_test_do_fields(stmt, tables, lex->insert_list);
break;
@@ -1650,18 +1616,15 @@ static int check_prepared_statement(Prepared_statement *stmt,
break;
default:
- /*
- All other is not supported yet
- */
- res= -1;
+ /* All other statements are not supported yet. */
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
goto error;
}
if (res == 0)
- DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) ||
- thd->protocol->flush()));
+ DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) ||
+ thd->protocol->flush()));
error:
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
/*
@@ -1699,45 +1662,64 @@ static bool init_param_array(Prepared_statement *stmt)
return FALSE;
}
+
+/* Cleanup PS after execute/prepare and restore THD state */
+
+static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd)
+{
+ stmt->lex->unit.cleanup();
+ cleanup_items(stmt->free_list);
+ thd->rollback_item_tree_changes();
+ thd->cleanup_after_query();
+}
+
/*
Given a query string with parameter markers, create a Prepared Statement
from it and send PS info back to the client.
-
+
SYNOPSIS
mysql_stmt_prepare()
- packet query to be prepared
- packet_length query string length, including ignored trailing NULL or
+ packet query to be prepared
+ packet_length query string length, including ignored trailing NULL or
quote char.
name NULL or statement name. For unnamed statements binary PS
- protocol is used, for named statements text protocol is
+ protocol is used, for named statements text protocol is
used.
RETURN
FALSE OK, statement prepared successfully
TRUE Error
NOTES
- This function parses the query and sends the total number of parameters
- and resultset metadata information back to client (if any), without
- executing the query i.e. without any log/disk writes. This allows the
- queries to be re-executed without re-parsing during execute.
+ This function parses the query and sends the total number of parameters
+ and resultset metadata information back to client (if any), without
+ executing the query i.e. without any log/disk writes. This allows the
+ queries to be re-executed without re-parsing during execute.
If parameter markers are found in the query, then store the information
- using Item_param along with maintaining a list in lex->param_array, so
- that a fast and direct retrieval can be made without going through all
+ using Item_param along with maintaining a list in lex->param_array, so
+ that a fast and direct retrieval can be made without going through all
field items.
-
+
*/
bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
LEX_STRING *name)
{
LEX *lex;
+ Statement stmt_backup;
Prepared_statement *stmt= new Prepared_statement(thd);
bool error;
DBUG_ENTER("mysql_stmt_prepare");
DBUG_PRINT("prep_query", ("%s", packet));
+ /*
+ If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
+ However, it seems handy if com_stmt_prepare is increased always,
+ no matter what kind of prepare is processed.
+ */
+ statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status);
+
if (stmt == 0)
DBUG_RETURN(TRUE);
@@ -1758,19 +1740,19 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
DBUG_RETURN(TRUE);
}
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- thd->set_n_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
+ thd->set_n_backup_item_arena(stmt, &stmt_backup);
if (alloc_query(thd, packet, packet_length))
{
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
- thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
+ thd->restore_backup_item_arena(stmt, &stmt_backup);
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
DBUG_RETURN(TRUE);
}
- mysql_log.write(thd, COM_PREPARE, "[%lu] %s", stmt->id, packet);
+ mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, packet);
thd->current_arena= stmt;
mysql_init_query(thd, (uchar *) thd->query, thd->query_length);
@@ -1789,7 +1771,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
transformation can be reused on execute, we set again thd->mem_root from
stmt->mem_root (see setup_wild for one place where we do that).
*/
- thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->restore_backup_item_arena(stmt, &stmt_backup);
if (!error)
error= check_prepared_statement(stmt, test(name));
@@ -1804,10 +1786,8 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
}
lex_end(lex);
close_thread_tables(thd);
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
- cleanup_items(stmt->free_list);
- thd->rollback_item_tree_changes();
- thd->cleanup_after_query();
+ cleanup_stmt_and_thd_after_use(stmt, thd);
+ thd->restore_backup_statement(stmt, &stmt_backup);
thd->current_arena= thd;
if (error)
@@ -1820,7 +1800,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
{
stmt->setup_set_params();
init_stmt_after_parse(thd, stmt->lex);
- stmt->state= Item_arena::PREPARED;
+ stmt->state= Query_arena::PREPARED;
}
DBUG_RETURN(!stmt);
}
@@ -1838,7 +1818,10 @@ void init_stmt_after_parse(THD *thd, LEX *lex)
optimisation.
*/
for (; sl; sl= sl->next_select_in_list())
+ {
sl->prep_where= sl->where;
+ sl->uncacheable&= ~UNCACHEABLE_PREPARE;
+ }
for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
table->prep_on_expr= table->on_expr;
@@ -1847,10 +1830,10 @@ void init_stmt_after_parse(THD *thd, LEX *lex)
/* Reinit prepared statement/stored procedure before execution */
-void reset_stmt_for_execute(THD *thd, LEX *lex)
+void reinit_stmt_before_use(THD *thd, LEX *lex)
{
SELECT_LEX *sl= lex->all_selects_list;
- DBUG_ENTER("reset_stmt_for_execute");
+ DBUG_ENTER("reinit_stmt_before_use");
if (lex->empty_field_list_on_rset)
{
@@ -1894,8 +1877,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
}
/*
- TODO: When the new table structure is ready, then have a status bit
- to indicate the table is altered, and re-do the setup_*
+ TODO: When the new table structure is ready, then have a status bit
+ to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
/*
@@ -1904,8 +1887,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
they have their own table list).
*/
for (TABLE_LIST *tables= lex->query_tables;
- tables;
- tables= tables->next_global)
+ tables;
+ tables= tables->next_global)
{
/*
Reset old pointers to TABLEs: they are not valid since the tables
@@ -1936,10 +1919,10 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
/*
Clears parameters from data left from previous execution or long data
-
+
SYNOPSIS
reset_stmt_params()
- stmt prepared statement for which parameters should be reset
+ stmt prepared statement for which parameters should be reset
*/
static void reset_stmt_params(Prepared_statement *stmt)
@@ -1967,6 +1950,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) ((uchar) packet[4]);
+ Statement stmt_backup;
Cursor *cursor;
/*
Query text for binary log, or empty string if the query is not put into
@@ -1981,13 +1965,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
packet+= 9; /* stmt_id + 5 bytes of flags */
+ statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute")))
DBUG_VOID_RETURN;
DBUG_PRINT("exec_query:", ("%s", stmt->query));
/* Check if we got an error when sending long data */
- if (stmt->state == Item_arena::ERROR)
+ if (stmt->state == Query_arena::ERROR)
{
my_message(stmt->last_errno, stmt->last_error, MYF(0));
DBUG_VOID_RETURN;
@@ -2019,7 +2004,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
DBUG_PRINT("info",("Using READ_ONLY cursor"));
if (!cursor &&
- !(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
+ !(cursor= stmt->cursor= new (stmt->mem_root) Cursor(thd)))
DBUG_VOID_RETURN;
/* If lex->result is set, mysql_execute_command will use it */
stmt->lex->result= &cursor->result;
@@ -2036,17 +2021,16 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
}
#else
/*
- In embedded library we re-install conversion routines each time
- we set params, and also we don't need to parse packet.
+ In embedded library we re-install conversion routines each time
+ we set params, and also we don't need to parse packet.
So we do it in one function.
*/
if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
goto set_params_data_err;
#endif
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
thd->current_arena= stmt;
- reset_stmt_for_execute(thd, stmt->lex);
+ reinit_stmt_before_use(thd, stmt->lex);
/* From now cursors assume that thd->mem_root is clean */
if (expanded_query.length() &&
alloc_query(thd, (char *)expanded_query.ptr(),
@@ -2055,10 +2039,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
my_error(ER_OUTOFMEMORY, 0, expanded_query.length());
goto err;
}
-
- mysql_log.write(thd, COM_EXECUTE, "[%lu] %s", stmt->id,
- expanded_query.length() ? expanded_query.c_ptr() :
- stmt->query);
+ mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query);
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -2070,20 +2051,21 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
if (cursor && cursor->is_open())
{
+ /*
+ It's safer if we grab THD state after mysql_execute_command is
+ finished and not in Cursor::open(), because currently the call to
+ Cursor::open is buried deep in JOIN::exec of the top level join.
+ */
cursor->init_from_thd(thd);
- cursor->state= stmt->state;
}
else
{
- thd->lex->unit.cleanup();
- cleanup_items(stmt->free_list);
+ close_thread_tables(thd);
+ cleanup_stmt_and_thd_after_use(stmt, thd);
reset_stmt_params(stmt);
- close_thread_tables(thd); /* to close derived tables */
- thd->rollback_item_tree_changes();
- thd->cleanup_after_query();
}
- thd->set_statement(&thd->stmt_backup);
+ thd->set_statement(&stmt_backup);
thd->current_arena= thd;
DBUG_VOID_RETURN;
@@ -2108,9 +2090,12 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
binary log.
*/
String expanded_query;
+ Statement stmt_backup;
DBUG_ENTER("mysql_sql_stmt_execute");
DBUG_ASSERT(thd->free_list == NULL);
+ /* See comment for statistic_increment in mysql_stmt_prepare */
+ statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
{
@@ -2127,15 +2112,16 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
/* Must go before setting variables, as it clears thd->user_var_events */
mysql_reset_thd_for_next_command(thd);
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- thd->set_statement(stmt);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
if (stmt->set_params_from_vars(stmt,
- thd->stmt_backup.lex->prepared_stmt_params,
+ stmt_backup.lex->prepared_stmt_params,
&expanded_query))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
}
+ thd->command= COM_STMT_EXECUTE; /* For nice messages in general log */
execute_stmt(thd, stmt, &expanded_query);
+ thd->set_statement(&stmt_backup);
DBUG_VOID_RETURN;
}
@@ -2158,7 +2144,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
{
DBUG_ENTER("execute_stmt");
- reset_stmt_for_execute(thd, stmt->lex);
+ reinit_stmt_before_use(thd, stmt->lex);
if (expanded_query->length() &&
alloc_query(thd, (char *)expanded_query->ptr(),
@@ -2167,6 +2153,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
my_error(ER_OUTOFMEMORY, MYF(0), expanded_query->length());
DBUG_VOID_RETURN;
}
+ mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query);
/*
At first execution of prepared statement we will perform logical
transformations of the query tree (i.e. negations elimination).
@@ -2179,30 +2166,34 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
mysql_execute_command(thd);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
+ /*
+ 'start_time' is set in dispatch_command, but THD::query will
+ be freed when we return from this function. So let's log the slow
+ query here.
+ */
+ log_slow_statement(thd);
+ /* Prevent from second logging in the end of dispatch_command */
+ thd->enable_slow_log= FALSE;
- thd->lex->unit.cleanup();
- thd->current_arena= thd;
- cleanup_items(stmt->free_list);
- thd->rollback_item_tree_changes();
- reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables
- thd->set_statement(&thd->stmt_backup);
- thd->cleanup_after_query();
+ cleanup_stmt_and_thd_after_use(stmt, thd);
+ reset_stmt_params(stmt);
+ thd->current_arena= thd;
- if (stmt->state == Item_arena::PREPARED)
- stmt->state= Item_arena::EXECUTED;
+ if (stmt->state == Query_arena::PREPARED)
+ stmt->state= Query_arena::EXECUTED;
DBUG_VOID_RETURN;
}
/*
- COM_FETCH handler: fetches requested amount of rows from cursor
+ COM_STMT_FETCH handler: fetches requested amount of rows from cursor
SYNOPSIS
mysql_stmt_fetch()
- thd Thread handler
- packet Packet from client (with stmt_id & num_rows)
- packet_length Length of packet
+ thd Thread handler
+ packet Packet from client (with stmt_id & num_rows)
+ packet_length Length of packet
*/
void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
@@ -2210,37 +2201,43 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
/* assume there is always place for 8-16 bytes */
ulong stmt_id= uint4korr(packet);
ulong num_rows= uint4korr(packet+4);
- Statement *stmt;
+ Prepared_statement *stmt;
+ Statement stmt_backup;
DBUG_ENTER("mysql_stmt_fetch");
+ statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
DBUG_VOID_RETURN;
if (!stmt->cursor || !stmt->cursor->is_open())
{
- my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0));
+ my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
DBUG_VOID_RETURN;
}
thd->current_arena= stmt;
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- stmt->cursor->init_thd(thd);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
- thd->protocol= &thd->protocol_prep; // Switch to binary protocol
+ thd->protocol= &thd->protocol_prep; // Switch to binary protocol
stmt->cursor->fetch(num_rows);
thd->protocol= &thd->protocol_simple; // Use normal protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- /* Restore THD state */
- stmt->cursor->reset_thd(thd);
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
thd->current_arena= thd;
+ if (!stmt->cursor->is_open())
+ {
+ /* We're done with the fetch: reset PS for next execution */
+ cleanup_stmt_and_thd_after_use(stmt, thd);
+ reset_stmt_params(stmt);
+ }
+
DBUG_VOID_RETURN;
}
@@ -2250,7 +2247,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
SYNOPSIS
mysql_stmt_reset()
thd Thread handle
- packet Packet with stmt id
+ packet Packet with stmt id
DESCRIPTION
This function resets statement to the state it was right after prepare.
@@ -2269,40 +2266,42 @@ void mysql_stmt_reset(THD *thd, char *packet)
Prepared_statement *stmt;
DBUG_ENTER("mysql_stmt_reset");
+ statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
DBUG_VOID_RETURN;
if (stmt->cursor && stmt->cursor->is_open())
stmt->cursor->close();
- stmt->state= Item_arena::PREPARED;
+ stmt->state= Query_arena::PREPARED;
- /*
- Clear parameters from data which could be set by
+ /*
+ Clear parameters from data which could be set by
mysql_stmt_send_long_data() call.
*/
reset_stmt_params(stmt);
mysql_reset_thd_for_next_command(thd);
send_ok(thd);
-
+
DBUG_VOID_RETURN;
}
/*
Delete a prepared statement from memory.
- Note: we don't send any reply to that command.
+ Note: we don't send any reply to that command.
*/
-void mysql_stmt_free(THD *thd, char *packet)
+void mysql_stmt_close(THD *thd, char *packet)
{
/* There is always space for 4 bytes in packet buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
- DBUG_ENTER("mysql_stmt_free");
+ DBUG_ENTER("mysql_stmt_close");
+ statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
DBUG_VOID_RETURN;
@@ -2317,9 +2316,9 @@ void mysql_stmt_free(THD *thd, char *packet)
SYNOPSIS
mysql_stmt_get_longdata()
- thd Thread handle
- pos String to append
- packet_length Length of string
+ thd Thread handle
+ pos String to append
+ packet_length Length of string
DESCRIPTION
Get a part of a long data.
@@ -2338,9 +2337,10 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Prepared_statement *stmt;
Item_param *param;
char *packet_end= packet + packet_length - 1;
-
+
DBUG_ENTER("mysql_stmt_get_longdata");
+ statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER)
@@ -2363,7 +2363,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
if (param_number >= stmt->param_count)
{
/* Error will be sent in execute call */
- stmt->state= Item_arena::ERROR;
+ stmt->state= Query_arena::ERROR;
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
"mysql_stmt_send_long_data");
@@ -2379,7 +2379,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
if (param->set_longdata(thd->extra_data, thd->extra_length))
#endif
{
- stmt->state= Item_arena::ERROR;
+ stmt->state= Query_arena::ERROR;
stmt->last_errno= ER_OUTOFMEMORY;
sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
}
@@ -2388,7 +2388,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Prepared_statement::Prepared_statement(THD *thd_arg)
- :Statement(thd_arg),
+ :Statement(INITIALIZED, ++thd_arg->statement_id_counter,
+ thd_arg->variables.query_alloc_block_size,
+ thd_arg->variables.query_prealloc_size),
thd(thd_arg),
param_array(0),
param_count(0),
@@ -2397,10 +2399,12 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
*last_error= '\0';
}
+
void Prepared_statement::setup_set_params()
{
/* Setup binary logging */
- if (mysql_bin_log.is_open() && is_update_query(lex->sql_command))
+ if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) ||
+ mysql_log.is_open() || mysql_slow_log.is_open())
{
set_params_from_vars= insert_params_from_vars_with_log;
#ifndef EMBEDDED_LIBRARY
@@ -2430,7 +2434,7 @@ Prepared_statement::~Prepared_statement()
}
-Item_arena::Type Prepared_statement::type() const
+Query_arena::Type Prepared_statement::type() const
{
return PREPARED_STATEMENT;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 8fe17198cf0..3880aa428b9 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -164,7 +164,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
ren_table->db, old_alias,
reg_ext);
unpack_filename(name, name);
- if ((table_type=get_table_type(name)) == DB_TYPE_UNKNOWN)
+ if ((table_type=get_table_type(thd, name)) == DB_TYPE_UNKNOWN)
{
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
if (!skip_error)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 1dcdf159f8f..dbefbb34b4a 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1317,6 +1317,7 @@ bool mysql_show_binlog_events(THD* thd)
if (mysql_bin_log.is_open())
{
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
+ SELECT_LEX_UNIT *unit= &thd->lex->unit;
ha_rows event_count, limit_start, limit_end;
my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
@@ -1325,8 +1326,9 @@ bool mysql_show_binlog_events(THD* thd)
LOG_INFO linfo;
Log_event* ev;
- limit_start= thd->lex->current_select->offset_limit;
- limit_end= thd->lex->current_select->select_limit + limit_start;
+ unit->set_limit(thd->lex->current_select);
+ limit_start= unit->offset_limit_cnt;
+ limit_end= unit->select_limit_cnt;
name= search_file_name;
if (log_file_name)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 8b5b4d7b224..bea68bf4da5 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -28,6 +28,8 @@
#include <hash.h>
#include <ft_global.h>
+typedef uint32 cache_rec_length_type;
+
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext",
"ref_or_null","unique_subquery","index_subquery",
@@ -136,7 +138,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static enum_nested_loop_state
end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
-static int test_if_group_changed(List<Item_buff> &list);
+static int test_if_group_changed(List<Cached_item> &list);
static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
static int join_read_system(JOIN_TAB *tab);
static int join_read_const(JOIN_TAB *tab);
@@ -580,7 +582,7 @@ JOIN::optimize()
MEMROOT for prepared statements and stored procedures.
*/
- Item_arena *arena= thd->current_arena, backup;
+ Query_arena *arena= thd->current_arena, backup;
if (arena->is_conventional())
arena= 0; // For easier test
else
@@ -812,9 +814,14 @@ JOIN::optimize()
DBUG_RETURN(1);
}
simple_group= 0;
- group_list= remove_const(this, group_list, conds,
- rollup.state == ROLLUP::STATE_NONE,
- &simple_group);
+ {
+ ORDER *old_group_list;
+ group_list= remove_const(this, (old_group_list= group_list), conds,
+ rollup.state == ROLLUP::STATE_NONE,
+ &simple_group);
+ if (old_group_list && !group_list)
+ select_distinct= 0;
+ }
if (!group_list && group)
{
order=0; // The output has only one row
@@ -1697,7 +1704,16 @@ JOIN::cleanup()
/************************* Cursor ******************************************/
-
+
+Cursor::Cursor(THD *thd)
+ :Query_arena(&main_mem_root, INITIALIZED),
+ join(0), unit(0)
+{
+ /* We will overwrite it at open anyway. */
+ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+}
+
+
void
Cursor::init_from_thd(THD *thd)
{
@@ -1705,10 +1721,11 @@ Cursor::init_from_thd(THD *thd)
We need to save and reset thd->mem_root, otherwise it'll be freed
later in mysql_parse.
- We can't just change the thd->mem_root here as we want to keep the things
- that is already allocated in thd->mem_root for Cursor::fetch()
+ We can't just change the thd->mem_root here as we want to keep the
+ things that are already allocated in thd->mem_root for Cursor::fetch()
*/
main_mem_root= *thd->mem_root;
+ state= thd->current_arena->state;
/* Allocate new memory root for thd */
init_sql_alloc(thd->mem_root,
thd->variables.query_alloc_block_size,
@@ -1731,24 +1748,6 @@ Cursor::init_from_thd(THD *thd)
What problems can we have with it if cursor is open?
TODO: must be fixed because of the prelocked mode.
*/
- /*
- TODO: grab thd->free_list here?
- */
-}
-
-
-void
-Cursor::init_thd(THD *thd)
-{
- DBUG_ASSERT(thd->derived_tables == 0);
- thd->derived_tables= derived_tables;
-
- DBUG_ASSERT(thd->open_tables == 0);
- thd->open_tables= open_tables;
-
- DBUG_ASSERT(thd->lock== 0);
- thd->lock= lock;
- thd->query_id= query_id;
}
@@ -1821,11 +1820,19 @@ Cursor::fetch(ulong num_rows)
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
enum_nested_loop_state error= NESTED_LOOP_OK;
+ Query_arena backup_arena;
DBUG_ENTER("Cursor::fetch");
DBUG_PRINT("enter",("rows: %lu", num_rows));
+ DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
+ thd->lock == 0);
+
+ thd->derived_tables= derived_tables;
+ thd->open_tables= open_tables;
+ thd->lock= lock;
+ thd->query_id= query_id;
/* save references to memory, allocated during fetch */
- thd->set_n_backup_item_arena(this, &thd->stmt_backup);
+ thd->set_n_backup_item_arena(this, &backup_arena);
join->fetch_limit+= num_rows;
@@ -1841,7 +1848,10 @@ Cursor::fetch(ulong num_rows)
ha_release_temporary_latches(thd);
#endif
- thd->restore_backup_item_arena(this, &thd->stmt_backup);
+ thd->restore_backup_item_arena(this, &backup_arena);
+ DBUG_ASSERT(thd->free_list == 0);
+ reset_thd(thd);
+
if (error == NESTED_LOOP_CURSOR_LIMIT)
{
/* Fetch limit worked, possibly more rows are there */
@@ -1882,8 +1892,8 @@ Cursor::close()
join->cleanup();
delete join;
}
- /* XXX: Another hack: closing tables used in the cursor */
{
+ /* XXX: Another hack: closing tables used in the cursor */
DBUG_ASSERT(lock || open_tables || derived_tables);
TABLE *tmp_derived_tables= thd->derived_tables;
@@ -2161,7 +2171,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
if (*s->on_expr_ref)
{
/* s is the only inner table of an outer join */
- if (!table->file->records)
+ if (!table->file->records && !embedding)
{ // Empty table
s->dependent= 0; // Ignore LEFT JOIN depend.
set_position(join,const_count++,s,(KEYUSE*) 0);
@@ -6273,7 +6283,7 @@ public:
COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {}
};
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List<COND_CMP>;
template class I_List_iterator<COND_CMP>;
template class List<Item_func_match>;
@@ -7067,7 +7077,7 @@ static COND* substitute_for_best_equal_field(COND *cond,
List_iterator_fast<Item_equal> it(cond_equal->current_level);
while ((item_equal= it++))
{
- eliminate_item_equal(cond, cond_equal->upper_levels, item_equal);
+ cond= eliminate_item_equal(cond, cond_equal->upper_levels, item_equal);
}
}
}
@@ -7960,6 +7970,19 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
modify_item ? (Item_field*) item : NULL,
convert_blob_length);
}
+ case Item::REF_ITEM:
+ if ( item->real_item()->type() == Item::FIELD_ITEM)
+ {
+ Item_field *field= (Item_field*) *((Item_ref*)item)->ref;
+ Field *new_field= create_tmp_field_from_field(thd,
+ (*from_field= field->field),
+ item->name, table,
+ NULL,
+ convert_blob_length);
+ if (modify_item)
+ item->set_result_field(new_field);
+ return new_field;
+ }
case Item::FUNC_ITEM:
case Item::COND_ITEM:
case Item::FIELD_AVG_ITEM:
@@ -7971,7 +7994,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::REAL_ITEM:
case Item::DECIMAL_ITEM:
case Item::STRING_ITEM:
- case Item::REF_ITEM:
case Item::NULL_ITEM:
case Item::VARBIN_ITEM:
return create_tmp_field_from_item(thd, item, table, copy_func, modify_item,
@@ -10080,7 +10102,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
join->do_send_rows= 0;
if (join->unit->fake_select_lex)
- join->unit->fake_select_lex->select_limit= HA_POS_ERROR;
+ join->unit->fake_select_lex->select_limit= 0;
DBUG_RETURN(NESTED_LOOP_OK);
}
}
@@ -11597,7 +11619,7 @@ used_blob_length(CACHE_FIELD **ptr)
static bool
store_record_in_cache(JOIN_CACHE *cache)
{
- ulong length;
+ cache_rec_length_type length;
uchar *pos;
CACHE_FIELD *copy,*end_field;
bool last_record;
@@ -11642,9 +11664,9 @@ store_record_in_cache(JOIN_CACHE *cache)
end > str && end[-1] == ' ' ;
end--) ;
length=(uint) (end-str);
- memcpy(pos+1,str,length);
- *pos=(uchar) length;
- pos+=length+1;
+ memcpy(pos+sizeof(length), str, length);
+ memcpy_fixed(pos, &length, sizeof(length));
+ pos+= length+sizeof(length);
}
else
{
@@ -11678,7 +11700,7 @@ static void
read_cached_record(JOIN_TAB *tab)
{
uchar *pos;
- uint length;
+ cache_rec_length_type length;
bool last_record;
CACHE_FIELD *copy,*end_field;
@@ -11707,9 +11729,10 @@ read_cached_record(JOIN_TAB *tab)
{
if (copy->strip)
{
- memcpy(copy->str,pos+1,length=(uint) *pos);
- memset(copy->str+length,' ',copy->length-length);
- pos+=1+length;
+ memcpy_fixed(&length, pos, sizeof(length));
+ memcpy(copy->str, pos+sizeof(length), length);
+ memset(copy->str+length, ' ', copy->length-length);
+ pos+= sizeof(length)+length;
}
else
{
@@ -11788,11 +11811,11 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
ref_pointer_array.
RETURN
- 0 if OK
- 1 if error occurred
+ FALSE if OK
+ TRUE if error occurred
*/
-static int
+static bool
find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
ORDER *order, List<Item> &fields, List<Item> &all_fields,
bool is_group_field)
@@ -11809,13 +11832,13 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
order_item->full_name(), thd->where);
- return 1;
+ return TRUE;
}
order->item= ref_pointer_array + count - 1;
order->in_field_list= 1;
order->counter= count;
order->counter_used= 1;
- return 0;
+ return FALSE;
}
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
uint counter;
@@ -11823,7 +11846,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
select_item= find_item_in_list(order_item, fields, &counter,
REPORT_EXCEPT_NOT_FOUND, &unaliased);
if (!select_item)
- return 1; /* Some error occured. */
+ return TRUE; /* The item is not unique, or some other error occured. */
/* Check whether the resolved field is not ambiguos. */
@@ -11837,7 +11860,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
*/
if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables,
order->item))
- return 1;
+ return TRUE;
/* Lookup the current GROUP field in the FROM clause. */
order_item_type= order_item->type();
@@ -11877,27 +11900,42 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{
order->item= ref_pointer_array + counter;
order->in_field_list=1;
- return 0;
+ return FALSE;
}
+ else
+ /*
+ There is a field with the same name in the FROM clause. This is the field
+ that will be chosen. In this case we issue a warning so the user knows
+ that the field from the FROM clause overshadows the column reference from
+ the SELECT list.
+ */
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR,
+ ER(ER_NON_UNIQ_ERROR), from_field->field_name,
+ current_thd->where);
}
order->in_field_list=0;
/*
+ The call to order_item->fix_fields() means that here we resolve 'order_item'
+ to a column from a table in the list 'tables', or to a column in some outer
+ query. Exactly because of the second case we come to this point even if
+ (select_item == not_found_item), inspite of that fix_fields() calls
+ find_item_in_list() one more time.
+
We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
-
- 'it' reassigned in if condition because fix_field can change it.
*/
if (!order_item->fixed &&
(order_item->fix_fields(thd, tables, order->item) ||
(order_item= *order->item)->check_cols(1) ||
thd->is_fatal_error))
- return 1; // Wrong field
+ return TRUE; /* Wrong field. */
+
uint el= all_fields.elements;
- all_fields.push_front(order_item); // Add new field to field list
+ all_fields.push_front(order_item); /* Add new field to field list. */
ref_pointer_array[el]= order_item;
order->item= ref_pointer_array + el;
- return 0;
+ return FALSE;
}
@@ -12284,7 +12322,7 @@ alloc_group_fields(JOIN *join,ORDER *group)
{
for (; group ; group=group->next)
{
- Item_buff *tmp=new_Item_buff(*group->item);
+ Cached_item *tmp=new_Cached_item(join->thd, *group->item);
if (!tmp || join->group_fields.push_front(tmp))
return TRUE;
}
@@ -12295,12 +12333,12 @@ alloc_group_fields(JOIN *join,ORDER *group)
static int
-test_if_group_changed(List<Item_buff> &list)
+test_if_group_changed(List<Cached_item> &list)
{
DBUG_ENTER("test_if_group_changed");
- List_iterator<Item_buff> li(list);
+ List_iterator<Cached_item> li(list);
int idx= -1,i;
- Item_buff *buff;
+ Cached_item *buff;
for (i=(int) list.elements-1 ; (buff=li++) ; i--)
{
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 49ac58e913b..e5266944251 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -178,7 +178,7 @@ class JOIN :public Sql_alloc
table_map const_table_map,found_const_table_map,outer_join;
ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
/*
- Used to fetch no more than given amount of rows per one
+ Used to fetch no more than given amount of rows per one
fetch operation of server side cursor.
The value is checked in end_send and end_send_group in fashion, similar
to offset_limit_cnt:
@@ -190,7 +190,7 @@ class JOIN :public Sql_alloc
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read;
List<Item> *fields;
- List<Item_buff> group_fields, group_fields_cache;
+ List<Cached_item> group_fields, group_fields_cache;
TABLE *tmp_table;
// used to store 2 possible tmp table of SELECT
TABLE *exec_tmp_table1, *exec_tmp_table2;
@@ -370,8 +370,9 @@ class JOIN :public Sql_alloc
statement for many cursors.
*/
-class Cursor: public Sql_alloc, public Item_arena
+class Cursor: public Sql_alloc, public Query_arena
{
+ MEM_ROOT main_mem_root;
JOIN *join;
SELECT_LEX_UNIT *unit;
@@ -386,8 +387,6 @@ public:
/* Temporary implementation as now we replace THD state by value */
/* Save THD state into cursor */
void init_from_thd(THD *thd);
- /* Restore THD from cursor to continue cursor execution */
- void init_thd(THD *thd);
/* bzero cursor state in THD */
void reset_thd(THD *thd);
@@ -398,7 +397,7 @@ public:
void close();
void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
- Cursor() :Item_arena(TRUE), join(0), unit(0) {}
+ Cursor(THD *thd);
~Cursor();
};
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1e34f32184a..12025c82da6 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -348,7 +348,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
table_list->table_name));
/* Only one table for now, but VIEW can involve several tables */
- if (open_and_lock_tables(thd, table_list))
+ if (open_normal_and_derived_tables(thd, table_list))
{
DBUG_RETURN(TRUE);
}
@@ -448,25 +448,32 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
DBUG_RETURN(TRUE);
}
#endif
-
- (void) sprintf(path,"%s/%s",mysql_data_home, dbname);
- length=unpack_dirname(path,path); // Convert if not unix
- found_libchar= 0;
- if (length && path[length-1] == FN_LIBCHAR)
+ if (!my_strcasecmp(system_charset_info, dbname,
+ information_schema_name.str))
{
- found_libchar= 1;
- path[length-1]=0; // remove ending '\'
+ dbname= information_schema_name.str;
+ create.default_table_charset= system_charset_info;
}
- if (access(path,F_OK))
+ else
{
- my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
- DBUG_RETURN(TRUE);
+ (void) sprintf(path,"%s/%s",mysql_data_home, dbname);
+ length=unpack_dirname(path,path); // Convert if not unix
+ found_libchar= 0;
+ if (length && path[length-1] == FN_LIBCHAR)
+ {
+ found_libchar= 1;
+ path[length-1]=0; // remove ending '\'
+ }
+ if (access(path,F_OK))
+ {
+ my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
+ DBUG_RETURN(TRUE);
+ }
+ if (found_libchar)
+ path[length-1]= FN_LIBCHAR;
+ strmov(path+length, MY_DB_OPT_FILE);
+ load_db_opt(thd, path, &create);
}
- if (found_libchar)
- path[length-1]= FN_LIBCHAR;
- strmov(path+length, MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
-
List<Item> field_list;
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
field_list.push_back(new Item_empty_string("Create Database",1024));
@@ -540,8 +547,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
DBUG_ENTER("mysqld_list_fields");
DBUG_PRINT("enter",("table: %s",table_list->table_name));
- table_list->lock_type= TL_UNLOCK;
- if (open_and_lock_tables(thd, table_list))
+ if (open_normal_and_derived_tables(thd, table_list))
DBUG_VOID_RETURN;
table= table_list->table;
@@ -1096,7 +1102,7 @@ public:
char *query;
};
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List<thread_info>;
#endif
@@ -1945,7 +1951,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
bool res;
lex->all_selects_list= lsel;
- res= open_and_lock_tables(thd, show_table_list);
+ res= open_normal_and_derived_tables(thd, show_table_list);
if (schema_table->process_table(thd, show_table_list,
table, res, show_table_list->db,
show_table_list->alias))
@@ -2050,7 +2056,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
show_table_list->lock_type= lock_type;
lex->all_selects_list= &sel;
lex->derived_tables= 0;
- res= open_and_lock_tables(thd, show_table_list);
+ res= open_normal_and_derived_tables(thd, show_table_list);
if (schema_table->process_table(thd, show_table_list, table,
res, base_name,
show_table_list->alias))
@@ -2646,6 +2652,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0))
{
+ int enum_idx= proc_table->field[5]->val_int();
table->field[3]->store(sp_name, strlen(sp_name), cs);
get_field(thd->mem_root, proc_table->field[3], &tmp_string);
table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
@@ -2667,10 +2674,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
table->field[10]->store("SQL", 3, cs);
get_field(thd->mem_root, proc_table->field[6], &tmp_string);
table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
- if (proc_table->field[5]->val_int() == SP_CONTAINS_SQL)
- {
- table->field[12]->store("CONTAINS SQL", 12 , cs);
- }
+ table->field[12]->store(sp_data_access_name[enum_idx].str,
+ sp_data_access_name[enum_idx].length , cs);
get_field(thd->mem_root, proc_table->field[7], &tmp_string);
table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
bzero((char *)&time, sizeof(time));
@@ -3874,7 +3879,7 @@ ST_SCHEMA_TABLE schema_tables[]=
};
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator_fast<char>;
template class List<char>;
#endif
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5e1e76e2a40..e34718ec05a 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -39,6 +39,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
uint order_num, ORDER *order,
ha_rows *copied,ha_rows *deleted);
static bool prepare_blob_field(THD *thd, create_field *sql_field);
+static bool check_engine(THD *thd, const char *table_name,
+ enum db_type *new_engine);
/*
@@ -268,7 +270,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
else
{
char *end;
- db_type table_type= get_table_type(path);
+ db_type table_type= get_table_type(thd, path);
*(end=fn_ext(path))=0; // Remove extension for delete
error= ha_delete_table(thd, table_type, path, table->table_name,
!dont_log_query);
@@ -1490,7 +1492,6 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
KEY *key_info_buffer;
handler *file;
bool error= TRUE;
- enum db_type new_db_type;
DBUG_ENTER("mysql_create_table");
/* Check for duplicate fields and check type of table to create */
@@ -1500,16 +1501,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0));
DBUG_RETURN(TRUE);
}
- if ((new_db_type= ha_checktype(create_info->db_type)) !=
- create_info->db_type)
- {
- create_info->db_type= new_db_type;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER(ER_WARN_USING_OTHER_HANDLER),
- ha_get_storage_engine(new_db_type),
- table_name);
- }
+ if (check_engine(thd, table_name, &create_info->db_type))
+ DBUG_RETURN(TRUE);
db_options= create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
db_options|=HA_OPTION_PACK_RECORD;
@@ -2590,28 +2583,33 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char *db= table->db;
char *table_name= table->table_name;
- char *src_db= thd->db;
+ char *src_db;
char *src_table= table_ident->table.str;
int err;
bool res= TRUE;
TABLE_LIST src_tables_list;
DBUG_ENTER("mysql_create_like_table");
+ src_db= table_ident->db.str ? table_ident->db.str : thd->db;
/*
Validate the source table
*/
if (table_ident->table.length > NAME_LEN ||
(table_ident->table.length &&
- check_table_name(src_table,table_ident->table.length)) ||
- table_ident->db.str && check_db_name((src_db= table_ident->db.str)))
+ check_table_name(src_table,table_ident->table.length)))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table);
DBUG_RETURN(TRUE);
}
+ if (!src_db || check_db_name(src_db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL");
+ DBUG_RETURN(-1);
+ }
bzero((gptr)&src_tables_list, sizeof(src_tables_list));
- src_tables_list.db= table_ident->db.str ? table_ident->db.str : thd->db;
- src_tables_list.table_name= table_ident->table.str;
+ src_tables_list.db= src_db;
+ src_tables_list.table_name= src_table;
if (lock_and_wait_for_table_name(thd, &src_tables_list))
goto err;
@@ -3121,16 +3119,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
old_db_type= table->s->db_type;
if (create_info->db_type == DB_TYPE_DEFAULT)
create_info->db_type= old_db_type;
- if ((new_db_type= ha_checktype(create_info->db_type)) !=
- create_info->db_type)
- {
- create_info->db_type= new_db_type;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER(ER_WARN_USING_OTHER_HANDLER),
- ha_get_storage_engine(new_db_type),
- new_name);
- }
+ if (check_engine(thd, new_name, &create_info->db_type))
+ DBUG_RETURN(TRUE);
+ new_db_type= create_info->db_type;
if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type= table->s->row_type;
@@ -3394,12 +3385,25 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
continue; // Field is removed
uint key_part_length=key_part->length;
if (cfield->field) // Not new field
- { // Check if sub key
- if (cfield->field->type() != FIELD_TYPE_BLOB &&
- (cfield->field->pack_length() == key_part_length ||
- cfield->length <= key_part_length /
- key_part->field->charset()->mbmaxlen))
- key_part_length=0; // Use whole field
+ {
+ /*
+ If the field can't have only a part used in a key according to its
+ new type, or should not be used partially according to its
+ previous type, or the field length is less than the key part
+ length, unset the key part length.
+
+ We also unset the key part length if it is the same as the
+ old field's length, so the whole new field will be used.
+
+ BLOBs may have cfield->length == 0, which is why we test it before
+ checking whether cfield->length < key_part_length (in chars).
+ */
+ if (!Field::type_can_have_key_part(cfield->field->type()) ||
+ !Field::type_can_have_key_part(cfield->sql_type) ||
+ cfield->field->field_length == key_part_length ||
+ (cfield->length && (cfield->length < key_part_length /
+ key_part->field->charset()->mbmaxlen)))
+ key_part_length= 0; // Use whole field
}
key_part_length /= key_part->field->charset()->mbmaxlen;
key_parts.push_back(new key_part_spec(cfield->field_name,
@@ -4117,3 +4121,24 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
table->table=0;
DBUG_RETURN(TRUE);
}
+
+static bool check_engine(THD *thd, const char *table_name,
+ enum db_type *new_engine)
+{
+ enum db_type req_engine= *new_engine;
+ bool no_substitution=
+ test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
+ if ((*new_engine=
+ ha_checktype(thd, req_engine, no_substitution, 1)) == DB_TYPE_UNKNOWN)
+ return TRUE;
+
+ if (req_engine != *new_engine)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_USING_OTHER_HANDLER,
+ ER(ER_WARN_USING_OTHER_HANDLER),
+ ha_get_storage_engine(*new_engine),
+ table_name);
+ }
+ return FALSE;
+}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 56401ced67c..f59d7fffe85 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -274,7 +274,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
all collations together for UNION.
*/
List_iterator_fast<Item> tp(types);
- Item_arena *arena= thd->current_arena;
+ Query_arena *arena= thd->current_arena;
Item *type;
while ((type= tp++))
@@ -308,7 +308,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (!item_list.elements)
{
Field **field;
- Item_arena *tmp_arena,backup;
+ Query_arena *tmp_arena,backup;
tmp_arena= thd->change_arena_if_needed(&backup);
for (field= table->field; *field; field++)
@@ -448,7 +448,7 @@ bool st_select_lex_unit::exec()
table->no_keyread=1;
}
res= sl->join->error;
- offset_limit_cnt= sl->offset_limit;
+ offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : 0;
if (!res)
{
examined_rows+= thd->examined_row_count;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 289bf9d28a3..0b351407c13 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -36,6 +36,61 @@ TYPELIB updatable_views_with_limit_typelib=
/*
+ Make a unique name for an anonymous view column
+ SYNOPSIS
+ target reference to the item for which a new name has to be made
+ item_list list of items within which we should check uniqueness of
+ the created name
+ last_element the last element of the list above
+
+ NOTE
+ Unique names are generated by adding 'My_exp_' to the old name of the
+ column. In case the name that was created this way already exists, we
+ add a numeric postfix to its end (i.e. "1") and increase the number
+ until the name becomes unique. If the generated name is longer than
+ NAME_LEN, it is truncated.
+*/
+
+static void make_unique_view_field_name(Item *target,
+ List<Item> &item_list,
+ Item *last_element)
+{
+ char *name= (target->orig_name ?
+ target->orig_name :
+ target->name);
+ uint name_len;
+ uint attempt= 0;
+ char buff[NAME_LEN+1];
+ for (;; attempt++)
+ {
+ Item *check;
+ List_iterator_fast<Item> itc(item_list);
+ bool ok= TRUE;
+
+ if (attempt)
+ name_len= my_snprintf(buff, NAME_LEN, "My_exp_%d_%s", attempt, name);
+ else
+ name_len= my_snprintf(buff, NAME_LEN, "My_exp_%s", name);
+
+ do
+ {
+ check= itc++;
+ if (check != target &&
+ my_strcasecmp(system_charset_info, buff, check->name) == 0)
+ {
+ ok= FALSE;
+ break;
+ }
+ } while (check != last_element);
+ if (ok)
+ break;
+ }
+
+ target->orig_name= target->name;
+ target->set_name(buff, name_len, system_charset_info);
+}
+
+/*
Creating/altering VIEW procedure
SYNOPSIS
@@ -240,24 +295,36 @@ bool mysql_create_view(THD *thd,
goto err;
}
while ((item= it++, name= nm++))
+ {
item->set_name(name->str, name->length, system_charset_info);
+ item->is_autogenerated_name= FALSE;
+ }
}
/* Test absence of duplicates names */
{
Item *item;
List_iterator_fast<Item> it(select_lex->item_list);
- it++;
while ((item= it++))
{
Item *check;
List_iterator_fast<Item> itc(select_lex->item_list);
+ /* treat underlying fields like set by user names */
+ if (item->real_item()->type() == Item::FIELD_ITEM)
+ item->is_autogenerated_name= FALSE;
while ((check= itc++) && check != item)
{
- if (strcmp(item->name, check->name) == 0)
+ if (my_strcasecmp(system_charset_info, item->name, check->name) == 0)
{
- my_error(ER_DUP_FIELDNAME, MYF(0), item->name);
- DBUG_RETURN(TRUE);
+ if (item->is_autogenerated_name)
+ make_unique_view_field_name(item, select_lex->item_list, item);
+ else if (check->is_autogenerated_name)
+ make_unique_view_field_name(check, select_lex->item_list, item);
+ else
+ {
+ my_error(ER_DUP_FIELDNAME, MYF(0), item->name);
+ DBUG_RETURN(TRUE);
+ }
}
}
}
@@ -579,7 +646,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
For now we assume that tables will not be changed during PS life (it
will be TRUE as far as we make new table cache).
*/
- Item_arena *arena= thd->current_arena, backup;
+ Query_arena *arena= thd->current_arena, backup;
if (arena->is_conventional())
arena= 0;
else
@@ -1000,8 +1067,9 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
we do not support updatable UNIONs in VIEW, so we can check just limit of
LEX::select_lex
*/
- if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT ||
- thd->lex->select_lex.select_limit == HA_POS_ERROR)
+ if ((!view->view && !view->belong_to_view) ||
+ thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->select_lex.select_limit == 0)
DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
table= view->table;
if (view->belong_to_view)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 88afab0bbe8..edca9cf3c5f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -52,7 +52,7 @@ const LEX_STRING null_lex_str={0,0};
ER_WARN_DEPRECATED_SYNTAX, \
ER(ER_WARN_DEPRECATED_SYNTAX), (A), (B));
-#define TEST_ASSERT(A) \
+#define YYERROR_UNLESS(A) \
if (!(A)) \
{ \
yyerror(ER(ER_SYNTAX_ERROR)); \
@@ -721,7 +721,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
signed_literal now_or_signed_literal opt_escape
sp_opt_default
simple_ident_nospvar simple_ident_q
- field_or_var
+ field_or_var limit_option
%type <item_num>
NUM_literal
@@ -914,11 +914,16 @@ deallocate:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "DEALLOCATE");
+ YYABORT;
+ }
lex->sql_command= SQLCOM_DEALLOCATE_PREPARE;
lex->prepared_stmt_name= $3;
};
@@ -934,11 +939,16 @@ prepare:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "PREPARE");
+ YYABORT;
+ }
lex->sql_command= SQLCOM_PREPARE;
lex->prepared_stmt_name= $2;
};
@@ -964,11 +974,16 @@ execute:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "EXECUTE");
+ YYABORT;
+ }
lex->sql_command= SQLCOM_EXECUTE;
lex->prepared_stmt_name= $2;
}
@@ -4014,7 +4029,7 @@ select_options:
/* empty*/
| select_option_list
{
- if (Select->options & SELECT_DISTINCT && Select->options2 & SELECT_ALL)
+ if (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL)
{
my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT");
YYABORT;
@@ -4054,7 +4069,7 @@ select_option:
{
Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
}
- | ALL { Select->options2|= SELECT_ALL; }
+ | ALL { Select->options|= SELECT_ALL; }
;
select_lock_type:
@@ -4092,7 +4107,10 @@ select_item:
if (add_item_to_list(YYTHD, $2))
YYABORT;
if ($4.str)
- $2->set_name($4.str,$4.length,system_charset_info);
+ {
+ $2->set_name($4.str, $4.length, system_charset_info);
+ $2->is_autogenerated_name= FALSE;
+ }
else if (!$2->name) {
char *str = $1;
if (str[-1] == '`')
@@ -4898,9 +4916,12 @@ udf_expr:
remember_name expr remember_end select_alias
{
if ($4.str)
- $2->set_name($4.str,$4.length,system_charset_info);
+ {
+ $2->set_name($4.str, $4.length, system_charset_info);
+ $2->is_autogenerated_name= FALSE;
+ }
else
- $2->set_name($1,(uint) ($3 - $1), YYTHD->charset());
+ $2->set_name($1, (uint) ($3 - $1), YYTHD->charset());
$$= $2;
}
;
@@ -5079,7 +5100,7 @@ table_ref:
;
join_table_list:
- derived_table_list { TEST_ASSERT($$=$1); }
+ derived_table_list { YYERROR_UNLESS($$=$1); }
;
/* Warning - may return NULL in case of incomplete SELECT */
@@ -5087,39 +5108,41 @@ derived_table_list:
table_ref { $$=$1; }
| derived_table_list ',' table_ref
{
- TEST_ASSERT($1 && ($$=$3));
+ YYERROR_UNLESS($1 && ($$=$3));
}
;
join_table:
- table_ref normal_join table_ref { TEST_ASSERT($1 && ($$=$3)); }
+ table_ref normal_join table_ref { YYERROR_UNLESS($1 && ($$=$3)); }
| table_ref STRAIGHT_JOIN table_factor
- { TEST_ASSERT($1 && ($$=$3)); $3->straight=1; }
+ { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; }
| table_ref normal_join table_ref ON expr
- { TEST_ASSERT($1 && ($$=$3)); add_join_on($3,$5); }
+ { YYERROR_UNLESS($1 && ($$=$3)); add_join_on($3,$5); }
+ | table_ref STRAIGHT_JOIN table_factor ON expr
+ { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; add_join_on($3,$5); }
| table_ref normal_join table_ref
USING
{
SELECT_LEX *sel= Select;
- TEST_ASSERT($1 && $3);
+ YYERROR_UNLESS($1 && $3);
sel->save_names_for_using_list($1, $3);
}
'(' using_list ')'
{ add_join_on($3,$7); $$=$3; }
| table_ref LEFT opt_outer JOIN_SYM table_ref ON expr
- { TEST_ASSERT($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+ { YYERROR_UNLESS($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
SELECT_LEX *sel= Select;
- TEST_ASSERT($1 && $5);
+ YYERROR_UNLESS($1 && $5);
sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
{ add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
- TEST_ASSERT($1 && $6);
+ YYERROR_UNLESS($1 && $6);
add_join_natural($1,$6);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
@@ -5127,7 +5150,7 @@ join_table:
| table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr
{
LEX *lex= Lex;
- TEST_ASSERT($1 && $5);
+ YYERROR_UNLESS($1 && $5);
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
add_join_on($$, $7);
@@ -5135,7 +5158,7 @@ join_table:
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{
SELECT_LEX *sel= Select;
- TEST_ASSERT($1 && $5);
+ YYERROR_UNLESS($1 && $5);
sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
@@ -5147,14 +5170,14 @@ join_table:
}
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
- TEST_ASSERT($1 && $6);
+ YYERROR_UNLESS($1 && $6);
add_join_natural($6,$1);
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
}
| table_ref NATURAL JOIN_SYM table_factor
- { TEST_ASSERT($1 && ($$=$4)); add_join_natural($1,$4); };
+ { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4); };
normal_join:
@@ -5183,7 +5206,7 @@ table_factor:
sel->add_joined_table($$);
}
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
- { TEST_ASSERT($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+ { YYERROR_UNLESS($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
| select_derived_init get_select_lex select_derived2
{
LEX *lex= Lex;
@@ -5564,8 +5587,8 @@ opt_limit_clause_init:
{
LEX *lex= Lex;
SELECT_LEX *sel= lex->current_select;
- sel->offset_limit= 0L;
- sel->select_limit= HA_POS_ERROR;
+ sel->offset_limit= 0;
+ sel->select_limit= 0;
}
| limit_clause {}
;
@@ -5580,21 +5603,21 @@ limit_clause:
;
limit_options:
- ulong_num
+ limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= $1;
- sel->offset_limit= 0L;
+ sel->offset_limit= 0;
sel->explicit_limit= 1;
}
- | ulong_num ',' ulong_num
+ | limit_option ',' limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= $3;
sel->offset_limit= $1;
sel->explicit_limit= 1;
}
- | ulong_num OFFSET_SYM ulong_num
+ | limit_option OFFSET_SYM limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= $1;
@@ -5602,18 +5625,23 @@ limit_options:
sel->explicit_limit= 1;
}
;
-
+limit_option:
+ param_marker
+ | ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); }
+ | LONG_NUM { $$= new Item_uint($1.str, $1.length); }
+ | NUM { $$= new Item_uint($1.str, $1.length); }
+ ;
delete_limit_clause:
/* empty */
{
LEX *lex=Lex;
- lex->current_select->select_limit= HA_POS_ERROR;
+ lex->current_select->select_limit= 0;
}
- | LIMIT ulonglong_num
+ | LIMIT limit_option
{
SELECT_LEX *sel= Select;
- sel->select_limit= (ha_rows) $2;
+ sel->select_limit= $2;
sel->explicit_limit= 1;
};
@@ -5669,7 +5697,8 @@ procedure_item:
if (add_proc_to_list(lex->thd, $2))
YYABORT;
if (!$2->name)
- $2->set_name($1,(uint) ((char*) lex->tok_end - $1), YYTHD->charset());
+ $2->set_name($1,(uint) ((char*) lex->tok_end - $1),
+ YYTHD->charset());
}
;
@@ -6091,9 +6120,24 @@ insert_update_elem:
simple_ident_nospvar equal expr_or_default
{
LEX *lex= Lex;
+ uint8 tmp= MY_ITEM_PREFER_1ST_TABLE;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($3))
YYABORT;
+ /*
+ INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY
+ UPDATE a= a + b1.b
+
+ Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items
+ to prevent find_field_in_tables() doing further item searching
+ if it finds item occurence in first table in insert_table_list.
+ This allows to avoid ambiguity in resolving 'a' field in
+ example above.
+ */
+ $1->walk(&Item::set_flags_processor,
+ (byte *) &tmp);
+ $3->walk(&Item::set_flags_processor,
+ (byte *) &tmp);
};
opt_low_priority:
@@ -6127,10 +6171,17 @@ single_multi:
| table_wild_list
{ mysql_init_multi_delete(Lex); }
FROM join_table_list where_clause
+ {
+ if (multi_delete_set_locks_and_link_aux_tables(Lex))
+ YYABORT;
+ }
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
USING join_table_list where_clause
- {}
+ {
+ if (multi_delete_set_locks_and_link_aux_tables(Lex))
+ YYABORT;
+ }
;
table_wild_list:
@@ -6873,7 +6924,7 @@ param_marker:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
Item_param *item= new Item_param((uint) (lex->tok_start -
(uchar *) thd->query));
@@ -7980,8 +8031,8 @@ handler:
LEX *lex=Lex;
lex->sql_command = SQLCOM_HA_READ;
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
- lex->current_select->select_limit= 1;
- lex->current_select->offset_limit= 0L;
+ lex->current_select->select_limit= new Item_int((int32) 1);
+ lex->current_select->offset_limit= 0;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
YYABORT;
}
@@ -8702,21 +8753,21 @@ xa: XA_SYM begin_or_start xid opt_join_or_resume
xid: text_string
{
- TEST_ASSERT($1->length() <= MAXGTRIDSIZE);
+ YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
YYABORT;
Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0);
}
| text_string ',' text_string
{
- TEST_ASSERT($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
YYABORT;
Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length());
}
| text_string ',' text_string ',' ulong_num
{
- TEST_ASSERT($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
YYABORT;
Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
diff --git a/sql/structs.h b/sql/structs.h
index 8f053f20776..03176b47360 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -20,6 +20,8 @@
struct st_table;
class Field;
+#define STRING_WITH_LEN(X) X, (sizeof(X)-1)
+
typedef struct st_lex_string
{
char *str;
diff --git a/sql/table.cc b/sql/table.cc
index 234fdbf5ef3..4ddaeeea248 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -163,7 +163,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
if (share->frm_version == FRM_VER_TRUE_VARCHAR -1 && head[33] == 5)
share->frm_version= FRM_VER_TRUE_VARCHAR;
- share->db_type= ha_checktype((enum db_type) (uint) *(head+3));
+ share->db_type= ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0);
share->db_create_options= db_create_options=uint2korr(head+30);
share->db_options_in_use= share->db_create_options;
share->mysql_version= uint4korr(head+51);
@@ -1344,8 +1344,8 @@ void append_unescaped(String *res, const char *pos, uint length)
/* Create a .frm file */
-File create_frm(register my_string name, uint reclength, uchar *fileinfo,
- HA_CREATE_INFO *create_info, uint keys)
+File create_frm(THD *thd, register my_string name, uint reclength,
+ uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys)
{
register File file;
ulong length;
@@ -1378,7 +1378,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
fileinfo[1]= 1;
fileinfo[2]= FRM_VER+3+ test(create_info->varchar);
- fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
+ fileinfo[3]= (uchar) ha_checktype(thd,create_info->db_type,0,0);
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
@@ -1640,7 +1640,7 @@ bool check_column_name(const char *name)
** Get type of table from .frm file
*/
-db_type get_table_type(const char *name)
+db_type get_table_type(THD *thd, const char *name)
{
File file;
uchar head[4];
@@ -1656,7 +1656,7 @@ db_type get_table_type(const char *name)
(head[2] != FRM_VER && head[2] != FRM_VER+1 &&
(head[2] < FRM_VER+3 || head[2] > FRM_VER+4)))
DBUG_RETURN(DB_TYPE_UNKNOWN);
- DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
+ DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0));
}
@@ -1929,7 +1929,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
(check_opt_type == VIEW_CHECK_CASCADED &&
ancestor->check_option))
{
- Item_arena *arena= thd->current_arena, backup;
+ Query_arena *arena= thd->current_arena, backup;
TABLE_LIST *tbl= this;
if (arena->is_conventional())
arena= 0; // For easier test
@@ -2019,7 +2019,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
/* full text function moving to current select */
if (view->select_lex.ftfunc_list->elements)
{
- Item_arena *arena= thd->current_arena, backup;
+ Query_arena *arena= thd->current_arena, backup;
if (arena->is_conventional())
arena= 0; // For easier test
else
@@ -2239,7 +2239,7 @@ const char *Field_iterator_view::name()
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<String>;
template class List_iterator<String>;
#endif
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a93f358c011..2ea79d92e37 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -113,7 +113,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
}
reclength=uint2korr(forminfo+266);
- if ((file=create_frm(file_name, reclength, fileinfo,
+ if ((file=create_frm(thd, file_name, reclength, fileinfo,
create_info, keys)) < 0)
{
my_free((gptr) screen_buff,MYF(0));