summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rwxr-xr-xsql/CMakeLists.txt2
-rw-r--r--sql/field.cc71
-rw-r--r--sql/field.h1
-rw-r--r--sql/filesort.cc5
-rw-r--r--sql/gstream.cc2
-rw-r--r--sql/ha_federated.cc11
-rw-r--r--sql/ha_heap.cc2
-rw-r--r--sql/ha_innodb.cc5
-rw-r--r--sql/ha_innodb.h3
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/item.cc87
-rw-r--r--sql/item.h10
-rw-r--r--sql/item_cmpfunc.cc59
-rw-r--r--sql/item_cmpfunc.h8
-rw-r--r--sql/item_func.cc23
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_geofunc.cc18
-rw-r--r--sql/item_geofunc.h7
-rw-r--r--sql/item_strfunc.cc35
-rw-r--r--sql/item_strfunc.h3
-rw-r--r--sql/item_sum.cc57
-rw-r--r--sql/item_timefunc.cc5
-rw-r--r--sql/item_timefunc.h11
-rw-r--r--sql/my_decimal.cc43
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/mysqld.cc48
-rw-r--r--sql/opt_range.cc24
-rw-r--r--sql/protocol.cc1
-rw-r--r--sql/set_var.cc22
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sp.cc13
-rw-r--r--sql/sp_head.cc31
-rw-r--r--sql/sp_head.h11
-rw-r--r--sql/sql_acl.cc144
-rw-r--r--sql/sql_acl.h5
-rw-r--r--sql/sql_base.cc17
-rw-r--r--sql/sql_cache.cc6
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_handler.cc68
-rw-r--r--sql/sql_insert.cc25
-rw-r--r--sql/sql_map.cc6
-rw-r--r--sql/sql_parse.cc44
-rw-r--r--sql/sql_select.cc106
-rw-r--r--sql/sql_select.h8
-rw-r--r--sql/sql_show.cc128
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_udf.cc4
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_view.cc14
-rw-r--r--sql/sql_yacc.yy410
-rw-r--r--sql/table.cc6
-rw-r--r--sql/table.h2
-rw-r--r--sql/udf_example.c35
-rw-r--r--sql/udf_example.def2
55 files changed, 1124 insertions, 557 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 0c4aeaf6043..84b042a91b1 100755
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -145,4 +145,4 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def)
ADD_DEPENDENCIES(udf_example strings)
-TARGET_LINK_LIBRARIES(udf_example wsock32)
+TARGET_LINK_LIBRARIES(udf_example strings wsock32)
diff --git a/sql/field.cc b/sql/field.cc
index 8191d885a27..86853389c64 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1356,15 +1356,25 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
void Field::make_field(Send_field *field)
{
- if (orig_table->s->table_cache_key && *(orig_table->s->table_cache_key))
+ if (orig_table && orig_table->s->table_cache_key &&
+ *(orig_table->s->table_cache_key))
{
field->org_table_name= orig_table->s->table_name;
field->db_name= orig_table->s->table_cache_key;
}
else
field->org_table_name= field->db_name= "";
- field->table_name= orig_table->alias;
- field->col_name= field->org_col_name= field_name;
+ if (orig_table)
+ {
+ field->table_name= orig_table->alias;
+ field->org_col_name= field_name;
+ }
+ else
+ {
+ field->table_name= "";
+ field->org_col_name= "";
+ }
+ field->col_name= field_name;
field->charsetnr= charset()->number;
field->length=field_length;
field->type=type();
@@ -5272,7 +5282,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
{
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
if (!error && (ret != MYSQL_TIMESTAMP_DATE) &&
- thd->count_cuted_fields != CHECK_FIELD_IGNORE)
+ (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
error= 3; // Datetime was cut (note)
}
@@ -5319,10 +5329,16 @@ int Field_newdate::store(longlong nr, bool unsigned_val)
else
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
+ if (!error && l_time.time_type != MYSQL_TIMESTAMP_DATE &&
+ (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
+ error= 3;
+
if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
- WARN_DATA_TRUNCATED,nr,MYSQL_TIMESTAMP_DATE, 1);
+ set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ error == 2 ?
+ ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED,
+ nr,MYSQL_TIMESTAMP_DATE, 1);
int3store(ptr,tmp);
return error;
@@ -5349,6 +5365,17 @@ int Field_newdate::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
}
+ if (!error && ltime->time_type != MYSQL_TIMESTAMP_DATE &&
+ (ltime->hour || ltime->minute || ltime->second || ltime->second_part))
+ {
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ String str(buff, sizeof(buff), &my_charset_latin1);
+ make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_NOTE,
+ WARN_DATA_TRUNCATED,
+ str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
+ error= 3;
+ }
}
else
{
@@ -7406,36 +7433,6 @@ uint Field_blob::max_packed_col_length(uint max_length)
#ifdef HAVE_SPATIAL
-uint Field_geom::get_key_image(char *buff, uint length, imagetype type)
-{
- char *blob;
- const char *dummy;
- MBR mbr;
- ulong blob_length= get_length(ptr);
- Geometry_buffer buffer;
- Geometry *gobj;
- const uint image_length= SIZEOF_STORED_DOUBLE*4;
-
- if (blob_length < SRID_SIZE)
- {
- bzero(buff, image_length);
- return image_length;
- }
- get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
- if (!gobj || gobj->get_mbr(&mbr, &dummy))
- bzero(buff, image_length);
- else
- {
- float8store(buff, mbr.xmin);
- float8store(buff + 8, mbr.xmax);
- float8store(buff + 16, mbr.ymin);
- float8store(buff + 24, mbr.ymax);
- }
- return image_length;
-}
-
-
void Field_geom::sql_type(String &res) const
{
CHARSET_INFO *cs= &my_charset_latin1;
diff --git a/sql/field.h b/sql/field.h
index 4fcdb50f8c7..8c01931fa21 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1326,7 +1326,6 @@ public:
int store(double nr);
int store(longlong nr, bool unsigned_val);
int store_decimal(const my_decimal *);
- uint get_key_image(char *buff,uint length,imagetype type);
uint size_of() const { return sizeof(*this); }
int reset(void) { return !maybe_null() || Field_blob::reset(); }
geometry_type get_geometry_type() { return geom_type; };
diff --git a/sql/filesort.cc b/sql/filesort.cc
index db73ede99b0..08ffa2211fa 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -534,7 +534,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
file->unlock_row();
/* It does not make sense to read more keys in case of a fatal error */
if (thd->net.report_error)
- DBUG_RETURN(HA_POS_ERROR);
+ break;
}
if (quick_select)
{
@@ -551,6 +551,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
file->ha_rnd_end();
}
+ if (thd->net.report_error)
+ DBUG_RETURN(HA_POS_ERROR);
+
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE)
{
diff --git a/sql/gstream.cc b/sql/gstream.cc
index 46e12b6ef3b..0c8011549f3 100644
--- a/sql/gstream.cc
+++ b/sql/gstream.cc
@@ -44,7 +44,7 @@ bool Gis_read_stream::get_next_word(LEX_STRING *res)
skip_space();
res->str= (char*) m_cur;
/* The following will also test for \0 */
- if (!my_isvar_start(&my_charset_bin, *m_cur))
+ if ((m_cur >= m_limit) || !my_isvar_start(&my_charset_bin, *m_cur))
return 1;
/*
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index d8ffd6c55f8..d7f2309657b 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -2528,7 +2528,12 @@ int ha_federated::info(uint flag)
status_query_string.length(0);
result= mysql_store_result(mysql);
- if (!result)
+
+ /*
+ We're going to use fields num. 4, 12 and 13 of the resultset,
+ so make sure we have these fields.
+ */
+ if (!result || (mysql_num_fields(result) < 14))
goto error;
if (!mysql_num_rows(result))
@@ -2557,9 +2562,9 @@ int ha_federated::info(uint flag)
data_file_length= records * mean_rec_length;
if (row[12] != NULL)
- update_time= (ha_rows) my_strtoll10(row[12], (char**) 0, &error);
+ update_time= (time_t) my_strtoll10(row[12], (char**) 0, &error);
if (row[13] != NULL)
- check_time= (ha_rows) my_strtoll10(row[13], (char**) 0, &error);
+ check_time= (time_t) my_strtoll10(row[13], (char**) 0, &error);
}
/*
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index bf807407df1..4b96e5b5744 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -175,7 +175,7 @@ void ha_heap::update_key_stats()
else
{
ha_rows hash_buckets= file->s->keydef[i].hash_buckets;
- uint no_records= hash_buckets ? file->s->records/hash_buckets : 2;
+ uint no_records= hash_buckets ? (uint) (file->s->records/hash_buckets) : 2;
if (no_records < 2)
no_records= 2;
key->rec_per_key[key->key_parts-1]= no_records;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 2d47c42cf1d..6b5e89848c3 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -174,6 +174,7 @@ my_bool innobase_file_per_table = FALSE;
my_bool innobase_locks_unsafe_for_binlog = FALSE;
my_bool innobase_rollback_on_timeout = FALSE;
my_bool innobase_create_status_file = FALSE;
+my_bool innobase_adaptive_hash_index = TRUE;
static char *internal_innobase_data_file_path = NULL;
@@ -1376,6 +1377,8 @@ innobase_init(void)
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
srv_use_checksums = (ibool) innobase_use_checksums;
+ srv_use_adaptive_hash_indexes = (ibool) innobase_adaptive_hash_index;
+
os_use_large_pages = (ibool) innobase_use_large_pages;
os_large_page_size = (ulint) innobase_large_page_size;
@@ -5474,7 +5477,7 @@ ha_innobase::info(
table->key_info[i].rec_per_key[j]=
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
- rec_per_key;
+ (ulong) rec_per_key;
}
index = dict_table_get_next_index_noninline(index);
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 585bc75fa36..3db983901b3 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -217,7 +217,8 @@ extern my_bool innobase_log_archive,
innobase_use_native_aio,
innobase_file_per_table, innobase_locks_unsafe_for_binlog,
innobase_rollback_on_timeout,
- innobase_create_status_file;
+ innobase_create_status_file,
+ innobase_adaptive_hash_index;
extern my_bool innobase_very_fast_shutdown; /* set this to 1 just before
calling innobase_end() if you want
InnoDB to shut down without
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 92fa9e405e1..ae0284fb202 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -1412,7 +1412,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows)
DBUG_ENTER("ha_myisam::start_bulk_insert");
THD *thd= current_thd;
ulong size= min(thd->variables.read_buff_size,
- table->s->avg_row_length*rows);
+ (ulong) (table->s->avg_row_length*rows));
DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
(ulong) rows, size));
diff --git a/sql/item.cc b/sql/item.cc
index 66379d5dcf9..7d1a1b20ac6 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -274,6 +274,7 @@ my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value)
if (get_date(&ltime, TIME_FUZZY_DATE))
{
my_decimal_set_zero(decimal_value);
+ null_value= 1; // set NULL, stop processing
return 0;
}
return date2my_decimal(&ltime, decimal_value);
@@ -700,10 +701,16 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
str++;
}
if (orig_len != length && !is_autogenerated_name)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES),
- str + length - orig_len);
-
+ {
+ if (length == 0)
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NAME_BECOMES_EMPTY, ER(ER_NAME_BECOMES_EMPTY),
+ str + length - orig_len);
+ else
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES),
+ str + length - orig_len);
+ }
}
if (!my_charset_same(cs, system_charset_info))
{
@@ -932,9 +939,12 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
int res;
THD *thd= field->table->in_use;
enum_check_fields tmp= thd->count_cuted_fields;
+ ulong sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
res= save_in_field(field, no_conversions);
thd->count_cuted_fields= tmp;
+ thd->variables.sql_mode= sql_mode;
return res;
}
@@ -4241,6 +4251,47 @@ bool Item::is_datetime()
}
+String *Item::check_well_formed_result(String *str, bool send_error)
+{
+ /* Check whether we got a well-formed string */
+ CHARSET_INFO *cs= str->charset();
+ int well_formed_error;
+ uint wlen= cs->cset->well_formed_len(cs,
+ str->ptr(), str->ptr() + str->length(),
+ str->length(), &well_formed_error);
+ if (wlen < str->length())
+ {
+ THD *thd= current_thd;
+ char hexbuf[7];
+ enum MYSQL_ERROR::enum_warning_level level;
+ uint diff= str->length() - wlen;
+ set_if_smaller(diff, 3);
+ octet2hex(hexbuf, str->ptr() + wlen, diff);
+ if (send_error)
+ {
+ my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
+ cs->csname, hexbuf);
+ return 0;
+ }
+ if ((thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ null_value= 1;
+ str= 0;
+ }
+ else
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ str->length(wlen);
+ }
+ push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
+ ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
+ }
+ return str;
+}
+
+
/*
Create a field to hold a string value from an item
@@ -4357,12 +4408,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
return new Field_blob(max_length, maybe_null, name, table,
collation.collation);
break; // Blob handled outside of case
+#ifdef HAVE_SPATIAL
case MYSQL_TYPE_GEOMETRY:
- return new Field_geom(max_length, maybe_null, name, table,
- (Field::geometry_type)
- ((type() == Item::TYPE_HOLDER) ?
- ((Item_type_holder *)this)->get_geometry_type() :
- ((Item_geometry_func *)this)->get_geometry_type()));
+ return new Field_geom(max_length, maybe_null,
+ name, table, get_geometry_type());
+#endif /* HAVE_SPATIAL */
}
}
@@ -4763,6 +4813,19 @@ warn:
}
+void Item_hex_string::print(String *str)
+{
+ char *end= (char*) str_value.ptr() + str_value.length(),
+ *ptr= end - min(str_value.length(), sizeof(longlong));
+ str->append("0x");
+ for (; ptr != end ; ptr++)
+ {
+ str->append(_dig_vec_lower[((uchar) *ptr) >> 4]);
+ str->append(_dig_vec_lower[((uchar) *ptr) & 0x0F]);
+ }
+}
+
+
bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const
{
if (arg->basic_const_item() && arg->type() == type())
@@ -6482,10 +6545,10 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
if (Field::result_merge_type(fld_type) == INT_RESULT)
decimals= 0;
prev_decimal_int_part= item->decimal_int_part();
+#ifdef HAVE_SPATIAL
if (item->field_type() == MYSQL_TYPE_GEOMETRY)
- geometry_type= (item->type() == Item::FIELD_ITEM) ?
- ((Item_field *)item)->get_geometry_type() :
- (Field::geometry_type)((Item_geometry_func *)item)->get_geometry_type();
+ geometry_type= item->get_geometry_type();
+#endif /* HAVE_SPATIAL */
}
diff --git a/sql/item.h b/sql/item.h
index 3c699c0eda3..b611c59b8f1 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -870,6 +870,9 @@ public:
*/
virtual bool result_as_longlong() { return FALSE; }
bool is_datetime();
+ virtual Field::geometry_type get_geometry_type() const
+ { return Field::GEOM_GEOMETRY; };
+ String *check_well_formed_result(String *str, bool send_error= 0);
};
@@ -1112,6 +1115,8 @@ public:
Item_name_const(Item *name_arg, Item *val):
value_item(val), name_item(name_arg)
{
+ if(!value_item->basic_const_item())
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
Item::maybe_null= TRUE;
}
@@ -1335,7 +1340,7 @@ public:
int fix_outer_field(THD *thd, Field **field, Item **reference);
virtual Item *update_value_transformer(byte *select_arg);
void print(String *str);
- Field::geometry_type get_geometry_type()
+ Field::geometry_type get_geometry_type() const
{
DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY);
return field->get_geometry_type();
@@ -1853,6 +1858,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
+ void print(String *str);
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
};
@@ -2637,7 +2643,7 @@ public:
Field *make_field_by_type(TABLE *table);
static uint32 display_length(Item *item);
static enum_field_types get_real_type(Item *);
- Field::geometry_type get_geometry_type() { return geometry_type; };
+ Field::geometry_type get_geometry_type() const { return geometry_type; };
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 86eb10d50b0..a9ad5ad675d 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -147,6 +147,36 @@ static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
}
+/**
+ @brief Aggregates field types from the array of items.
+
+ @param[in] items array of items to aggregate the type from
+ @paran[in] nitems number of items in the array
+
+ @details This function aggregates field types from the array of items.
+ Found type is supposed to be used later as the result field type
+ of a multi-argument function.
+ Aggregation itself is performed by the Field::field_type_merge()
+ function.
+
+ @note The term "aggregation" is used here in the sense of inferring the
+ result type of a function from its argument types.
+
+ @return aggregated field type.
+*/
+
+enum_field_types agg_field_type(Item **items, uint nitems)
+{
+ uint i;
+ if (!nitems || items[0]->result_type() == ROW_RESULT )
+ return (enum_field_types)-1;
+ enum_field_types res= items[0]->field_type();
+ for (i= 1 ; i < nitems ; i++)
+ res= Field::field_type_merge(res, items[i]->field_type());
+ return res;
+}
+
+
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
@@ -1990,10 +2020,20 @@ 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= (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);
+ unsigned_flag= args[0]->unsigned_flag && args[1]->unsigned_flag;
+
+ if (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT)
+ {
+ int len0= args[0]->max_length - args[0]->decimals
+ - (args[0]->unsigned_flag ? 0 : 1);
+
+ int len1= args[1]->max_length - args[1]->decimals
+ - (args[1]->unsigned_flag ? 0 : 1);
+
+ max_length= max(len0, len1) + decimals + (unsigned_flag ? 0 : 1);
+ }
+ else
+ max_length= max(args[0]->max_length, args[1]->max_length);
switch (hybrid_type) {
case STRING_RESULT:
@@ -2009,9 +2049,7 @@ Item_func_ifnull::fix_length_and_dec()
default:
DBUG_ASSERT(0);
}
- cached_field_type= args[0]->field_type();
- if (cached_field_type != args[1]->field_type())
- cached_field_type= Item_func::field_type();
+ cached_field_type= agg_field_type(args, 2);
}
@@ -2159,11 +2197,13 @@ Item_func_if::fix_length_and_dec()
{
cached_result_type= arg2_type;
collation.set(args[2]->collation.collation);
+ cached_field_type= args[2]->field_type();
}
else if (null2)
{
cached_result_type= arg1_type;
collation.set(args[1]->collation.collation);
+ cached_field_type= args[1]->field_type();
}
else
{
@@ -2177,6 +2217,7 @@ Item_func_if::fix_length_and_dec()
{
collation.set(&my_charset_bin); // Number
}
+ cached_field_type= agg_field_type(args + 1, 2);
}
if ((cached_result_type == DECIMAL_RESULT )
@@ -2556,7 +2597,7 @@ void Item_func_case::fix_length_and_dec()
agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV, 1))
return;
-
+ cached_field_type= agg_field_type(agg, nagg);
/*
Aggregate first expression and all THEN expression types
and collations when string comparison
@@ -2695,6 +2736,7 @@ my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value)
void Item_func_coalesce::fix_length_and_dec()
{
+ cached_field_type= agg_field_type(args, arg_count);
agg_result_type(&hybrid_type, args, arg_count);
switch (hybrid_type) {
case STRING_RESULT:
@@ -4253,6 +4295,7 @@ Item_func_regex::fix_fields(THD *thd, Item **ref)
if (args[1]->null_value)
{ // Will always return NULL
maybe_null=1;
+ fixed= 1;
return FALSE;
}
int error;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 8410c66b034..4d3df7aebf9 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -640,6 +640,7 @@ public:
class Item_func_coalesce :public Item_func_numhybrid
{
protected:
+ enum_field_types cached_field_type;
Item_func_coalesce(Item *a, Item *b) :Item_func_numhybrid(a, b) {}
public:
Item_func_coalesce(List<Item> &list) :Item_func_numhybrid(list) {}
@@ -652,13 +653,13 @@ public:
enum Item_result result_type () const { return hybrid_type; }
const char *func_name() const { return "coalesce"; }
table_map not_null_tables() const { return 0; }
+ enum_field_types field_type() const { return cached_field_type; }
};
class Item_func_ifnull :public Item_func_coalesce
{
protected:
- enum_field_types cached_field_type;
bool field_type_defined;
public:
Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {}
@@ -677,6 +678,7 @@ public:
class Item_func_if :public Item_func
{
enum Item_result cached_result_type;
+ enum_field_types cached_field_type;
public:
Item_func_if(Item *a,Item *b,Item *c)
:Item_func(a,b,c), cached_result_type(INT_RESULT)
@@ -686,6 +688,7 @@ public:
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
+ enum_field_types field_type() const { return cached_field_type; }
bool fix_fields(THD *, Item **);
void fix_length_and_dec();
uint decimal_precision() const;
@@ -722,6 +725,7 @@ class Item_func_case :public Item_func
uint ncases;
Item_result cmp_type;
DTCollation cmp_collation;
+ enum_field_types cached_field_type;
public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
@@ -749,6 +753,7 @@ public:
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
+ enum_field_types field_type() const { return cached_field_type; }
const char *func_name() const { return "case"; }
void print(String *str);
Item *find_item(String *str);
@@ -1382,6 +1387,7 @@ public:
bool subst_argument_checker(byte **arg) { return TRUE; }
Item *compile(Item_analyzer analyzer, byte **arg_p,
Item_transformer transformer, byte *arg_t);
+ enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index d03d497dfd0..22b0044242c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1380,7 +1380,11 @@ longlong Item_func_int_div::val_int()
void Item_func_int_div::fix_length_and_dec()
{
- max_length=args[0]->max_length - args[0]->decimals;
+ Item_result argtype= args[0]->result_type();
+ /* use precision ony for the data type it is applicable for and valid */
+ max_length=args[0]->max_length -
+ (argtype == DECIMAL_RESULT || argtype == INT_RESULT ?
+ args[0]->decimals : 0);
maybe_null=1;
unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
}
@@ -2243,6 +2247,7 @@ void Item_func_min_max::fix_length_and_dec()
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals,
unsigned_flag);
+ cached_field_type= agg_field_type(args, arg_count);
}
@@ -2924,7 +2929,8 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
String *res= arguments[i]->val_str(&buffers[i]);
if (arguments[i]->null_value)
continue;
- f_args.args[i]= (char*) res->ptr();
+ f_args.args[i]= (char*) res->c_ptr();
+ f_args.lengths[i]= res->length();
break;
}
case INT_RESULT:
@@ -5583,8 +5589,13 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
}
+
if (!m_sp->m_chistics->detistic)
- used_tables_cache |= RAND_TABLE_BIT;
+ {
+ used_tables_cache |= RAND_TABLE_BIT;
+ const_item_cache= FALSE;
+ }
+
DBUG_RETURN(res);
}
@@ -5592,6 +5603,10 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
void Item_func_sp::update_used_tables()
{
Item_func::update_used_tables();
+
if (!m_sp->m_chistics->detistic)
- used_tables_cache |= RAND_TABLE_BIT;
+ {
+ used_tables_cache |= RAND_TABLE_BIT;
+ const_item_cache= FALSE;
+ }
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 56b5e75652c..43221a18a5b 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -435,6 +435,7 @@ public:
longlong int_op();
my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "-"; }
+ virtual bool basic_const_item() const { return args[0]->basic_const_item(); }
void fix_length_and_dec();
void fix_num_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
@@ -692,7 +693,8 @@ class Item_func_min_max :public Item_func
/* An item used for issuing warnings while string to DATETIME conversion. */
Item *datetime_item;
THD *thd;
-
+protected:
+ enum_field_types cached_field_type;
public:
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE),
@@ -705,6 +707,7 @@ public:
enum Item_result result_type () const { return cmp_type; }
bool result_as_longlong() { return compare_as_dates; };
uint cmp_datetimes(ulonglong *value);
+ enum_field_types field_type() const { return cached_field_type; }
};
class Item_func_min :public Item_func_min_max
@@ -747,6 +750,8 @@ public:
collation= args[0]->collation;
max_length= args[0]->max_length;
decimals=args[0]->decimals;
+ /* The item could be a NULL constant. */
+ null_value= args[0]->null_value;
}
};
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 6c012277888..966cefea9fe 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -27,7 +27,7 @@
Field *Item_geometry_func::tmp_table_field(TABLE *t_arg)
{
return new Field_geom(max_length, maybe_null, name, t_arg,
- (Field::geometry_type) get_geometry_type());
+ get_geometry_type());
}
void Item_geometry_func::fix_length_and_dec()
@@ -38,10 +38,6 @@ void Item_geometry_func::fix_length_and_dec()
maybe_null= 1;
}
-int Item_geometry_func::get_geometry_type() const
-{
- return (int)Field::GEOM_GEOMETRY;
-}
String *Item_func_geometry_from_text::val_str(String *str)
{
@@ -160,9 +156,9 @@ String *Item_func_geometry_type::val_str(String *str)
}
-int Item_func_envelope::get_geometry_type() const
+Field::geometry_type Item_func_envelope::get_geometry_type() const
{
- return (int) Field::GEOM_POLYGON;
+ return Field::GEOM_POLYGON;
}
@@ -190,9 +186,9 @@ String *Item_func_envelope::val_str(String *str)
}
-int Item_func_centroid::get_geometry_type() const
+Field::geometry_type Item_func_centroid::get_geometry_type() const
{
- return (int) Field::GEOM_POINT;
+ return Field::GEOM_POINT;
}
@@ -330,9 +326,9 @@ err:
*/
-int Item_func_point::get_geometry_type() const
+Field::geometry_type Item_func_point::get_geometry_type() const
{
- return (int) Field::GEOM_POINT;
+ return Field::GEOM_POINT;
}
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 9c7970f9e53..e99510f762f 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -33,7 +33,6 @@ public:
void fix_length_and_dec();
enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
Field *tmp_table_field(TABLE *t_arg);
- virtual int get_geometry_type() const;
bool is_null() { (void) val_int(); return null_value; }
};
@@ -92,7 +91,7 @@ public:
Item_func_centroid(Item *a): Item_geometry_func(a) {}
const char *func_name() const { return "centroid"; }
String *val_str(String *);
- int get_geometry_type() const;
+ Field::geometry_type get_geometry_type() const;
};
class Item_func_envelope: public Item_geometry_func
@@ -101,7 +100,7 @@ public:
Item_func_envelope(Item *a): Item_geometry_func(a) {}
const char *func_name() const { return "envelope"; }
String *val_str(String *);
- int get_geometry_type() const;
+ Field::geometry_type get_geometry_type() const;
};
class Item_func_point: public Item_geometry_func
@@ -111,7 +110,7 @@ public:
Item_func_point(Item *a, Item *b, Item *srid): Item_geometry_func(a, b, srid) {}
const char *func_name() const { return "point"; }
String *val_str(String *);
- int get_geometry_type() const;
+ Field::geometry_type get_geometry_type() const;
};
class Item_func_spatial_decomp: public Item_geometry_func
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 0c11c9eece8..4e72f117869 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -38,36 +38,6 @@ C_MODE_END
String my_empty_string("",default_charset_info);
-String *Item_str_func::check_well_formed_result(String *str)
-{
- /* Check whether we got a well-formed string */
- CHARSET_INFO *cs= str->charset();
- int well_formed_error;
- uint wlen= cs->cset->well_formed_len(cs,
- str->ptr(), str->ptr() + str->length(),
- str->length(), &well_formed_error);
- if (wlen < str->length())
- {
- THD *thd= current_thd;
- char hexbuf[7];
- enum MYSQL_ERROR::enum_warning_level level;
- uint diff= str->length() - wlen;
- set_if_smaller(diff, 3);
- octet2hex(hexbuf, str->ptr() + wlen, diff);
- if (thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
- {
- level= MYSQL_ERROR::WARN_LEVEL_ERROR;
- null_value= 1;
- str= 0;
- }
- else
- level= MYSQL_ERROR::WARN_LEVEL_WARN;
- push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
- ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
- }
- return str;
-}
bool Item_str_func::fix_fields(THD *thd, Item **ref)
@@ -2229,11 +2199,13 @@ String *Item_func_char::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
str->length(0);
+ str->set_charset(collation.collation);
for (uint i=0 ; i < arg_count ; i++)
{
int32 num=(int32) args[i]->val_int();
if (!args[i]->null_value)
{
+ char char_num= (char) num;
if (num&0xFF000000L) {
str->append((char)(num>>24));
goto b2;
@@ -2243,10 +2215,9 @@ String *Item_func_char::val_str(String *str)
} else if (num&0xFF00L) {
b1: str->append((char)(num>>8));
}
- str->append((char) num);
+ str->append(&char_num, 1);
}
}
- str->set_charset(collation.collation);
str->realloc(str->length()); // Add end 0 (for Purify)
return check_well_formed_result(str);
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 6ca0b89a22b..04d1997e879 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -35,7 +35,6 @@ public:
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
- String *check_well_formed_result(String *str);
bool fix_fields(THD *thd, Item **ref);
};
@@ -535,7 +534,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- max_length= arg_count * collation.collation->mbmaxlen;
+ max_length= arg_count * 4;
}
const char *func_name() const { return "char"; }
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index fe9f58d84e1..30cbe872101 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -905,7 +905,9 @@ bool Item_sum_distinct::setup(THD *thd)
List<create_field> field_list;
create_field field_def; /* field definition */
DBUG_ENTER("Item_sum_distinct::setup");
- DBUG_ASSERT(tree == 0);
+ /* It's legal to call setup() more than once when in a subquery */
+ if (tree)
+ DBUG_RETURN(FALSE);
/*
Virtual table and the tree are created anew on each re-execution of
@@ -913,7 +915,7 @@ bool Item_sum_distinct::setup(THD *thd)
mem_root.
*/
if (field_list.push_back(&field_def))
- return TRUE;
+ DBUG_RETURN(TRUE);
null_value= maybe_null= 1;
quick_group= 0;
@@ -925,7 +927,7 @@ bool Item_sum_distinct::setup(THD *thd)
args[0]->unsigned_flag);
if (! (table= create_virtual_tmp_table(thd, field_list)))
- return TRUE;
+ DBUG_RETURN(TRUE);
/* XXX: check that the case of CHAR(0) works OK */
tree_key_length= table->s->reclength - table->s->null_bytes;
@@ -2443,6 +2445,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
/*
Setup can be called twice for ROLLUP items. This is a bug.
Please add DBUG_ASSERT(tree == 0) here when it's fixed.
+ It's legal to call setup() more than once when in a subquery
*/
if (tree || table || tmp_table_param)
return FALSE;
@@ -2464,6 +2467,23 @@ bool Item_sum_count_distinct::setup(THD *thd)
count_field_types(select_lex, tmp_table_param, list, 0);
tmp_table_param->force_copy_fields= force_copy_fields;
DBUG_ASSERT(table == 0);
+ /*
+ Make create_tmp_table() convert BIT columns to BIGINT.
+ This is needed because BIT fields store parts of their data in table's
+ null bits, and we don't have methods to compare two table records, which
+ is needed by Unique which is used when HEAP table is used.
+ */
+ {
+ List_iterator_fast<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*)item)->field->type() == FIELD_TYPE_BIT)
+ item->marker=4;
+ }
+ }
+
if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
0,
(select_lex->options | thd->options),
@@ -3290,15 +3310,34 @@ bool Item_func_group_concat::setup(THD *thd)
count_field_types(select_lex, tmp_table_param, all_fields, 0);
tmp_table_param->force_copy_fields= force_copy_fields;
DBUG_ASSERT(table == 0);
- /*
- Currently we have to force conversion of BLOB values to VARCHAR's
- if we are to store them in TREE objects used for ORDER BY and
- DISTINCT. This leads to truncation if the BLOB's size exceeds
- Field_varstring::MAX_SIZE.
- */
if (arg_count_order > 0 || distinct)
+ {
+ /*
+ Currently we have to force conversion of BLOB values to VARCHAR's
+ if we are to store them in TREE objects used for ORDER BY and
+ DISTINCT. This leads to truncation if the BLOB's size exceeds
+ Field_varstring::MAX_SIZE.
+ */
set_if_smaller(tmp_table_param->convert_blob_length,
Field_varstring::MAX_SIZE);
+
+ /*
+ Force the create_tmp_table() to convert BIT columns to INT
+ as we cannot compare two table records containg BIT fields
+ stored in the the tree used for distinct/order by.
+ Moreover we don't even save in the tree record null bits
+ where BIT fields store parts of their data.
+ */
+ List_iterator_fast<Item> li(all_fields);
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field->type() == FIELD_TYPE_BIT)
+ item->marker= 4;
+ }
+ }
+
/*
We have to create a temporary table to get descriptions of fields
(types, sizes and so on).
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index ae18e4786d7..c1fa9dce038 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1603,8 +1603,7 @@ bool Item_func_now::get_date(MYSQL_TIME *res,
int Item_func_now::save_in_field(Field *to, bool no_conversions)
{
to->set_notnull();
- to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
- return 0;
+ return to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
}
@@ -3310,7 +3309,7 @@ void Item_func_str_to_date::fix_length_and_dec()
String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
maybe_null= 1;
decimals=0;
- cached_field_type= MYSQL_TYPE_STRING;
+ cached_field_type= MYSQL_TYPE_DATETIME;
max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
format= args[1]->val_str(&format_str);
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 8e925a0156f..a5ecbc57e8d 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -844,7 +844,9 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
void fix_length_and_dec()
{
- Item_typecast_maybe_null::fix_length_and_dec();
+ collation.set(&my_charset_bin);
+ maybe_null= 1;
+ max_length= MAX_DATETIME_FULL_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
decimals= DATETIME_DEC;
}
@@ -962,7 +964,10 @@ class Item_func_maketime :public Item_str_timefunc
{
public:
Item_func_maketime(Item *a, Item *b, Item *c)
- :Item_str_timefunc(a, b ,c) {}
+ :Item_str_timefunc(a, b, c)
+ {
+ maybe_null= TRUE;
+ }
String *val_str(String *str);
const char *func_name() const { return "maketime"; }
};
@@ -1030,7 +1035,7 @@ class Item_func_str_to_date :public Item_str_func
bool const_item;
public:
Item_func_str_to_date(Item *a, Item *b)
- :Item_str_func(a, b)
+ :Item_str_func(a, b), const_item(false)
{}
String *val_str(String *str);
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 4ef2ae5cf95..31a5b09370a 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -68,24 +68,43 @@ int decimal_operation_results(int result)
}
-/*
- Converting decimal to string
-
- SYNOPSIS
- my_decimal2string()
-
- return
- E_DEC_OK
- E_DEC_TRUNCATED
- E_DEC_OVERFLOW
- E_DEC_OOM
+/**
+ @brief Converting decimal to string
+
+ @details Convert given my_decimal to String; allocate buffer as needed.
+
+ @param[in] mask what problems to warn on (mask of E_DEC_* values)
+ @param[in] d the decimal to print
+ @param[in] fixed_prec overall number of digits if ZEROFILL, 0 otherwise
+ @param[in] fixed_dec number of decimal places (if fixed_prec != 0)
+ @param[in] filler what char to pad with (ZEROFILL et al.)
+ @param[out] *str where to store the resulting string
+
+ @return error coce
+ @retval E_DEC_OK
+ @retval E_DEC_TRUNCATED
+ @retval E_DEC_OVERFLOW
+ @retval E_DEC_OOM
*/
int my_decimal2string(uint mask, const my_decimal *d,
uint fixed_prec, uint fixed_dec,
char filler, String *str)
{
- int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d));
+ /*
+ Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
+ holds true iff the type is also ZEROFILL, which in turn implies
+ UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
+ the user requested, plus one for a possible decimal point, plus
+ one if the user only wanted decimal places, but we force a leading
+ zero on them. Because the type is implicitly UNSIGNED, we do not
+ need to reserve a character for the sign. For all other cases,
+ fixed_prec will be 0, and my_decimal_string_length() will be called
+ instead to calculate the required size of the buffer.
+ */
+ int length= (fixed_prec
+ ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
+ : my_decimal_string_length(d));
int result;
if (str->alloc(length))
return check_result(mask, E_DEC_OOM);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 44eb5590a28..e2d78303763 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -245,8 +245,13 @@ MY_LOCALE *my_locale_by_number(uint number);
#define PRECISION_FOR_DOUBLE 53
#define PRECISION_FOR_FLOAT 24
+/*
+ Default time to wait before aborting a new client connection
+ that does not respond to "initial server greeting" timely
+*/
+#define CONNECT_TIMEOUT 10
+
/* The following can also be changed from the command line */
-#define CONNECT_TIMEOUT 5 // Do not wait long for connect
#define DEFAULT_CONCURRENCY 10
#define DELAYED_LIMIT 100 /* pause after xxx inserts */
#define DELAYED_QUEUE_SIZE 1000
@@ -726,7 +731,6 @@ pthread_handler_t handle_bootstrap(void *arg);
void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
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);
@@ -1220,6 +1224,7 @@ my_bool mysql_rm_tmp_tables(void);
/* item_func.cc */
extern bool check_reserved_words(LEX_STRING *name);
+extern enum_field_types agg_field_type(Item **items, uint nitems);
/* strfunc.cc */
ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 08c2b60fa79..c128aeaa47d 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1300,8 +1300,21 @@ static void set_ports()
{ // Get port if not from commandline
struct servent *serv_ptr;
mysqld_port= MYSQL_PORT;
+
+ /*
+ if builder specifically requested a default port, use that
+ (even if it coincides with our factory default).
+ only if they didn't do we check /etc/services (and, failing
+ on that, fall back to the factory default of 3306).
+ either default can be overridden by the environment variable
+ MYSQL_TCP_PORT, which in turn can be overridden with command
+ line options.
+ */
+
+#if MYSQL_PORT_DEFAULT == 0
if ((serv_ptr= getservbyname("mysql", "tcp")))
mysqld_port= ntohs((u_short) serv_ptr->s_port); /* purecov: inspected */
+#endif
if ((env = getenv("MYSQL_TCP_PORT")))
mysqld_port= (uint) atoi(env); /* purecov: inspected */
}
@@ -2130,7 +2143,7 @@ bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\
yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\
-the thread stack. Please read http://www.mysql.com/doc/en/Linux.html\n\n",
+the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
thread_count);
}
#endif /* HAVE_LINUXTHREADS */
@@ -2150,7 +2163,7 @@ Some pointers may be invalid and cause the dump to abort...\n");
fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id);
}
fprintf(stderr, "\
-The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\
+The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\
information that should help you find out what is causing the crash.\n");
fflush(stderr);
#endif /* HAVE_STACKTRACE */
@@ -4829,7 +4842,8 @@ enum options_mysqld
OPT_MERGE,
OPT_INNODB_ROLLBACK_ON_TIMEOUT,
OPT_SECURE_FILE_PRIV,
- OPT_KEEP_FILES_ON_CREATE
+ OPT_KEEP_FILES_ON_CREATE,
+ OPT_INNODB_ADAPTIVE_HASH_INDEX
};
@@ -5057,6 +5071,12 @@ Disable with --skip-innodb-checksums.", (gptr*) &innobase_use_checksums,
"The common part for InnoDB table spaces.", (gptr*) &innobase_data_home_dir,
(gptr*) &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
+ {"innodb_adaptive_hash_index", OPT_INNODB_ADAPTIVE_HASH_INDEX,
+ "Enable InnoDB adaptive hash index (enabled by default). "
+ "Disable with --skip-innodb-adaptive-hash-index.",
+ (gptr*) &innobase_adaptive_hash_index,
+ (gptr*) &innobase_adaptive_hash_index,
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"innodb_doublewrite", OPT_INNODB_DOUBLEWRITE, "Enable InnoDB doublewrite buffer (enabled by default). \
Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
(gptr*) &innobase_use_doublewrite, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
@@ -5400,7 +5420,13 @@ Disable with --skip-ndbcluster (will save memory).",
{"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.",
(gptr*) &pidfile_name_ptr, (gptr*) &pidfile_name_ptr, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port,
+ {"port", 'P', "Port number to use for connection or 0 for default to, in "
+ "order of preference, my.cnf, $MYSQL_TCP_PORT, "
+#if MYSQL_PORT_DEFAULT == 0
+ "/etc/services, "
+#endif
+ "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
+ (gptr*) &mysqld_port,
(gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"port-open-timeout", OPT_PORT_OPEN_TIMEOUT,
"Maximum time in seconds to wait for the port to become free. "
@@ -5829,7 +5855,7 @@ log and this option does nothing anymore.",
"The size of the buffer that is used for full joins.",
(gptr*) &global_system_variables.join_buff_size,
(gptr*) &max_system_variables.join_buff_size, 0, GET_ULONG,
- REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD,
+ REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, UINT_MAX32, MALLOC_OVERHEAD,
IO_SIZE, 0},
{"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE,
"Don't overwrite stale .MYD and .MYI even if no directory is specified.",
@@ -5998,7 +6024,7 @@ The minimum value for this variable is 4096.",
"The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.",
(gptr*) &global_system_variables.myisam_sort_buff_size,
(gptr*) &max_system_variables.myisam_sort_buff_size, 0,
- GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 8192*1024, 4, UINT_MAX32, 0, 1, 0},
{"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
"Specifies how MyISAM index statistics collection code should threat NULLs. "
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
@@ -6091,7 +6117,7 @@ The minimum value for this variable is 4096.",
"Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.",
(gptr*) &global_system_variables.read_buff_size,
(gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
- 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, SSIZE_MAX, MALLOC_OVERHEAD, IO_SIZE,
+ 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE,
0},
{"read_only", OPT_READONLY,
"Make all non-temporary tables read-only, with the exception for replication (slave) threads and users with the SUPER privilege",
@@ -6103,12 +6129,12 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.read_rnd_buff_size,
(gptr*) &max_system_variables.read_rnd_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD,
- SSIZE_MAX, MALLOC_OVERHEAD, IO_SIZE, 0},
+ INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0},
{"record_buffer", OPT_RECORD_BUFFER,
"Alias for read_buffer_size",
(gptr*) &global_system_variables.read_buff_size,
(gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
- 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, SSIZE_MAX, MALLOC_OVERHEAD, IO_SIZE, 0},
+ 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0},
#ifdef HAVE_REPLICATION
{"relay_log_purge", OPT_RELAY_LOG_PURGE,
"0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.",
@@ -6144,7 +6170,7 @@ The minimum value for this variable is 4096.",
"Each thread that needs to do a sort allocates a buffer of this size.",
(gptr*) &global_system_variables.sortbuff_size,
(gptr*) &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
- MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD,
+ MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, UINT_MAX32, MALLOC_OVERHEAD,
1, 0},
#ifdef HAVE_BERKELEY_DB
{"sync-bdb-logs", OPT_BDB_SYNC,
@@ -7146,6 +7172,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
have_merge_db= SHOW_OPTION_YES;
else
have_merge_db= SHOW_OPTION_DISABLED;
+ break;
#ifdef HAVE_BERKELEY_DB
case OPT_BDB_NOSYNC:
/* Deprecated option */
@@ -7285,6 +7312,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
fprintf(stderr, "Unknown option to tc-heuristic-recover: %s\n",argument);
exit(1);
}
+ break;
}
case OPT_MYISAM_STATS_METHOD:
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 04e2816d553..969777d4792 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2206,7 +2206,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
if (param->table->file->primary_key_is_clustered())
{
result= param->table->file->read_time(param->table->s->primary_key,
- records, records);
+ (uint)records, records);
}
else
{
@@ -2414,7 +2414,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
/* Add Unique operations cost */
unique_calc_buff_size=
- Unique::get_cost_calc_buff_size(non_cpk_scan_records,
+ Unique::get_cost_calc_buff_size((ulong)non_cpk_scan_records,
param->table->file->ref_length,
param->thd->variables.sortbuff_size);
if (param->imerge_cost_buff_size < unique_calc_buff_size)
@@ -2426,7 +2426,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
}
imerge_cost +=
- Unique::get_use_cost(param->imerge_cost_buff, non_cpk_scan_records,
+ Unique::get_use_cost(param->imerge_cost_buff, (uint)non_cpk_scan_records,
param->table->file->ref_length,
param->thd->variables.sortbuff_size);
DBUG_PRINT("info",("index_merge total cost: %g (wanted: less then %g)",
@@ -2765,7 +2765,7 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param)
info->is_covering= FALSE;
info->index_scan_costs= 0.0;
info->index_records= 0;
- info->out_rows= param->table->file->records;
+ info->out_rows= (double) param->table->file->records;
bitmap_clear_all(&info->covered_fields);
return info;
}
@@ -6757,7 +6757,7 @@ int QUICK_RANGE_SELECT::reset()
if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER)
{
mrange_bufsiz= min(multi_range_bufsiz,
- (QUICK_SELECT_I::records + 1)* head->s->reclength);
+ ((uint)QUICK_SELECT_I::records + 1)* head->s->reclength);
while (mrange_bufsiz &&
! my_multi_malloc(MYF(MY_WME),
@@ -8359,7 +8359,7 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
bool have_min, bool have_max,
double *read_cost, ha_rows *records)
{
- uint table_records;
+ ha_rows table_records;
uint num_groups;
uint num_blocks;
uint keys_per_block;
@@ -8376,14 +8376,14 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
keys_per_block= (table->file->block_size / 2 /
(index_info->key_length + table->file->ref_length)
+ 1);
- num_blocks= (table_records / keys_per_block) + 1;
+ num_blocks= (uint)(table_records / keys_per_block) + 1;
/* Compute the number of keys in a group. */
keys_per_group= index_info->rec_per_key[group_key_parts - 1];
if (keys_per_group == 0) /* If there is no statistics try to guess */
/* each group contains 10% of all records */
- keys_per_group= (table_records / 10) + 1;
- num_groups= (table_records / keys_per_group) + 1;
+ keys_per_group= (uint)(table_records / 10) + 1;
+ num_groups= (uint)(table_records / keys_per_group) + 1;
/* Apply the selectivity of the quick select for group prefixes. */
if (range_tree && (quick_prefix_records != HA_POS_ERROR))
@@ -8427,9 +8427,9 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
*records= num_groups;
DBUG_PRINT("info",
- ("table rows: %u keys/block: %u keys/group: %u result rows: %lu blocks: %u",
- table_records, keys_per_block, keys_per_group, (ulong) *records,
- num_blocks));
+ ("table rows: %lu keys/block: %u keys/group: %u result rows: %lu blocks: %u",
+ (ulong)table_records, keys_per_block, keys_per_group,
+ (ulong) *records, num_blocks));
DBUG_VOID_RETURN;
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index ced6d78519a..2bdbe83eea1 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -824,6 +824,7 @@ bool Protocol_simple::store(const char *from, uint length,
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
field_types[field_pos] == MYSQL_TYPE_BIT ||
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDATE ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index e1246617d84..a128529fcc7 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -784,7 +784,6 @@ sys_var *sys_variables[]=
&sys_innodb_max_purge_lag,
&sys_innodb_table_locks,
&sys_innodb_support_xa,
- &sys_innodb_max_purge_lag,
&sys_innodb_autoextend_increment,
&sys_innodb_sync_spin_loops,
&sys_innodb_concurrency_tickets,
@@ -901,6 +900,7 @@ struct show_var_st init_vars[]= {
{sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS},
{"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR},
{"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR},
+ {"innodb_adaptive_hash_index", (char*) &innobase_adaptive_hash_index, SHOW_MY_BOOL},
{"innodb_doublewrite", (char*) &innobase_use_doublewrite, SHOW_MY_BOOL},
{sys_innodb_fast_shutdown.name,(char*) &sys_innodb_fast_shutdown, SHOW_SYS},
{"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
@@ -1040,6 +1040,9 @@ struct show_var_st init_vars[]= {
{sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
{sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
#ifdef HAVE_REPLICATION
+ {"relay_log" , (char*) &opt_relay_logname, SHOW_CHAR_PTR},
+ {"relay_log_index", (char*) &opt_relaylog_index_name, SHOW_CHAR_PTR},
+ {"relay_log_info_file", (char*) &relay_log_info_file, SHOW_CHAR_PTR},
{sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
{"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG},
#endif
@@ -1532,16 +1535,31 @@ bool sys_var_thd_ulong::check(THD *thd, set_var *var)
bool sys_var_thd_ulong::update(THD *thd, set_var *var)
{
ulonglong tmp= var->save_result.ulonglong_value;
+ char buf[22];
+ bool truncated= false;
/* Don't use bigger value than given with --maximum-variable-name=.. */
if ((ulong) tmp > max_system_variables.*offset)
+ {
+ truncated= true;
+ llstr(tmp, buf);
tmp= max_system_variables.*offset;
+ }
#if SIZEOF_LONG == 4
/* Avoid overflows on 32 bit systems */
if (tmp > (ulonglong) ~(ulong) 0)
+ {
+ truncated= true;
+ llstr(tmp, buf);
tmp= ((ulonglong) ~(ulong) 0);
+ }
#endif
+ if (truncated)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), name,
+ buf);
if (option_limits)
tmp= (ulong) getopt_ull_limit_value(tmp, option_limits);
@@ -1749,7 +1767,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
&not_used));
if (error_len)
{
- strmake(buff, error, min(sizeof(buff), error_len));
+ strmake(buff, error, min(sizeof(buff) - 1, error_len));
goto err;
}
}
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 6d4ca33ccc7..709cd1fc0a9 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5637,3 +5637,5 @@ ER_ADMIN_WRONG_MRG_TABLE
eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist"
ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT
eng "Too high level of nesting for select"
+ER_NAME_BECOMES_EMPTY
+ eng "Name '%-.64s' has become ''"
diff --git a/sql/sp.cc b/sql/sp.cc
index 75d6fa4618f..0b84e1ad07f 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1405,12 +1405,12 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
{
Sroutine_hash_entry *rn=
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
- key->length);
+ key->length + 1);
if (!rn) // OOM. Error will be reported using fatal_error().
return FALSE;
rn->key.length= key->length;
rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
- memcpy(rn->key.str, key->str, key->length);
+ memcpy(rn->key.str, key->str, key->length + 1);
my_hash_insert(&lex->sroutines, (byte *)rn);
lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
rn->belong_to_view= belong_to_view;
@@ -1595,7 +1595,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
for (Sroutine_hash_entry *rt= start; rt; rt= rt->next)
{
- sp_name name(rt->key.str, rt->key.length);
+ sp_name name(thd, rt->key.str, rt->key.length);
int type= rt->key.str[0];
sp_head *sp;
@@ -1603,13 +1603,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
&thd->sp_func_cache : &thd->sp_proc_cache),
&name)))
{
- name.m_name.str= strchr(name.m_qname.str, '.');
- name.m_db.length= name.m_name.str - name.m_qname.str;
- name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
- name.m_db.length);
- name.m_name.str+= 1;
- name.m_name.length= name.m_qname.length - name.m_db.length - 1;
-
switch ((ret= db_find_routine(thd, type, &name, &sp)))
{
case SP_OK:
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 5ad6625efb8..69dda9ec1e8 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -369,17 +369,42 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
*
*/
+sp_name::sp_name(THD *thd, char *key, uint key_len)
+{
+ m_sroutines_key.str= key;
+ m_sroutines_key.length= key_len;
+ m_qname.str= ++key;
+ m_qname.length= key_len - 1;
+ if ((m_name.str= strchr(m_qname.str, '.')))
+ {
+ m_db.length= m_name.str - key;
+ m_db.str= strmake_root(thd->mem_root, key, m_db.length);
+ m_name.str++;
+ m_name.length= m_qname.length - m_db.length - 1;
+ }
+ else
+ {
+ m_name.str= m_qname.str;
+ m_name.length= m_qname.length;
+ m_db.str= 0;
+ m_db.length= 0;
+ }
+ m_explicit_name= false;
+}
+
void
sp_name::init_qname(THD *thd)
{
- m_sroutines_key.length= m_db.length + m_name.length + 2;
+ const uint dot= !!m_db.length;
+ /* m_sroutines format: m_type + [database + dot] + name + nul */
+ m_sroutines_key.length= 1 + m_db.length + dot + m_name.length;
if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1)))
return;
m_qname.length= m_sroutines_key.length - 1;
m_qname.str= m_sroutines_key.str + 1;
- sprintf(m_qname.str, "%.*s.%.*s",
+ sprintf(m_qname.str, "%.*s%.*s%.*s",
m_db.length, (m_db.length ? m_db.str : ""),
- m_name.length, m_name.str);
+ dot, ".", m_name.length, m_name.str);
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index ebe40ce9c87..7d042367985 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -72,16 +72,7 @@ public:
Creates temporary sp_name object from key, used mainly
for SP-cache lookups.
*/
- sp_name(char *key, uint key_len)
- {
- m_sroutines_key.str= key;
- m_sroutines_key.length= key_len;
- m_name.str= m_qname.str= key + 1;
- m_name.length= m_qname.length= key_len - 1;
- m_db.str= 0;
- m_db.length= 0;
- m_explicit_name= false;
- }
+ sp_name(THD *thd, char *key, uint key_len);
// Init. the qualified name from the db and name.
void init_qname(THD *thd); // thd for memroot allocation
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index f9bd2c6ba0d..e62d0f40abf 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1132,7 +1132,7 @@ static void acl_update_db(const char *user, const char *host, const char *db,
{
if (!acl_db->host.hostname && !host[0] ||
acl_db->host.hostname &&
- !my_strcasecmp(system_charset_info, host, acl_db->host.hostname))
+ !strcmp(host, acl_db->host.hostname))
{
if (!acl_db->db && !db[0] ||
acl_db->db && !strcmp(db,acl_db->db))
@@ -3835,50 +3835,83 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
}
-bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
- const char* db_name, const char *table_name,
- Field_iterator *fields)
+/**
+ @brief check if a query can access a set of columns
+
+ @param thd the current thread
+ @param want_access_arg the privileges requested
+ @param fields an iterator over the fields of a table reference.
+ @return Operation status
+ @retval 0 Success
+ @retval 1 Falure
+ @details This function walks over the columns of a table reference
+ The columns may originate from different tables, depending on the kind of
+ table reference, e.g. join.
+ For each table it will retrieve the grant information and will use it
+ to check the required access privileges for the fields requested from it.
+*/
+bool check_grant_all_columns(THD *thd, ulong want_access_arg,
+ Field_iterator_table_ref *fields)
{
Security_context *sctx= thd->security_ctx;
- GRANT_TABLE *grant_table;
- GRANT_COLUMN *grant_column;
+ ulong want_access= want_access_arg;
+ const char *table_name= NULL;
- want_access &= ~grant->privilege;
- if (!want_access)
- return 0; // Already checked
- if (!grant_option)
- goto err2;
+ if (grant_option)
+ {
+ const char* db_name;
+ GRANT_INFO *grant;
+ /* Initialized only to make gcc happy */
+ GRANT_TABLE *grant_table= NULL;
- rw_rdlock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
- /* reload table if someone has modified any grants */
+ for (; !fields->end_of_fields(); fields->next())
+ {
+ const char *field_name= fields->name();
- if (grant->version != grant_version)
- {
- grant->grant_table=
- table_hash_search(sctx->host, sctx->ip, db_name,
- sctx->priv_user,
- table_name, 0); /* purecov: inspected */
- grant->version= grant_version; /* purecov: inspected */
- }
- /* The following should always be true */
- if (!(grant_table= grant->grant_table))
- goto err; /* purecov: inspected */
+ if (table_name != fields->table_name())
+ {
+ table_name= fields->table_name();
+ db_name= fields->db_name();
+ grant= fields->grant();
+ /* get a fresh one for each table */
+ want_access= want_access_arg & ~grant->privilege;
+ if (want_access)
+ {
+ /* reload table if someone has modified any grants */
+ if (grant->version != grant_version)
+ {
+ grant->grant_table=
+ table_hash_search(sctx->host, sctx->ip, db_name,
+ sctx->priv_user,
+ table_name, 0); /* purecov: inspected */
+ grant->version= grant_version; /* purecov: inspected */
+ }
- for (; !fields->end_of_fields(); fields->next())
- {
- const char *field_name= fields->name();
- grant_column= column_hash_search(grant_table, field_name,
- (uint) strlen(field_name));
- if (!grant_column || (~grant_column->rights & want_access))
- goto err;
- }
- rw_unlock(&LOCK_grant);
- return 0;
+ grant_table= grant->grant_table;
+ DBUG_ASSERT (grant_table);
+ }
+ }
+
+ if (want_access)
+ {
+ GRANT_COLUMN *grant_column=
+ column_hash_search(grant_table, field_name,
+ (uint) strlen(field_name));
+ if (!grant_column || (~grant_column->rights & want_access))
+ goto err;
+ }
+ }
+ rw_unlock(&LOCK_grant);
+ return 0;
err:
- rw_unlock(&LOCK_grant);
-err2:
+ rw_unlock(&LOCK_grant);
+ }
+ else
+ table_name= fields->table_name();
+
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
@@ -4344,6 +4377,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!(host=acl_db->host.hostname))
host= "";
+ /*
+ We do not make SHOW GRANTS case-sensitive here (like REVOKE),
+ but make it case-insensitive because that's the way they are
+ actually applied, and showing fewer privileges than are applied
+ would be wrong from a security point of view.
+ */
+
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
@@ -4379,8 +4419,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
db.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
db.append (STRING_WITH_LEN("'@'"));
- db.append(lex_user->host.str, lex_user->host.length,
- system_charset_info);
+ // host and lex_user->host are equal except for case
+ db.append(host, strlen(host), system_charset_info);
db.append ('\'');
if (want_access & GRANT_ACL)
db.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
@@ -4407,6 +4447,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!(host= grant_table->host.hostname))
host= "";
+ /*
+ We do not make SHOW GRANTS case-sensitive here (like REVOKE),
+ but make it case-insensitive because that's the way they are
+ actually applied, and showing fewer privileges than are applied
+ would be wrong from a security point of view.
+ */
+
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
@@ -4487,8 +4534,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
global.append(STRING_WITH_LEN("'@'"));
- global.append(lex_user->host.str,lex_user->host.length,
- system_charset_info);
+ // host and lex_user->host are equal except for case
+ global.append(host, strlen(host), system_charset_info);
global.append('\'');
if (table_access & GRANT_ACL)
global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
@@ -4543,6 +4590,13 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
if (!(host= grant_proc->host.hostname))
host= "";
+ /*
+ We do not make SHOW GRANTS case-sensitive here (like REVOKE),
+ but make it case-insensitive because that's the way they are
+ actually applied, and showing fewer privileges than are applied
+ would be wrong from a security point of view.
+ */
+
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
@@ -4586,8 +4640,8 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
global.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
global.append(STRING_WITH_LEN("'@'"));
- global.append(lex_user->host.str,lex_user->host.length,
- system_charset_info);
+ // host and lex_user->host are equal except for case
+ global.append(host, strlen(host), system_charset_info);
global.append('\'');
if (proc_access & GRANT_ACL)
global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
@@ -5541,7 +5595,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ !strcmp(lex_user->host.str, host))
{
if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~(ulong)0, 1))
{
@@ -5572,7 +5626,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ !strcmp(lex_user->host.str, host))
{
if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
grant_table->db,
@@ -5618,7 +5672,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ !strcmp(lex_user->host.str, host))
{
if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
grant_proc->db,
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index d08f2663af5..b2007ccdf47 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -205,9 +205,8 @@ bool check_grant_column (THD *thd, GRANT_INFO *grant,
const char *name, uint length, Security_context *sctx);
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
const char *name, uint length);
-bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
- const char* db_name, const char *table_name,
- Field_iterator *fields);
+bool check_grant_all_columns(THD *thd, ulong want_access,
+ Field_iterator_table_ref *fields);
bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_error);
bool check_grant_db(THD *thd,const char *db);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 289924ff418..b97ba45e18f 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1745,7 +1745,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
DBUG_RETURN(0);
}
- /* close handler tables which are marked for flush */
+ /*
+ In order for the back off and re-start process to work properly,
+ handler tables having old versions (due to FLUSH TABLES or pending
+ name-lock) MUST be closed. This is specially important if a name-lock
+ is pending for any table of the handler_tables list, otherwise a
+ deadlock may occur.
+ */
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
@@ -1810,6 +1816,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->db_stat == 0 signals wait_for_locked_table_names
that the tables in question are not used any more. See
table_is_used call for details.
+
+ Notice that HANDLER tables were already taken care of by
+ the earlier call to mysql_ha_flush() in this same critical
+ section.
*/
close_old_data_files(thd,thd->open_tables,0,0);
/*
@@ -5414,10 +5424,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
!any_privileges)
{
field_iterator.set(tables);
- if (check_grant_all_columns(thd, SELECT_ACL, field_iterator.grant(),
- field_iterator.db_name(),
- field_iterator.table_name(),
- &field_iterator))
+ if (check_grant_all_columns(thd, SELECT_ACL, &field_iterator))
DBUG_RETURN(TRUE);
}
#endif
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 9a29350880e..8c868971911 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1032,12 +1032,14 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
Query_cache_query_flags flags;
+#ifndef __WIN__
const uint spin_treshold= 50000;
const double lock_time_treshold= 0.1; /* Time in seconds */
uint spin_count= 0;
int lock_status= 0;
ulong new_time= 0;
ulong stop_time= 0;
+#endif
DBUG_ENTER("Query_cache::send_result_to_client");
@@ -1085,6 +1087,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
}
}
+#ifdef __WIN__
+ STRUCT_LOCK(&structure_guard_mutex);
+#else
stop_time= my_clock()+(ulong)lock_time_treshold*CLOCKS_PER_SEC;
while ((lock_status= pthread_mutex_trylock(&structure_guard_mutex)) == EBUSY
&& spin_count < spin_treshold
@@ -1107,6 +1112,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
thd->lex->safe_to_cache_query= FALSE;
goto err;
}
+#endif
if (query_cache_size == 0 || flush_in_progress)
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b67f63778dc..4a98a044e25 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2241,8 +2241,11 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
void mark_transaction_to_rollback(THD *thd, bool all)
{
- thd->is_fatal_sub_stmt_error= TRUE;
- thd->transaction_rollback_request= all;
+ if (thd)
+ {
+ thd->is_fatal_sub_stmt_error= TRUE;
+ thd->transaction_rollback_request= all;
+ }
}
/***************************************************************************
Handling of XA id cacheing
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4fac86dc405..e6d65f3133a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2029,7 +2029,7 @@ class select_insert :public select_result_interceptor {
ulonglong last_insert_id;
COPY_INFO info;
bool insert_into_view;
-
+ bool is_bulk_insert_mode;
select_insert(TABLE_LIST *table_list_par,
TABLE *table_par, List<Item> *fields_par,
List<Item> *update_fields, List<Item> *update_values,
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 9aefa71647e..822f2b2c419 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -65,11 +65,6 @@
static enum enum_ha_read_modes rkey_to_rnext[]=
{ RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
-#define HANDLER_TABLES_HACK(thd) { \
- TABLE *tmp=thd->open_tables; \
- thd->open_tables=thd->handler_tables; \
- thd->handler_tables=tmp; }
-
static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags);
@@ -187,6 +182,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter;
int error;
+ TABLE *backup_open_tables;
DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
tables->db, tables->table_name, tables->alias,
@@ -216,17 +212,39 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
}
/*
+ Save and reset the open_tables list so that open_tables() won't
+ be able to access (or know about) the previous list. And on return
+ from open_tables(), thd->open_tables will contain only the opened
+ table.
+
+ The thd->handler_tables list is kept as-is to avoid deadlocks if
+ open_table(), called by open_tables(), needs to back-off because
+ of a pending name-lock on the table being opened.
+
+ See open_table() back-off comments for more details.
+ */
+ backup_open_tables= thd->open_tables;
+ thd->open_tables= NULL;
+
+ /*
open_tables() will set 'tables->table' if successful.
It must be NULL for a real open when calling open_tables().
*/
DBUG_ASSERT(! tables->table);
- HANDLER_TABLES_HACK(thd);
/* for now HANDLER can be used only for real TABLES */
tables->required_type= FRMTYPE_TABLE;
error= open_tables(thd, &tables, &counter, 0);
- HANDLER_TABLES_HACK(thd);
+ /* restore the state and merge the opened table into handler_tables list */
+ if (thd->open_tables)
+ {
+ thd->open_tables->next= thd->handler_tables;
+ thd->handler_tables= thd->open_tables;
+ }
+
+ thd->open_tables= backup_open_tables;
+
if (error)
goto err;
@@ -351,7 +369,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
{
TABLE_LIST *hash_tables;
- TABLE *table;
+ TABLE *table, *backup_open_tables;
MYSQL_LOCK *lock;
List<Item> list;
Protocol *protocol= thd->protocol;
@@ -361,7 +379,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint num_rows;
byte *key;
uint key_len;
- bool not_used;
+ bool need_reopen;
DBUG_ENTER("mysql_ha_read");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
@@ -375,6 +393,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
List_iterator<Item> it(list);
it++;
+retry:
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
(byte*) tables->alias,
strlen(tables->alias) + 1)))
@@ -427,9 +446,34 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- HANDLER_TABLES_HACK(thd);
- lock= mysql_lock_tables(thd, &tables->table, 1, 0, &not_used);
- HANDLER_TABLES_HACK(thd);
+ /* save open_tables state */
+ backup_open_tables= thd->open_tables;
+ /*
+ mysql_lock_tables() needs thd->open_tables to be set correctly to
+ be able to handle aborts properly. When the abort happens, it's
+ safe to not protect thd->handler_tables because it won't close any
+ tables.
+ */
+ thd->open_tables= thd->handler_tables;
+
+ lock= mysql_lock_tables(thd, &tables->table, 1,
+ MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
+
+ /* restore previous context */
+ thd->open_tables= backup_open_tables;
+
+ if (need_reopen)
+ {
+ mysql_ha_close_table(thd, tables);
+ hash_tables->table= NULL;
+ /*
+ The lock might have been aborted, we need to manually reset
+ thd->some_tables_deleted because handler's tables are closed
+ in a non-standard way. Otherwise we might loop indefinitely.
+ */
+ thd->some_tables_deleted= 0;
+ goto retry;
+ }
if (!lock)
goto err0; // mysql_lock_tables() printed error message already
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index f07af393070..770bbd1349d 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -189,11 +189,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{
- Field_iterator_table field_it;
- field_it.set_table(table);
- if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
- table->s->db, table->s->table_name,
- &field_it))
+ Field_iterator_table_ref field_it;
+ field_it.set(table_list);
+ if (check_grant_all_columns(thd, INSERT_ACL, &field_it))
return -1;
}
#endif
@@ -2647,7 +2645,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
bool ignore_check_option_errors)
:table_list(table_list_par), table(table_par), fields(fields_par),
last_insert_id(0),
- insert_into_view(table_list_par && table_list_par->view != 0)
+ insert_into_view(table_list_par && table_list_par->view != 0),
+ is_bulk_insert_mode(FALSE)
{
bzero((char*) &info,sizeof(info));
info.handle_duplicates= duplic;
@@ -2832,8 +2831,11 @@ int select_insert::prepare2(void)
{
DBUG_ENTER("select_insert::prepare2");
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
- !thd->prelocked_mode)
+ !thd->prelocked_mode && !is_bulk_insert_mode)
+ {
table->file->start_bulk_insert((ha_rows) 0);
+ is_bulk_insert_mode= TRUE;
+ }
DBUG_RETURN(0);
}
@@ -2939,6 +2941,7 @@ bool select_insert::send_eof()
DBUG_ENTER("select_insert::send_eof");
error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
+ is_bulk_insert_mode= FALSE;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
@@ -3129,7 +3132,10 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
create_field *cr_field;
Field *field, *def_field;
if (item->type() == Item::FUNC_ITEM)
- field= item->tmp_table_field(&tmp_table);
+ if (item->result_type() != STRING_RESULT)
+ field= item->tmp_table_field(&tmp_table);
+ else
+ field= item->tmp_table_field_from_field_type(&tmp_table);
else
field= create_tmp_field(thd, &tmp_table, item, item->type(),
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0,
@@ -3271,7 +3277,10 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (info.handle_duplicates == DUP_UPDATE)
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
if (!thd->prelocked_mode)
+ {
table->file->start_bulk_insert((ha_rows) 0);
+ is_bulk_insert_mode= TRUE;
+ }
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 03dc091b9b7..282716c6151 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -41,7 +41,7 @@ mapped_files::mapped_files(const my_string filename,byte *magic,uint magic_lengt
struct stat stat_buf;
if (!fstat(file,&stat_buf))
{
- if (!(map=(byte*) my_mmap(0,(size=(ulong) stat_buf.st_size),PROT_READ,
+ if (!(map=(byte*) my_mmap(0,(size_t)(size=(ulong) stat_buf.st_size),PROT_READ,
MAP_SHARED | MAP_NORESERVE,file,
0L)))
{
@@ -52,7 +52,7 @@ mapped_files::mapped_files(const my_string filename,byte *magic,uint magic_lengt
if (map && memcmp(map,magic,magic_length))
{
my_error(ER_WRONG_MAGIC, MYF(0), name);
- VOID(my_munmap(map,size));
+ VOID(my_munmap(map,(size_t)size));
map=0;
}
if (!map)
@@ -70,7 +70,7 @@ mapped_files::~mapped_files()
#ifdef HAVE_MMAP
if (file >= 0)
{
- VOID(my_munmap(map,size));
+ VOID(my_munmap(map,(size_t)size));
VOID(my_close(file,MYF(0)));
file= -1; map=0;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 084bcfc3c76..0a8b92d28c0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -93,6 +93,10 @@ const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
+#ifndef EMBEDDED_LIBRARY
+static bool do_command(THD *thd);
+#endif // EMBEDDED_LIBRARY
+
#ifdef __WIN__
static void test_signal(int sig_ptr)
{
@@ -1199,23 +1203,28 @@ pthread_handler_t handle_one_connection(void *arg)
}
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
+
+ if (thd->killed ||
+ net->vio && net->error && net->report_error)
+ {
+ statistic_increment(aborted_threads, &LOCK_status);
+ }
+
if (net->error && net->vio != 0 && net->report_error)
{
if (!thd->killed && thd->variables.log_warnings > 1)
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ {
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip,
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
+ }
+
net_send_error(thd, net->last_errno, NullS);
- statistic_increment(aborted_threads,&LOCK_status);
- }
- else if (thd->killed)
- {
- statistic_increment(aborted_threads,&LOCK_status);
}
-
+
end_thread:
close_connection(thd, 0, 1);
end_thread(thd,1);
@@ -1520,7 +1529,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
1 request of thread shutdown (see dispatch_command() description)
*/
-bool do_command(THD *thd)
+static bool do_command(THD *thd)
{
char *packet= 0;
ulong packet_length;
@@ -1550,12 +1559,12 @@ bool do_command(THD *thd)
DBUG_PRINT("info",("Got error %d reading command from socket %s",
net->error,
vio_description(net->vio)));
+
/* Check if we can continue without closing the connection */
+
if (net->error != 3)
- {
- statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it.
- }
+
net_send_error(thd, net->last_errno, NullS);
net->error= 0;
DBUG_RETURN(FALSE);
@@ -4007,12 +4016,6 @@ end_with_restore_list:
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
break;
#ifdef HAVE_DLOPEN
- if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
- &thd->sp_func_cache, FALSE))
- {
- my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
- goto error;
- }
if (!(res = mysql_create_function(thd, &lex->udf)))
send_ok(thd);
#else
@@ -6427,7 +6430,12 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
if (!schema_table ||
(schema_table->hidden &&
- lex->orig_sql_command == SQLCOM_END)) // not a 'show' command
+ (lex->orig_sql_command == SQLCOM_END || // not a 'show' command
+ /*
+ this check is used for show columns|keys from I_S hidden table
+ */
+ lex->orig_sql_command == SQLCOM_SHOW_FIELDS ||
+ lex->orig_sql_command == SQLCOM_SHOW_KEYS)))
{
my_error(ER_UNKNOWN_TABLE, MYF(0),
ptr->table_name, INFORMATION_SCHEMA_NAME.str);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index bd93a7ae203..7af39071561 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -5915,7 +5915,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
/* Fix for EXPLAIN */
if (sel->quick)
- join->best_positions[i].records_read= sel->quick->records;
+ join->best_positions[i].records_read= (double)sel->quick->records;
}
else
{
@@ -12063,6 +12063,12 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
for (; const_key_parts & 1 ; const_key_parts>>= 1)
key_part++;
+ /*
+ The primary and secondary key parts were all const (i.e. there's
+ one row). The sorting doesn't matter.
+ */
+ if (key_part == key_part_end && reverse == 0)
+ DBUG_RETURN(1);
}
else
DBUG_RETURN(0);
@@ -12480,7 +12486,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
DBUG_RETURN(1);
}
- if (tab->ref.key_parts < used_key_parts)
+ if (tab->ref.key_parts <= used_key_parts)
{
/*
SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
@@ -13060,7 +13066,8 @@ static int
join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{
reg1 uint i;
- uint length,blobs,size;
+ uint length, blobs;
+ size_t size;
CACHE_FIELD *copy,**blob_ptr;
JOIN_CACHE *cache;
JOIN_TAB *join_tab;
@@ -13176,7 +13183,7 @@ store_record_in_cache(JOIN_CACHE *cache)
length=cache->length;
if (cache->blobs)
length+=used_blob_length(cache->blob_ptr);
- if ((last_record=(length+cache->length > (uint) (cache->end - pos))))
+ if ((last_record= (length + cache->length > (size_t) (cache->end - pos))))
cache->ptr_record=cache->records;
/*
@@ -13222,7 +13229,7 @@ store_record_in_cache(JOIN_CACHE *cache)
}
}
cache->pos=pos;
- return last_record || (uint) (cache->end -pos) < cache->length;
+ return last_record || (size_t) (cache->end - pos) < cache->length;
}
@@ -13895,13 +13902,31 @@ calc_group_buffer(JOIN *join,ORDER *group)
group_item->decimals);
break;
case STRING_RESULT:
+ {
+ enum enum_field_types type= group_item->field_type();
/*
- Group strings are taken as varstrings and require an length field.
- A field is not yet created by create_tmp_field()
- and the sizes should match up.
+ As items represented as DATE/TIME fields in the group buffer
+ have STRING_RESULT result type, we increase the length
+ by 8 as maximum pack length of such fields.
*/
- key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH;
+ if (type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_DATETIME ||
+ type == MYSQL_TYPE_TIMESTAMP)
+ {
+ key_length+= 8;
+ }
+ else
+ {
+ /*
+ Group strings are taken as varstrings and require an length field.
+ A field is not yet created by create_tmp_field()
+ and the sizes should match up.
+ */
+ key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH;
+ }
break;
+ }
default:
/* This case should never be choosen */
DBUG_ASSERT(0);
@@ -14324,6 +14349,9 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
item_field= (Item*) new Item_field(field);
if (!item_field)
DBUG_RETURN(TRUE); // Fatal error
+
+ if (item->real_item()->type() != Item::FIELD_ITEM)
+ field->orig_table= 0;
item_field->name= item->name;
if (item->type() == Item::REF_ITEM)
{
@@ -15463,6 +15491,55 @@ static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables)
}
+/**
+ @brief Print an index hint for a table
+
+ @details Prints out the USE|FORCE|IGNORE index hints for a table.
+
+ @param thd the current thread
+ @param[out] str appends the index hint here
+ @param hint what the hint is (as string : "USE INDEX"|
+ "FORCE INDEX"|"IGNORE INDEX")
+ @param hint_length the length of the string in 'hint'
+ @param indexes a list of index names for the hint
+*/
+
+void
+TABLE_LIST::print_index_hint(THD *thd, String *str,
+ const char *hint, uint32 hint_length,
+ List<String> indexes)
+{
+ List_iterator_fast<String> li(indexes);
+ String *idx;
+ bool first= 1;
+ size_t find_length= strlen(primary_key_name);
+
+ str->append (' ');
+ str->append (hint, hint_length);
+ str->append (STRING_WITH_LEN(" ("));
+ while ((idx = li++))
+ {
+ if (first)
+ first= 0;
+ else
+ str->append(',');
+ /*
+ It's safe to use ptr() here because we compare the length first
+ and we rely that my_strcasecmp will not access more than length()
+ chars from the string. See test_if_string_in_list() for similar
+ implementation.
+ */
+ if (find_length == idx->length() &&
+ !my_strcasecmp (system_charset_info, primary_key_name,
+ idx->ptr()))
+ str->append(primary_key_name);
+ else
+ append_identifier (thd, str, idx->ptr(), idx->length());
+ }
+ str->append(')');
+}
+
+
/*
Print table as it should be in join list
@@ -15530,6 +15607,17 @@ void TABLE_LIST::print(THD *thd, String *str)
str->append(' ');
append_identifier(thd, str, alias, strlen(alias));
}
+
+ if (use_index)
+ {
+ if (force_index)
+ print_index_hint(thd, str, STRING_WITH_LEN("FORCE INDEX"), *use_index);
+ else
+ print_index_hint(thd, str, STRING_WITH_LEN("USE INDEX"), *use_index);
+ }
+ if (ignore_index)
+ print_index_hint (thd, str, STRING_WITH_LEN("IGNORE INDEX"), *ignore_index);
+
}
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index d84fbcb8c2d..4fc32e7fdb3 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -521,9 +521,13 @@ public:
store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length)
:null_key(0), null_ptr(null), err(0)
{
- if (field_arg->type() == FIELD_TYPE_BLOB)
+ if (field_arg->type() == FIELD_TYPE_BLOB
+ || field_arg->type() == FIELD_TYPE_GEOMETRY)
{
- /* Key segments are always packed with a 2 byte length prefix */
+ /*
+ Key segments are always packed with a 2 byte length prefix.
+ See mi_rkey for details.
+ */
to_field=new Field_varstring(ptr, length, 2, (uchar*) null, 1,
Field::NONE, field_arg->field_name,
field_arg->table, field_arg->charset());
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1ad94c12b99..36d154181f8 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -791,13 +791,70 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
#define LIST_PROCESS_HOST_LEN 64
+
+static bool get_field_default_value(THD *thd, TABLE *table,
+ Field *field, String *def_value,
+ bool quoted)
+{
+ bool has_default;
+ bool has_now_default;
+
+ /*
+ We are using CURRENT_TIMESTAMP instead of NOW because it is
+ more standard
+ */
+ has_now_default= table->timestamp_field == field &&
+ field->unireg_check != Field::TIMESTAMP_UN_FIELD;
+
+ has_default= (field->type() != FIELD_TYPE_BLOB &&
+ !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
+ field->unireg_check != Field::NEXT_NUMBER &&
+ !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
+ && has_now_default));
+
+ def_value->length(0);
+ if (has_default)
+ {
+ if (has_now_default)
+ def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
+ else if (!field->is_null())
+ { // Not null by default
+ char tmp[MAX_FIELD_WIDTH];
+ String type(tmp, sizeof(tmp), field->charset());
+ field->val_str(&type);
+ if (type.length())
+ {
+ String def_val;
+ uint dummy_errors;
+ /* convert to system_charset_info == utf8 */
+ def_val.copy(type.ptr(), type.length(), field->charset(),
+ system_charset_info, &dummy_errors);
+ if (quoted)
+ append_unescaped(def_value, def_val.ptr(), def_val.length());
+ else
+ def_value->append(def_val.ptr(), def_val.length());
+ }
+ else if (quoted)
+ def_value->append(STRING_WITH_LEN("''"));
+ }
+ else if (field->maybe_null() && quoted)
+ def_value->append(STRING_WITH_LEN("NULL")); // Null as default
+ else
+ return 0;
+
+ }
+ return has_default;
+}
+
+
static int
store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
{
List<Item> field_list;
- char tmp[MAX_FIELD_WIDTH], *for_str, buff[128];
+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
const char *alias;
String type(tmp, sizeof(tmp), system_charset_info);
+ String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
Field **ptr,*field;
uint primary_key;
KEY *key_info;
@@ -833,8 +890,6 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
for (ptr=table->field ; (field= *ptr); ptr++)
{
- bool has_default;
- bool has_now_default;
uint flags = field->flags;
if (ptr != table->field)
@@ -882,44 +937,10 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
packet->append(STRING_WITH_LEN(" NULL"));
}
- /*
- Again we are using CURRENT_TIMESTAMP instead of NOW because it is
- more standard
- */
- has_now_default= table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD;
-
- has_default= (field->type() != FIELD_TYPE_BLOB &&
- !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
- field->unireg_check != Field::NEXT_NUMBER &&
- !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
- && has_now_default));
-
- if (has_default)
+ if (get_field_default_value(thd, table, field, &def_value, 1))
{
packet->append(STRING_WITH_LEN(" default "));
- if (has_now_default)
- packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
- else if (!field->is_null())
- { // Not null by default
- type.set(tmp, sizeof(tmp), field->charset());
- field->val_str(&type);
- if (type.length())
- {
- String def_val;
- uint dummy_errors;
- /* convert to system_charset_info == utf8 */
- def_val.copy(type.ptr(), type.length(), field->charset(),
- system_charset_info, &dummy_errors);
- append_unescaped(packet, def_val.ptr(), def_val.length());
- }
- else
- packet->append(STRING_WITH_LEN("''"));
- }
- else if (field->maybe_null())
- packet->append(STRING_WITH_LEN("NULL")); // Null as default
- else
- packet->append(tmp);
+ packet->append(def_value.ptr(), def_value.length(), system_charset_info);
}
if (!limited_mysql_mode && table->timestamp_field == field &&
@@ -2664,7 +2685,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
bool is_blob;
uint flags=field->flags;
char tmp[MAX_FIELD_WIDTH];
- char tmp1[MAX_FIELD_WIDTH];
String type(tmp,sizeof(tmp), system_charset_info);
char *end;
int decimals, field_length;
@@ -2710,33 +2730,13 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
table->field[7]->store(type.ptr(),
(tmp_buff ? tmp_buff - type.ptr() :
type.length()), cs);
- if (show_table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD)
- {
- table->field[5]->store(STRING_WITH_LEN("CURRENT_TIMESTAMP"), cs);
- table->field[5]->set_notnull();
- }
- else if (field->unireg_check != Field::NEXT_NUMBER &&
- !field->is_null() &&
- !(field->flags & NO_DEFAULT_VALUE_FLAG))
- {
- String def(tmp1,sizeof(tmp1), cs);
- type.set(tmp, sizeof(tmp), field->charset());
- field->val_str(&type);
- uint dummy_errors;
- def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors);
- table->field[5]->store(def.ptr(), def.length(), def.charset());
- table->field[5]->set_notnull();
- }
- else if (field->unireg_check == Field::NEXT_NUMBER ||
- lex->orig_sql_command != SQLCOM_SHOW_FIELDS ||
- field->maybe_null())
- table->field[5]->set_null(); // Null as default
- else
+
+ if (get_field_default_value(thd, show_table, field, &type, 0))
{
- table->field[5]->store("",0, cs);
+ table->field[5]->store(type.ptr(), type.length(), cs);
table->field[5]->set_notnull();
}
+
pos=(byte*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES");
table->field[6]->store((const char*) pos,
strlen((const char*) pos), cs);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6cbe98fe862..20b8c7a4278 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1287,7 +1287,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
Field::GEOM_POINT)
- column->length= 21;
+ column->length= 25;
if (!column->length)
{
my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 077660f0bb9..ce6cd43eace 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -426,14 +426,14 @@ int mysql_create_function(THD *thd,udf_func *udf)
}
if (udf->name.length > NAME_LEN)
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name);
+ my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name.str);
DBUG_RETURN(1);
}
rw_wrlock(&THR_LOCK_udf);
if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length)))
{
- my_error(ER_UDF_EXISTS, MYF(0), udf->name);
+ my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
goto err;
}
if (!(dl = find_udf_dl(udf->dl)))
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index c78e246f518..321d07dec76 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -362,7 +362,7 @@ int mysql_update(THD *thd,
init_read_record_idx(&info, thd, table, 1, used_index);
thd->proc_info="Searching rows for update";
- uint tmp_limit= limit;
+ ha_rows tmp_limit= limit;
while (!(error=info.read_record(&info)) && !thd->killed)
{
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 35a97411511..297edd0d90d 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -223,9 +223,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
{
LEX *lex= thd->lex;
bool link_to_local;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- bool definer_check_is_needed= mode != VIEW_ALTER || lex->definer;
-#endif
/* first table in list is target VIEW name => cut off it */
TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
@@ -280,7 +277,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
- same as current user
- current user has SUPER_ACL
*/
- if (definer_check_is_needed &&
+ if (lex->definer &&
(strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
my_strcasecmp(system_charset_info,
lex->definer->host.str,
@@ -925,6 +922,15 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
DBUG_RETURN(0);
}
+ if (table->use_index || table->ignore_index)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0),
+ table->ignore_index ? "IGNORE INDEX" :
+ (table->force_index ? "FORCE INDEX" : "USE INDEX"),
+ "VIEW");
+ DBUG_RETURN(TRUE);
+ }
+
/* check loop via view definition */
for (TABLE_LIST *precedent= table->referencing_view;
precedent;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 553cc6d24d5..368ce5673e2 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1121,8 +1121,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <cast_type> cast_type
-%type <udf_type> udf_func_type
-
%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp
%type <lex_user> user grant_user
@@ -1181,11 +1179,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
statement sp_suid
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
- definer view_replace_or_algorithm view_replace view_algorithm_opt
- view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
+ view_replace_or_algorithm view_replace view_algorithm_opt
+ view_algorithm view_or_trigger_or_sp definer_tail
view_suid view_tail view_list_opt view_list view_select
- view_check_option trigger_tail sp_tail
+ view_check_option trigger_tail sp_tail sf_tail udf_tail
case_stmt_specification simple_case_stmt searched_case_stmt
+ definer_opt no_definer definer
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -1571,6 +1570,7 @@ sp_name:
{
LEX *lex= Lex;
LEX_STRING db;
+
if (check_routine_name($1))
{
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
@@ -1584,124 +1584,6 @@ sp_name:
}
;
-create_function_tail:
- RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
- {
- LEX *lex=Lex;
- if (lex->definer != NULL)
- {
- /*
- DEFINER is a concept meaningful when interpreting SQL code.
- UDF functions are compiled.
- Using DEFINER with UDF has therefore no semantic,
- and is considered a parsing error.
- */
- my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
- MYSQL_YYABORT;
- }
- lex->sql_command = SQLCOM_CREATE_FUNCTION;
- lex->udf.name = lex->spname->m_name;
- lex->udf.returns=(Item_result) $2;
- lex->udf.dl=$4.str;
- }
- | '('
- {
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- Lex_input_stream *lip= thd->m_lip;
- sp_head *sp;
-
- /*
- First check if AGGREGATE was used, in that case it's a
- syntax error.
- */
- if (lex->udf.type == UDFTYPE_AGGREGATE)
- {
- my_error(ER_SP_NO_AGGREGATE, MYF(0));
- MYSQL_YYABORT;
- }
-
- if (lex->sphead)
- {
- my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
- MYSQL_YYABORT;
- }
- /* Order is important here: new - reset - init */
- sp= new sp_head();
- sp->reset_thd_mem_root(thd);
- sp->init(lex);
- sp->init_sp_name(thd, lex->spname);
-
- sp->m_type= TYPE_ENUM_FUNCTION;
- lex->sphead= sp;
- /*
- * We have to turn of CLIENT_MULTI_QUERIES while parsing a
- * stored procedure, otherwise yylex will chop it into pieces
- * at each ';'.
- */
- sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES;
- thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
- lex->sphead->m_param_begin= lip->tok_start+1;
- }
- sp_fdparam_list ')'
- {
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- Lex_input_stream *lip= thd->m_lip;
-
- lex->sphead->m_param_end= lip->tok_start;
- }
- RETURNS_SYM
- {
- LEX *lex= Lex;
- lex->charset= NULL;
- lex->length= lex->dec= NULL;
- lex->interval_list.empty();
- lex->type= 0;
- }
- type
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
-
- if (sp->fill_field_definition(YYTHD, lex,
- (enum enum_field_types) $8,
- &sp->m_return_field_def))
- MYSQL_YYABORT;
-
- bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
- }
- sp_c_chistics
- {
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- Lex_input_stream *lip= thd->m_lip;
-
- lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lip->tok_start;
- }
- sp_proc_stmt
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
-
- if (sp->is_not_allowed_in_function("function"))
- MYSQL_YYABORT;
-
- lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
- sp->init_strings(YYTHD, lex);
- if (!(sp->m_flags & sp_head::HAS_RETURN))
- {
- my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
- MYSQL_YYABORT;
- }
- /* Restore flag if it was cleared above */
- if (sp->m_old_cmq)
- YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
- sp->restore_thd_mem_root(YYTHD);
- }
- ;
-
sp_a_chistics:
/* Empty */ {}
| sp_a_chistics sp_chistic {}
@@ -3002,10 +2884,6 @@ opt_select_from:
opt_limit_clause {}
| select_from select_lock_type;
-udf_func_type:
- /* empty */ { $$ = UDFTYPE_FUNCTION; }
- | AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; };
-
udf_type:
STRING_SYM {$$ = (int) STRING_RESULT; }
| REAL {$$ = (int) REAL_RESULT; }
@@ -3216,7 +3094,7 @@ type:
spatial_type:
GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
| GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
- | POINT_SYM { Lex->length= (char*)"21";
+ | POINT_SYM { Lex->length= (char*)"25";
$$= Field::GEOM_POINT;
}
| MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
@@ -3669,7 +3547,7 @@ alter:
lex->sql_command= SQLCOM_ALTER_FUNCTION;
lex->spname= $3;
}
- | ALTER view_algorithm_opt definer view_suid
+ | ALTER view_algorithm_opt definer_opt view_suid
VIEW_SYM table_ident
{
THD *thd= YYTHD;
@@ -5196,8 +5074,30 @@ simple_expr:
{
THD *thd= lex->thd;
LEX_STRING db;
+ if (! thd->db && ! lex->sphead)
+ {
+ /*
+ The proper error message should be in the lines of:
+ Can't resolve <name>() to a function call,
+ because this function:
+ - is not a native function,
+ - is not a user defined function,
+ - can not match a stored function since no database is selected.
+ Reusing ER_SP_DOES_NOT_EXIST have a message consistent with
+ the case when a default database exist, see below.
+ */
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ "FUNCTION", $1.str);
+ MYSQL_YYABORT;
+ }
+
if (lex->copy_db_to(&db.str, &db.length))
MYSQL_YYABORT;
+
+ /*
+ From here, the parser assumes <name>() is a stored function,
+ as a last choice. This later can lead to ER_SP_DOES_NOT_EXIST.
+ */
sp_name *name= new sp_name(db, $1, false);
if (name)
name->init_qname(thd);
@@ -6499,9 +6399,11 @@ drop:
lex->drop_if_exists=$3;
lex->name=$4.str;
}
- | DROP FUNCTION_SYM if_exists sp_name
+ | DROP FUNCTION_SYM if_exists ident '.' ident
{
- LEX *lex=Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ sp_name *spname;
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
@@ -6509,7 +6411,28 @@ drop:
}
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->drop_if_exists= $3;
- lex->spname= $4;
+ spname= new sp_name($4, $6, true);
+ spname->init_qname(thd);
+ lex->spname= spname;
+ }
+ | DROP FUNCTION_SYM if_exists ident
+ {
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ LEX_STRING db= {0, 0};
+ sp_name *spname;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ MYSQL_YYABORT;
+ }
+ if (thd->db && lex->copy_db_to(&db.str, &db.length))
+ MYSQL_YYABORT;
+ lex->sql_command = SQLCOM_DROP_FUNCTION;
+ lex->drop_if_exists= $3;
+ spname= new sp_name(db, $4, false);
+ spname->init_qname(thd);
+ lex->spname= spname;
}
| DROP PROCEDURE if_exists sp_name
{
@@ -7716,11 +7639,15 @@ literal:
String *str= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0;
- $$= new Item_string(str ? str->ptr() : "",
+ $$= new Item_string(NULL, /* name will be set in select_item */
+ str ? str->ptr() : "",
str ? str->length() : 0,
Lex->underscore_charset);
- if ($$)
- ((Item_string *) $$)->set_repertoire_from_value();
+ if (!$$ || !$$->check_well_formed_result(&$$->str_value, TRUE))
+ {
+ MYSQL_YYABORT;
+ }
+ ((Item_string *) $$)->set_repertoire_from_value();
}
| UNDERSCORE_CHARSET BIN_NUM
{
@@ -7732,9 +7659,14 @@ literal:
String *str= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0;
- $$= new Item_string(str ? str->ptr() : "",
- str ? str->length() : 0,
- Lex->charset);
+ $$= new Item_string(NULL, /* name will be set in select_item */
+ str ? str->ptr() : "",
+ str ? str->length() : 0,
+ Lex->underscore_charset);
+ if (!$$ || !$$->check_well_formed_result(&$$->str_value, TRUE))
+ {
+ MYSQL_YYABORT;
+ }
}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
@@ -9558,19 +9490,27 @@ subselect_end:
**************************************************************************/
view_or_trigger_or_sp:
- definer view_or_trigger_or_sp_tail
- {}
- | view_replace_or_algorithm definer view_tail
- {}
+ definer definer_tail
+ {}
+ | no_definer no_definer_tail
+ {}
+ | view_replace_or_algorithm definer_opt view_tail
+ {}
;
-view_or_trigger_or_sp_tail:
- view_tail
- {}
+definer_tail:
+ view_tail
| trigger_tail
- {}
| sp_tail
- {}
+ | sf_tail
+ ;
+
+no_definer_tail:
+ view_tail
+ | trigger_tail
+ | sp_tail
+ | sf_tail
+ | udf_tail
;
/**************************************************************************
@@ -9579,23 +9519,31 @@ view_or_trigger_or_sp_tail:
**************************************************************************/
+definer_opt:
+ no_definer
+ | definer
+ ;
+
+no_definer:
+ /* empty */
+ {
+ /*
+ We have to distinguish missing DEFINER-clause from case when
+ CURRENT_USER specified as definer explicitly in order to properly
+ handle CREATE TRIGGER statements which come to replication thread
+ from older master servers (i.e. to create non-suid trigger in this
+ case).
+ */
+ YYTHD->lex->definer= 0;
+ }
+ ;
+
definer:
- /* empty */
- {
- /*
- We have to distinguish missing DEFINER-clause from case when
- CURRENT_USER specified as definer explicitly in order to properly
- handle CREATE TRIGGER statements which come to replication thread
- from older master servers (i.e. to create non-suid trigger in this
- case).
- */
- YYTHD->lex->definer= 0;
- }
- | DEFINER_SYM EQ user
- {
- YYTHD->lex->definer= get_current_user(YYTHD, $3);
- }
- ;
+ DEFINER_SYM EQ user
+ {
+ YYTHD->lex->definer= get_current_user(YYTHD, $3);
+ }
+;
/**************************************************************************
@@ -9745,7 +9693,7 @@ trigger_tail:
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
MYSQL_YYABORT;
}
-
+
if (!(sp= new sp_head()))
MYSQL_YYABORT;
sp->reset_thd_mem_root(thd);
@@ -9807,17 +9755,131 @@ trigger_tail:
**************************************************************************/
+udf_tail:
+ AGGREGATE_SYM remember_name FUNCTION_SYM ident
+ RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_CREATE_FUNCTION;
+ lex->udf.type= UDFTYPE_AGGREGATE;
+ lex->stmt_definition_begin= $2;
+ lex->udf.name = $4;
+ lex->udf.returns=(Item_result) $6;
+ lex->udf.dl=$8.str;
+ }
+ | remember_name FUNCTION_SYM ident
+ RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_CREATE_FUNCTION;
+ lex->udf.type= UDFTYPE_FUNCTION;
+ lex->stmt_definition_begin= $1;
+ lex->udf.name = $3;
+ lex->udf.returns=(Item_result) $5;
+ lex->udf.dl=$7.str;
+ }
+ ;
+
+sf_tail:
+ remember_name /* $1 */
+ FUNCTION_SYM /* $2 */
+ sp_name /* $3 */
+ '(' /* 44 */
+ { /* $5 */
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+ sp_head *sp;
+
+ lex->stmt_definition_begin= $1;
+ lex->spname= $3;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
+ MYSQL_YYABORT;
+ }
+
+ /* Order is important here: new - reset - init */
+ sp= new sp_head();
+ sp->reset_thd_mem_root(thd);
+ sp->init(lex);
+ sp->init_sp_name(thd, lex->spname);
+
+ sp->m_type= TYPE_ENUM_FUNCTION;
+ lex->sphead= sp;
+ /*
+ * We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ * stored procedure, otherwise yylex will chop it into pieces
+ * at each ';'.
+ */
+ sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES;
+ thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+ lex->sphead->m_param_begin= lip->tok_start+1;
+ }
+ sp_fdparam_list /* $6 */
+ ')' /* $7 */
+ { /* $8 */
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+
+ lex->sphead->m_param_end= lip->tok_start;
+ }
+ RETURNS_SYM /* $9 */
+ { /* $10 */
+ LEX *lex= Lex;
+ lex->charset= NULL;
+ lex->length= lex->dec= NULL;
+ lex->interval_list.empty();
+ lex->type= 0;
+ }
+ type /* $11 */
+ { /* $12 */
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if (sp->fill_field_definition(YYTHD, lex,
+ (enum enum_field_types) $11,
+ &sp->m_return_field_def))
+ MYSQL_YYABORT;
+
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ }
+ sp_c_chistics /* $13 */
+ { /* $14 */
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+
+ lex->sphead->m_chistics= &lex->sp_chistics;
+ lex->sphead->m_body_begin= lip->tok_start;
+ }
+ sp_proc_stmt /* $15 */
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if (sp->is_not_allowed_in_function("function"))
+ MYSQL_YYABORT;
+
+ lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
+ sp->init_strings(YYTHD, lex);
+ if (!(sp->m_flags & sp_head::HAS_RETURN))
+ {
+ my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
+ MYSQL_YYABORT;
+ }
+ /* Restore flag if it was cleared above */
+ if (sp->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ sp->restore_thd_mem_root(YYTHD);
+ }
+ ;
+
+
sp_tail:
- udf_func_type remember_name FUNCTION_SYM sp_name
- {
- LEX *lex=Lex;
- lex->udf.type= $1;
- lex->stmt_definition_begin= $2;
- lex->spname= $4;
- }
- create_function_tail
- {}
- | PROCEDURE remember_name sp_name
+ PROCEDURE remember_name sp_name
{
LEX *lex= Lex;
sp_head *sp;
diff --git a/sql/table.cc b/sql/table.cc
index a393f1a676b..7fe9aa774f3 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -732,9 +732,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
if (field->type() == FIELD_TYPE_BLOB ||
- field->real_type() == MYSQL_TYPE_VARCHAR)
+ field->real_type() == MYSQL_TYPE_VARCHAR ||
+ field->type() == FIELD_TYPE_GEOMETRY)
{
- if (field->type() == FIELD_TYPE_BLOB)
+ if (field->type() == FIELD_TYPE_BLOB ||
+ field->type() == FIELD_TYPE_GEOMETRY)
key_part->key_part_flag|= HA_BLOB_PART;
else
key_part->key_part_flag|= HA_VAR_LENGTH_PART;
diff --git a/sql/table.h b/sql/table.h
index f411ce489c4..cff4be630e4 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -773,6 +773,8 @@ struct TABLE_LIST
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
+ void print_index_hint(THD *thd, String *str, const char *hint,
+ uint32 hint_length, List<String>);
/*
Cleanup for re-execution in a prepared statement or a stored
procedure.
diff --git a/sql/udf_example.c b/sql/udf_example.c
index 0f28c2a14b0..df3a69755ad 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -1106,4 +1106,39 @@ char * is_const(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)),
}
+
+my_bool check_const_len_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1)
+ {
+ strmov(message, "CHECK_CONST_LEN accepts only one argument");
+ return 1;
+ }
+ if (args->args[0] == 0)
+ {
+ initid->ptr= (char*)"Not constant";
+ }
+ else if(strlen(args->args[0]) == args->lengths[0])
+ {
+ initid->ptr= (char*)"Correct length";
+ }
+ else
+ {
+ initid->ptr= (char*)"Wrong length";
+ }
+ initid->max_length = 100;
+ return 0;
+}
+
+char * check_const_len(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)),
+ char *result, unsigned long *length,
+ char *is_null, char *error __attribute__((unused)))
+{
+ strmov(result, initid->ptr);
+ *length= strlen(result);
+ *is_null= 0;
+ return result;
+}
+
+
#endif /* HAVE_DLOPEN */
diff --git a/sql/udf_example.def b/sql/udf_example.def
index 7a87147d7b6..3d569941cc8 100644
--- a/sql/udf_example.def
+++ b/sql/udf_example.def
@@ -23,3 +23,5 @@ EXPORTS
avgcost
is_const
is_const_init
+ check_const_len
+ check_const_len_init