mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-16806 Add Type_handler::create_literal_item()
This commit is contained in:
14
sql/item.cc
14
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;
|
||||
}
|
||||
|
||||
|
||||
|
28
sql/item.h
28
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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
117
sql/sql_type.cc
117
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
;
|
||||
|
@ -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;
|
||||
}
|
||||
;
|
||||
|
Reference in New Issue
Block a user