diff --git a/sql/item.cc b/sql/item.cc index b955e4372e9..30e5725adca 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4043,6 +4043,23 @@ Item *Item_null::clone_item(THD *thd) return new (thd->mem_root) Item_null(thd, name.str); } + +Item_basic_constant * +Item_null::make_string_literal_concat(THD *thd, const LEX_CSTRING *str) +{ + DBUG_ASSERT(thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL); + if (str->length) + { + CHARSET_INFO *cs= thd->variables.collation_connection; + uint repertoire= my_string_repertoire(cs, str->str, str->length); + return new (thd->mem_root) Item_string(thd, + str->str, (uint) str->length, cs, + DERIVATION_COERCIBLE, repertoire); + } + return this; +} + + /*********************** Item_param related ******************************/ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg, @@ -6998,6 +7015,41 @@ Item *Item_string::clone_item(THD *thd) } +Item_basic_constant * +Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str) +{ + append(str->str, (uint32) str->length); + if (!(collation.repertoire & MY_REPERTOIRE_EXTENDED)) + { + // If the string has been pure ASCII so far, check the new part. + CHARSET_INFO *cs= thd->variables.collation_connection; + collation.repertoire|= my_string_repertoire(cs, str->str, str->length); + } + return this; +} + + +/* + If "this" 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'}; +*/ +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); + /* + create_temporal_literal() 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; +} + + static int save_int_value_in_field (Field *field, longlong nr, bool null_value, bool unsigned_flag) { diff --git a/sql/item.h b/sql/item.h index 860a1fb1bde..d2789d40664 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1554,6 +1554,10 @@ public: virtual Item *copy_andor_structure(THD *thd) { return this; } virtual Item *real_item() { return this; } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } + virtual Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) + { + return this; + } static CHARSET_INFO *default_charset(); @@ -2329,6 +2333,12 @@ public: void set_used_tables(table_map map) { used_table_map= map; } table_map used_tables() const { return used_table_map; } bool check_vcol_func_processor(void *arg) { return FALSE;} + virtual Item_basic_constant *make_string_literal_concat(THD *thd, + const LEX_CSTRING *) + { + DBUG_ASSERT(0); + return this; + } /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() { @@ -3169,6 +3179,8 @@ public: Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool check_partition_func_processor(void *int_arg) {return FALSE;} + Item_basic_constant *make_string_literal_concat(THD *thd, + const LEX_CSTRING *); Item *get_copy(THD *thd) { return get_item_copy(thd, this); } }; @@ -3956,7 +3968,10 @@ public: } 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); + Item *get_copy(THD *thd) { return get_item_copy(thd, this); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9e6eb1fc0e2..d3921ce51b1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2495,8 +2495,8 @@ bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) } -Item *THD::make_string_literal(const char *str, size_t length, - uint repertoire) +Item_basic_constant * +THD::make_string_literal(const char *str, size_t length, uint repertoire) { if (!length && (variables.sql_mode & MODE_EMPTY_STRING_IS_NULL)) return new (mem_root) Item_null(this, 0, variables.collation_connection); @@ -2517,7 +2517,8 @@ Item *THD::make_string_literal(const char *str, size_t length, } -Item *THD::make_string_literal_nchar(const Lex_string_with_metadata_st &str) +Item_basic_constant * +THD::make_string_literal_nchar(const Lex_string_with_metadata_st &str) { DBUG_ASSERT(my_charset_is_ascii_based(national_charset_info)); if (!str.length && (variables.sql_mode & MODE_EMPTY_STRING_IS_NULL)) @@ -2530,8 +2531,9 @@ Item *THD::make_string_literal_nchar(const Lex_string_with_metadata_st &str) } -Item *THD::make_string_literal_charset(const Lex_string_with_metadata_st &str, - CHARSET_INFO *cs) +Item_basic_constant * +THD::make_string_literal_charset(const Lex_string_with_metadata_st &str, + CHARSET_INFO *cs) { if (!str.length && (variables.sql_mode & MODE_EMPTY_STRING_IS_NULL)) return new (mem_root) Item_null(this, 0, cs); @@ -2540,34 +2542,6 @@ Item *THD::make_string_literal_charset(const Lex_string_with_metadata_st &str, } -Item *THD::make_string_literal_concat(Item *item, const LEX_CSTRING &str) -{ - if (item->type() == Item::NULL_ITEM) - { - DBUG_ASSERT(variables.sql_mode & MODE_EMPTY_STRING_IS_NULL); - if (str.length) - { - CHARSET_INFO *cs= variables.collation_connection; - uint repertoire= my_string_repertoire(cs, str.str, str.length); - return new (mem_root) Item_string(this, str.str, (uint)str.length, cs, - DERIVATION_COERCIBLE, repertoire); - } - return item; - } - - DBUG_ASSERT(item->type() == Item::STRING_ITEM); - DBUG_ASSERT(item->basic_const_item()); - static_cast(item)->append(str.str, (uint)str.length); - if (!(item->collation.repertoire & MY_REPERTOIRE_EXTENDED)) - { - // If the string has been pure ASCII so far, check the new part. - CHARSET_INFO *cs= variables.collation_connection; - item->collation.repertoire|= my_string_repertoire(cs, str.str, str.length); - } - return item; -} - - /* Update some cache variables when character set changes */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 61d80003046..0fc2830be7c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3721,17 +3721,16 @@ public: @param length - length of the string @param repertoire - the repertoire of the string */ - Item *make_string_literal(const char *str, size_t length, - uint repertoire); - Item *make_string_literal(const Lex_string_with_metadata_st &str) + Item_basic_constant *make_string_literal(const char *str, size_t length, + uint repertoire); + Item_basic_constant *make_string_literal(const Lex_string_with_metadata_st &str) { uint repertoire= str.repertoire(variables.character_set_client); return make_string_literal(str.str, str.length, repertoire); } - Item *make_string_literal_nchar(const Lex_string_with_metadata_st &str); - Item *make_string_literal_charset(const Lex_string_with_metadata_st &str, - CHARSET_INFO *cs); - Item *make_string_literal_concat(Item *item1, const LEX_CSTRING &str); + Item_basic_constant *make_string_literal_nchar(const Lex_string_with_metadata_st &str); + Item_basic_constant *make_string_literal_charset(const Lex_string_with_metadata_st &str, + CHARSET_INFO *cs); void add_changed_table(TABLE *table); void add_changed_table(const char *key, size_t key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, size_t key_length); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 393dcb8c900..919d792e618 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -807,6 +807,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) Item *item; Item_num *item_num; Item_param *item_param; + Item_basic_constant *item_basic_constant; Key_part_spec *key_part; LEX *lex; sp_assignment_lex *assignment_lex; @@ -1760,7 +1761,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); replace_lock_option opt_low_priority insert_lock_option load_data_lock %type - literal text_literal insert_ident order_ident temporal_literal + literal insert_ident order_ident temporal_literal simple_ident expr sum_expr in_sum_expr variable variable_aux bool_pri predicate bit_expr parenthesized_expr @@ -1792,6 +1793,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type NUM_literal +%type text_literal + %type expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else ident_list ident_list_arg opt_expr_list @@ -9948,27 +9951,8 @@ column_default_non_parenthesized_expr: } | '{' ident expr '}' { - $$= NULL; - /* - If "expr" is 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 ($3->type() == Item::STRING_ITEM) - { - Item_string *item= (Item_string *) $3; - enum_field_types type= item->odbc_temporal_literal_type(&$2); - if (type != MYSQL_TYPE_STRING) - { - $$= create_temporal_literal(thd, item->val_str(NULL), - type, false); - } - } - if ($$ == NULL) - $$= $3; + if (!($$= $3->make_odbc_literal(thd, &$2))) + MYSQL_YYABORT; } | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')' { @@ -14682,7 +14666,7 @@ text_literal: } | text_literal TEXT_STRING_literal { - if (!($$= thd->make_string_literal_concat($1, $2))) + if (!($$= $1->make_string_literal_concat(thd, &$2))) MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index bd1e47266b0..f357cc47903 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -198,6 +198,7 @@ void ORAerror(THD *thd, const char *s) Item *item; Item_num *item_num; Item_param *item_param; + Item_basic_constant *item_basic_constant; Key_part_spec *key_part; LEX *lex; sp_assignment_lex *assignment_lex; @@ -1156,7 +1157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); replace_lock_option opt_low_priority insert_lock_option load_data_lock %type - literal text_literal insert_ident order_ident temporal_literal + literal insert_ident order_ident temporal_literal simple_ident expr sum_expr in_sum_expr variable variable_aux bool_pri predicate bit_expr parenthesized_expr @@ -1189,6 +1190,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type NUM_literal +%type text_literal + %type expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else ident_list ident_list_arg opt_expr_list @@ -9727,27 +9730,8 @@ column_default_non_parenthesized_expr: } | '{' ident expr '}' { - $$= NULL; - /* - If "expr" is 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 ($3->type() == Item::STRING_ITEM) - { - Item_string *item= (Item_string *) $3; - enum_field_types type= item->odbc_temporal_literal_type(&$2); - if (type != MYSQL_TYPE_STRING) - { - $$= create_temporal_literal(thd, item->val_str(NULL), - type, false); - } - } - if ($$ == NULL) - $$= $3; + if (!($$= $3->make_odbc_literal(thd, &$2))) + MYSQL_YYABORT; } | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')' { @@ -14404,7 +14388,7 @@ text_literal: } | text_literal TEXT_STRING_literal { - if (!($$= thd->make_string_literal_concat($1, $2))) + if (!($$= $1->make_string_literal_concat(thd, &$2))) MYSQL_YYABORT; } ;