summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-07-24 12:00:17 +0400
committerAlexander Barkov <bar@mariadb.com>2018-07-24 12:00:17 +0400
commita78d1aaaa349ebbe3400e48f63903b349050b316 (patch)
treeb20f70c785b6e84ae059357fa97d57c75685f8f8
parentfee463238793dcc196273654b6f6abd23a1b35ac (diff)
downloadmariadb-git-a78d1aaaa349ebbe3400e48f63903b349050b316.tar.gz
MDEV-16806 Add Type_handler::create_literal_item()
-rw-r--r--sql/item.cc14
-rw-r--r--sql/item.h28
-rw-r--r--sql/item_create.cc78
-rw-r--r--sql/item_create.h15
-rw-r--r--sql/sql_type.cc117
-rw-r--r--sql/sql_type.h34
-rw-r--r--sql/sql_yacc.yy26
-rw-r--r--sql/sql_yacc_ora.yy26
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, &ltime, flags, &status) &&
- ltime.time_type == MYSQL_TIMESTAMP_DATE && !status.warnings)
- item= new (thd->mem_root) Item_date_literal(thd, &ltime);
- break;
- case MYSQL_TYPE_DATETIME:
- if (!str_to_datetime(cs, str, length, &ltime, flags, &status) &&
- ltime.time_type == MYSQL_TIMESTAMP_DATETIME &&
- !have_important_literal_warnings(&status))
- item= new (thd->mem_root) Item_datetime_literal(thd, &ltime,
- status.precision);
- break;
- case MYSQL_TYPE_TIME:
- if (!str_to_time(cs, str, length, &ltime, 0, &status) &&
- ltime.time_type == MYSQL_TIMESTAMP_TIME &&
- !have_important_literal_warnings(&status))
- item= new (thd->mem_root) Item_time_literal(thd, &ltime,
- 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, &ltime, flags, &st) &&
+ ltime.time_type == MYSQL_TIMESTAMP_DATE && !st.warnings)
+ item= new (thd->mem_root) Item_date_literal(thd, &ltime);
+ literal_warn(thd, item, str, length, cs, &ltime, &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, &ltime, flags, &st) &&
+ ltime.time_type == MYSQL_TIMESTAMP_DATETIME &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_datetime_literal(thd, &ltime, st.precision);
+ literal_warn(thd, item, str, length, cs, &ltime, &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, &ltime, 0, &st) &&
+ ltime.time_type == MYSQL_TIMESTAMP_TIME &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_time_literal(thd, &ltime, st.precision);
+ literal_warn(thd, item, str, length, cs, &ltime, &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;
}
;