diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-07-24 12:00:17 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-07-24 12:00:17 +0400 |
commit | a78d1aaaa349ebbe3400e48f63903b349050b316 (patch) | |
tree | b20f70c785b6e84ae059357fa97d57c75685f8f8 | |
parent | fee463238793dcc196273654b6f6abd23a1b35ac (diff) | |
download | mariadb-git-a78d1aaaa349ebbe3400e48f63903b349050b316.tar.gz |
MDEV-16806 Add Type_handler::create_literal_item()
-rw-r--r-- | sql/item.cc | 14 | ||||
-rw-r--r-- | sql/item.h | 28 | ||||
-rw-r--r-- | sql/item_create.cc | 78 | ||||
-rw-r--r-- | sql/item_create.h | 15 | ||||
-rw-r--r-- | sql/sql_type.cc | 117 | ||||
-rw-r--r-- | sql/sql_type.h | 34 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 26 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 26 |
8 files changed, 184 insertions, 154 deletions
diff --git a/sql/item.cc b/sql/item.cc index fddae456bbe..2b325706d4c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6951,14 +6951,18 @@ Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str) */ Item *Item_string::make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) { - enum_field_types type= odbc_temporal_literal_type(typestr); - Item *res= type == MYSQL_TYPE_STRING ? this : - create_temporal_literal(thd, val_str(NULL), type, false); + Item_literal *res; + const Type_handler *h; + if (collation.repertoire == MY_REPERTOIRE_ASCII && + str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4 && + (h= Type_handler::odbc_literal_type_handler(typestr)) && + (res= h->create_literal_item(thd, val_str(NULL), false))) + return res; /* - create_temporal_literal() returns NULL if failed to parse the string, + h->create_literal_item() returns NULL if failed to parse the string, or the string format did not match the type, e.g.: {d'2001-01-01 10:10:10'} */ - return res ? res : this; + return this; } diff --git a/sql/item.h b/sql/item.h index 4fce15af83d..21a96760c49 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4330,34 +4330,6 @@ public: String *check_well_formed_result(bool send_error) { return Item::check_well_formed_result(&str_value, send_error); } - enum_field_types odbc_temporal_literal_type(const LEX_CSTRING *type_str) const - { - /* - If string is a reasonably short pure ASCII string literal, - try to parse known ODBC style date, time or timestamp literals, - e.g: - SELECT {d'2001-01-01'}; - SELECT {t'10:20:30'}; - SELECT {ts'2001-01-01 10:20:30'}; - */ - if (collation.repertoire == MY_REPERTOIRE_ASCII && - str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4) - { - if (type_str->length == 1) - { - if (type_str->str[0] == 'd') /* {d'2001-01-01'} */ - return MYSQL_TYPE_DATE; - else if (type_str->str[0] == 't') /* {t'10:20:30'} */ - return MYSQL_TYPE_TIME; - } - else if (type_str->length == 2) /* {ts'2001-01-01 10:20:30'} */ - { - if (type_str->str[0] == 't' && type_str->str[1] == 's') - return MYSQL_TYPE_DATETIME; - } - } - return MYSQL_TYPE_STRING; // Not a temporal literal - } Item_basic_constant *make_string_literal_concat(THD *thd, const LEX_CSTRING *); Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr); diff --git a/sql/item_create.cc b/sql/item_create.cc index 904896770c7..80cb830c584 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -7432,84 +7432,6 @@ find_qualified_function_builder(THD *thd) } -static bool -have_important_literal_warnings(const MYSQL_TIME_STATUS *status) -{ - return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0; -} - - -/** - Builder for datetime literals: - TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'. - @param thd The current thread - @param str Character literal - @param length Length of str - @param type Type of literal (TIME, DATE or DATETIME) - @param send_error Whether to generate an error on failure -*/ - -Item *create_temporal_literal(THD *thd, - const char *str, size_t length, - CHARSET_INFO *cs, - enum_field_types type, - bool send_error) -{ - MYSQL_TIME_STATUS status; - MYSQL_TIME ltime; - Item *item= NULL; - sql_mode_t flags= sql_mode_for_dates(thd); - - switch(type) - { - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_NEWDATE: - if (!str_to_datetime(cs, str, length, <ime, flags, &status) && - ltime.time_type == MYSQL_TIMESTAMP_DATE && !status.warnings) - item= new (thd->mem_root) Item_date_literal(thd, <ime); - break; - case MYSQL_TYPE_DATETIME: - if (!str_to_datetime(cs, str, length, <ime, flags, &status) && - ltime.time_type == MYSQL_TIMESTAMP_DATETIME && - !have_important_literal_warnings(&status)) - item= new (thd->mem_root) Item_datetime_literal(thd, <ime, - status.precision); - break; - case MYSQL_TYPE_TIME: - if (!str_to_time(cs, str, length, <ime, 0, &status) && - ltime.time_type == MYSQL_TIMESTAMP_TIME && - !have_important_literal_warnings(&status)) - item= new (thd->mem_root) Item_time_literal(thd, <ime, - status.precision); - break; - default: - DBUG_ASSERT(0); - } - - if (likely(item)) - { - if (status.warnings) // e.g. a note on nanosecond truncation - { - ErrConvString err(str, length, cs); - make_truncated_value_warning(thd, - Sql_condition::time_warn_level(status.warnings), - &err, ltime.time_type, 0); - } - return item; - } - - if (send_error) - { - const char *typestr= - (type == MYSQL_TYPE_DATE) ? "DATE" : - (type == MYSQL_TYPE_TIME) ? "TIME" : "DATETIME"; - ErrConvString err(str, length, thd->variables.character_set_client); - my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr()); - } - return NULL; -} - - static List<Item> *create_func_dyncol_prepare(THD *thd, DYNCALL_CREATE_DEF **dfs, List<DYNCALL_CREATE_DEF> &list) diff --git a/sql/item_create.h b/sql/item_create.h index 5983a092cdc..4fb3c07c4ae 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -191,21 +191,6 @@ protected: #endif -Item *create_temporal_literal(THD *thd, - const char *str, size_t length, - CHARSET_INFO *cs, - enum_field_types type, - bool send_error); -inline -Item *create_temporal_literal(THD *thd, const String *str, - enum_field_types type, - bool send_error) -{ - return create_temporal_literal(thd, - str->ptr(), str->length(), str->charset(), - type, send_error); -} - struct Native_func_registry { LEX_CSTRING name; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 669358eff52..70d4a6a6fd5 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -285,6 +285,32 @@ bool Type_std_attributes::count_string_length(const char *func_name, } +/* + Find a handler by its ODBC literal data type. + + @param type_str - data type name, not necessarily 0-terminated + @retval - a pointer to data type handler if type_str points + to a known ODBC literal data type, or NULL otherwise +*/ +const Type_handler * +Type_handler::odbc_literal_type_handler(const LEX_CSTRING *type_str) +{ + if (type_str->length == 1) + { + if (type_str->str[0] == 'd') // {d'2001-01-01'} + return &type_handler_newdate; + else if (type_str->str[0] == 't') // {t'10:20:30'} + return &type_handler_time2; + } + else if (type_str->length == 2) // {ts'2001-01-01 10:20:30'} + { + if (type_str->str[0] == 't' && type_str->str[1] == 's') + return &type_handler_datetime2; + } + return NULL; // Not a known ODBC literal type +} + + /** This method is used by: - Item_user_var_as_out_param::field_type() @@ -6663,3 +6689,94 @@ int Type_handler_real_result::stored_field_cmp_to_item(THD *thd, return 1; return 0; } + + +/***************************************************************************/ + + +static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status) +{ + return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0; +} + + +static void literal_warn(THD *thd, const Item *item, + const char *str, size_t length, CHARSET_INFO *cs, + const MYSQL_TIME *ltime, + const MYSQL_TIME_STATUS *st, + const char *typestr, bool send_error) +{ + if (likely(item)) + { + if (st->warnings) // e.g. a note on nanosecond truncation + { + ErrConvString err(str, length, cs); + make_truncated_value_warning(thd, + Sql_condition::time_warn_level(st->warnings), + &err, ltime->time_type, 0); + } + } + else if (send_error) + { + ErrConvString err(str, length, cs); + my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr()); + } +} + + +Item_literal * +Type_handler_date_common::create_literal_item(THD *thd, + const char *str, + size_t length, + CHARSET_INFO *cs, + bool send_error) const +{ + MYSQL_TIME_STATUS st; + MYSQL_TIME ltime; + Item_literal *item= NULL; + sql_mode_t flags= sql_mode_for_dates(thd); + if (!str_to_datetime(cs, str, length, <ime, flags, &st) && + ltime.time_type == MYSQL_TIMESTAMP_DATE && !st.warnings) + item= new (thd->mem_root) Item_date_literal(thd, <ime); + literal_warn(thd, item, str, length, cs, <ime, &st, "DATE", send_error); + return item; +} + + +Item_literal * +Type_handler_temporal_with_date::create_literal_item(THD *thd, + const char *str, + size_t length, + CHARSET_INFO *cs, + bool send_error) const +{ + MYSQL_TIME_STATUS st; + MYSQL_TIME ltime; + Item_literal *item= NULL; + sql_mode_t flags= sql_mode_for_dates(thd); + if (!str_to_datetime(cs, str, length, <ime, flags, &st) && + ltime.time_type == MYSQL_TIMESTAMP_DATETIME && + !have_important_literal_warnings(&st)) + item= new (thd->mem_root) Item_datetime_literal(thd, <ime, st.precision); + literal_warn(thd, item, str, length, cs, <ime, &st, "DATETIME", send_error); + return item; +} + + +Item_literal * +Type_handler_time_common::create_literal_item(THD *thd, + const char *str, + size_t length, + CHARSET_INFO *cs, + bool send_error) const +{ + MYSQL_TIME_STATUS st; + MYSQL_TIME ltime; + Item_literal *item= NULL; + if (!str_to_time(cs, str, length, <ime, 0, &st) && + ltime.time_type == MYSQL_TIMESTAMP_TIME && + !have_important_literal_warnings(&st)) + item= new (thd->mem_root) Item_time_literal(thd, <ime, st.precision); + literal_warn(thd, item, str, length, cs, <ime, &st, "TIME", send_error); + return item; +} diff --git a/sql/sql_type.h b/sql/sql_type.h index 7ba2727f787..d4b93ec9563 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -31,6 +31,7 @@ class Column_definition; class Column_definition_attributes; class Item; class Item_const; +class Item_literal; class Item_param; class Item_cache; class Item_func_or_sum; @@ -1077,6 +1078,7 @@ protected: enum_field_types type) const; public: + static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str); static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *bit_and_int_mixture_handler(uint max_char_len); @@ -1416,6 +1418,32 @@ public: Item *src, const Item *cmp) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; + /** + A builder for literals with data type name prefix, e.g.: + TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'. + @param thd The current thread + @param str Character literal + @param length Length of str + @param cs Character set of the string + @param send_error Whether to generate an error on failure + + @retval A pointer to a new Item on success + NULL on error (wrong literal value, EOM) + */ + virtual Item_literal *create_literal_item(THD *thd, + const char *str, size_t length, + CHARSET_INFO *cs, + bool send_error) const + { + DBUG_ASSERT(0); + return NULL; + } + Item_literal *create_literal_item(THD *thd, const String *str, + bool send_error) const + { + return create_literal_item(thd, str->ptr(), str->length(), str->charset(), + send_error); + } virtual Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const { @@ -2894,6 +2922,8 @@ public: { return MYSQL_TIMESTAMP_TIME; } + Item_literal *create_literal_item(THD *thd, const char *str, size_t length, + CHARSET_INFO *cs, bool send_error) const; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, @@ -3008,6 +3038,8 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result { public: virtual ~Type_handler_temporal_with_date() {} + Item_literal *create_literal_item(THD *thd, const char *str, size_t length, + CHARSET_INFO *cs, bool send_error) const; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const; int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const; @@ -3037,6 +3069,8 @@ public: { return MYSQL_TIMESTAMP_DATE; } + Item_literal *create_literal_item(THD *thd, const char *str, size_t length, + CHARSET_INFO *cs, bool send_error) const; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; bool Column_definition_fix_attributes(Column_definition *c) const; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c8eb1fce6c3..c484af0fb78 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9259,8 +9259,9 @@ history_point: TIMESTAMP TEXT_STRING { Item *item; - if (!(item= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, - MYSQL_TYPE_DATETIME, true))) + if (!(item= type_handler_datetime.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true))) MYSQL_YYABORT; $$= Vers_history_point(VERS_TIMESTAMP, item); } @@ -14801,26 +14802,23 @@ NUM_literal: temporal_literal: DATE_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATE, - true)))) + if (unlikely(!($$= type_handler_newdate.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIME_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_TIME, - true)))) + if (unlikely(!($$= type_handler_time2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIMESTAMP TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATETIME, - true)))) + if (unlikely(!($$= type_handler_datetime.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 8cd2ad598ea..6397654bc7d 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -9387,8 +9387,9 @@ history_point: TIMESTAMP TEXT_STRING { Item *item; - if (!(item= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, - MYSQL_TYPE_DATETIME, true))) + if (!(item= type_handler_datetime2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true))) MYSQL_YYABORT; $$= Vers_history_point(VERS_TIMESTAMP, item); } @@ -15046,26 +15047,23 @@ NUM_literal: temporal_literal: DATE_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATE, - true)))) + if (unlikely(!($$= type_handler_newdate.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIME_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_TIME, - true)))) + if (unlikely(!($$= type_handler_time2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIMESTAMP TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATETIME, - true)))) + if (unlikely(!($$= type_handler_datetime2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } ; |