From 276b0c8ef03046cc210e4eeab7231cb8d9f16bac Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 2 May 2017 19:23:00 +0300 Subject: Fixed crash with SEQUENCE when using REPAIR --- mysql-test/suite/sql_sequence/other.result | 42 ++++++++++++++++++++++++++++++ mysql-test/suite/sql_sequence/other.test | 29 +++++++++++++++++++++ sql/ha_sequence.cc | 6 ++++- sql/sql_sequence.cc | 12 +++++---- sql/sql_sequence.h | 4 ++- 5 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/sql_sequence/other.result create mode 100644 mysql-test/suite/sql_sequence/other.test diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result new file mode 100644 index 00000000000..b9510d46de7 --- /dev/null +++ b/mysql-test/suite/sql_sequence/other.result @@ -0,0 +1,42 @@ +# +# Create and check +# +create sequence s1 engine=innodb; +check table s1; +Table Op Msg_type Msg_text +test.s1 check note The storage engine for the table doesn't support check +select next value for s1; +next value for s1 +1 +flush tables; +check table s1; +Table Op Msg_type Msg_text +test.s1 check note The storage engine for the table doesn't support check +select next value for s1; +next value for s1 +1001 +flush tables; +repair table s1; +Table Op Msg_type Msg_text +test.s1 repair note The storage engine for the table doesn't support repair +select next value for s1; +next value for s1 +2001 +drop sequence s1; +create or replace sequence s1 engine=innodb; +select next value for s1; +next value for s1 +1 +repair table s1; +Table Op Msg_type Msg_text +test.s1 repair note The storage engine for the table doesn't support repair +check table s1; +Table Op Msg_type Msg_text +test.s1 check note The storage engine for the table doesn't support check +select next value for s1; +next value for s1 +1001 +select * from s1; +next_value min_value max_value start increment cache cycle round +2001 1 9223372036854775806 1 1 1000 0 0 +drop sequence s1; diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test new file mode 100644 index 00000000000..c9ed326004a --- /dev/null +++ b/mysql-test/suite/sql_sequence/other.test @@ -0,0 +1,29 @@ +--source include/have_sequence.inc +--source include/have_innodb.inc + +# +# Test various combinations of operations on sequence +# + +--echo # +--echo # Create and check +--echo # + +create sequence s1 engine=innodb; +check table s1; +select next value for s1; +flush tables; +check table s1; +select next value for s1; +flush tables; +repair table s1; +select next value for s1; +drop sequence s1; + +create or replace sequence s1 engine=innodb; +select next value for s1; +repair table s1; +check table s1; +select next value for s1; +select * from s1; +drop sequence s1; diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 25a1a6e71c4..5ff5a4eb213 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -110,6 +110,8 @@ int ha_sequence::open(const char *name, int mode, uint flags) if ((error= table->s->sequence->read_initial_values(table))) file->ha_close(); } + else + table->m_needs_reopen= true; } DBUG_RETURN(error); } @@ -189,11 +191,13 @@ int ha_sequence::write_row(uchar *buf) DBUG_ASSERT(table->record[0] == buf); row_already_logged= 0; - if (!sequence->initialized) + if (unlikely(sequence->initialized == SEQUENCE::SEQ_IN_PREPARE)) { /* This calls is from ha_open() as part of create table */ DBUG_RETURN(file->write_row(buf)); } + if (unlikely(sequence->initialized != SEQUENCE::SEQ_READY_TO_USE)) + DBUG_RETURN(HA_ERR_WRONG_COMMAND); /* User tries to write a row diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 98912691904..6b0a03a4e07 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -327,7 +327,9 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list) tmp_disable_binlog(thd); save_write_set= table->write_set; table->write_set= &table->s->all_set; + table->s->sequence->initialized= SEQUENCE::SEQ_IN_PREPARE; error= table->file->ha_write_row(table->record[0]); + table->s->sequence->initialized= SEQUENCE::SEQ_UNINTIALIZED; reenable_binlog(thd); table->write_set= save_write_set; @@ -339,7 +341,7 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list) Sequence structure is up to date and table has one row, sequence is now usable */ - table->s->sequence->initialized= 1; + table->s->sequence->initialized= SEQUENCE::SEQ_READY_TO_USE; } trans_commit_stmt(thd); @@ -353,7 +355,7 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list) /* Create a SQUENCE object */ -SEQUENCE::SEQUENCE() :initialized(0), all_values_used(0), table(0) +SEQUENCE::SEQUENCE() :all_values_used(0), initialized(SEQ_UNINTIALIZED), table(0) { mysql_mutex_init(key_LOCK_SEQUENCE, &mutex, MY_MUTEX_INIT_SLOW); } @@ -376,11 +378,11 @@ int SEQUENCE::read_initial_values(TABLE *table_arg) MDL_request mdl_request; // Empty constructor! DBUG_ENTER("SEQUENCE::read_initial_values"); - if (likely(initialized)) + if (likely(initialized != SEQ_UNINTIALIZED)) DBUG_RETURN(0); table= table_arg; mysql_mutex_lock(&mutex); - if (unlikely(!initialized)) + if (likely(initialized == SEQ_UNINTIALIZED)) { MYSQL_LOCK *lock; bool mdl_lock_used= 0; @@ -419,7 +421,7 @@ int SEQUENCE::read_initial_values(TABLE *table_arg) DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT); } if (!(error= read_stored_values())) - initialized= 1; + initialized= SEQ_READY_TO_USE; mysql_unlock_tables(thd, lock, 0); if (mdl_lock_used) thd->mdl_context.release_lock(mdl_request.ticket); diff --git a/sql/sql_sequence.h b/sql/sql_sequence.h index f5534d55d9b..1409f86649f 100644 --- a/sql/sql_sequence.h +++ b/sql/sql_sequence.h @@ -66,6 +66,7 @@ public: class SEQUENCE :public sequence_definition { public: + enum seq_init { SEQ_UNINTIALIZED, SEQ_IN_PREPARE, SEQ_READY_TO_USE }; SEQUENCE(); ~SEQUENCE(); int read_initial_values(TABLE *table); @@ -87,8 +88,9 @@ public: } longlong next_value(TABLE *table, bool second_round, int *error); - bool initialized; // If row has been read bool all_values_used; + seq_init initialized; + private: TABLE *table; mysql_mutex_t mutex; -- cgit v1.2.1 From 1e04ad284c6ac0a9ce433f827bc6dbfbd6029007 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 7 May 2017 18:26:10 +0300 Subject: Fixed compiler warnings and warnings from build.tags Other things - Ensure that ut_d() is set to EXPR if ut_ad() is DEBUG_ASSERT() If not, we will get a crash in purge_sys_t::~purge_sys_t() as this ut_ad() code expect's that the ut_d() codes has been executed --- client/mysqlcheck.c | 2 ++ include/mysql/service_my_snprintf.h | 2 +- sql/item_cmpfunc.cc | 3 +-- sql/item_jsonfunc.cc | 2 ++ sql/opt_range.cc | 2 ++ sql/slave.cc | 3 +-- sql/sql_admin.cc | 2 ++ sql/sql_table.cc | 2 +- sql/sys_vars.ic | 2 ++ sql/table.cc | 6 ++++-- sql/wsrep_binlog.cc | 2 +- storage/connect/ha_connect.cc | 2 +- storage/connect/tabext.cpp | 2 +- storage/innobase/buf/buf0flu.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 4 ++-- storage/innobase/include/ut0dbg.h | 2 +- storage/innobase/include/ut0stage.h | 2 +- storage/maria/ma_create.c | 2 +- storage/maria/ma_ft_update.c | 2 ++ storage/myisam/ft_update.c | 2 ++ storage/myisam/mi_create.c | 2 +- support-files/build-tags | 2 +- 22 files changed, 33 insertions(+), 19 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index b47b9c98510..8bc6334448f 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -19,6 +19,8 @@ /* By Jani Tolonen, 2001-04-20, MySQL Development Team */ #define CHECK_VERSION "2.7.4-MariaDB" +/* Avoid warnings from %'s format */ +#define USING_MARIADB_SNPRINTF_EXTENSIONS #include "client_priv.h" #include diff --git a/include/mysql/service_my_snprintf.h b/include/mysql/service_my_snprintf.h index 586a539d48c..1b2ee2ca202 100644 --- a/include/mysql/service_my_snprintf.h +++ b/include/mysql/service_my_snprintf.h @@ -96,7 +96,7 @@ extern struct my_snprintf_service_st { #define ATTRIBUTE_FORMAT_DEFINED #define ATTRIBUTE_FORMAT(A,B,C) #endif -#ifdef MYSQL_ABI_CHECK +#if defined(MYSQL_ABI_CHECK) || defined(USING_MARIADB_SNPRINTF_EXTENSIONS) #undef ATTRIBUTE_FORMAT #define ATTRIBUTE_FORMAT(A,B,C) #endif diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 891a0c0f594..18c55d872db 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -479,7 +479,6 @@ void Item_bool_rowready_func2::fix_length_and_dec() int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg, Item **a1, Item **a2) { - THD *thd= current_thd; owner= owner_arg; set_null= set_null && owner_arg; a= a1; @@ -488,7 +487,7 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg, Type_handler_hybrid_field_type tmp; if (tmp.aggregate_for_comparison(owner_arg->func_name(), tmp_args, 2, false)) { - DBUG_ASSERT(thd->is_error()); + DBUG_ASSERT(current_thd->is_error()); return 1; } m_compare_handler= tmp.type_handler(); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index c7639bc2513..fd5b4a98e0e 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1258,6 +1258,7 @@ longlong Item_func_json_contains_path::val_int() longlong result; json_path_t p; int n_found; + LINT_INIT(n_found); if ((null_value= args[0]->null_value)) return 0; @@ -1985,6 +1986,7 @@ String *Item_func_json_merge::val_str(String *str) json_engine_t je1, je2; String *js1= args[0]->val_json(&tmp_js1), *js2; uint n_arg; + LINT_INIT(js2); if (args[0]->null_value) goto null_return; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 87cb16c96fe..284f4348080 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7501,6 +7501,8 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param, param->current_table); #ifdef HAVE_SPATIAL Field::geometry_type sav_geom_type; + LINT_INIT(sav_geom_type); + if (field_item->field->type() == MYSQL_TYPE_GEOMETRY) { sav_geom_type= ((Field_geom*) field_item->field)->geom_type; diff --git a/sql/slave.cc b/sql/slave.cc index b28bc1d8dc5..b2cbac44c1b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3728,8 +3728,7 @@ int apply_event_and_update_pos_for_parallel(Log_event* ev, THD* thd, rpl_group_info *rgi) { - Relay_log_info* rli= rgi->rli; - mysql_mutex_assert_not_owner(&rli->data_lock); + mysql_mutex_assert_not_owner(&rgi->rli->data_lock); int reason= apply_event_and_update_pos_setup(ev, thd, rgi); /* In parallel replication, sql_slave_skip_counter is handled in the SQL diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index f3ecee89a79..31933e63b4e 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -394,7 +394,9 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table, open_and_lock_tables(thd, table, TRUE, 0)); } +#ifndef DBUG_OFF dbug_err: +#endif thd->prepare_derived_at_open= FALSE; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 813c74b60b2..2ad8c2d5562 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2193,7 +2193,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; bool non_tmp_table_deleted= 0; bool is_drop_tmp_if_exists_added= 0; - bool was_view= 0, was_table, is_sequence; + bool was_view= 0, was_table= 0, is_sequence; String built_query; String built_trans_tmp_query, built_non_trans_tmp_query; DBUG_ENTER("mysql_rm_table_no_locks"); diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index a157538d528..f9acfb3b657 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -612,7 +612,9 @@ public: /* parse and feel list with default values */ if (thd) { +#ifndef DBUG_OFF bool res= +#endif sysvartrack_validate_value(thd, var->save_result.string_value.str, var->save_result.string_value.length); diff --git a/sql/table.cc b/sql/table.cc index fa8ed3c2587..9c3613a879c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1177,7 +1177,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, char *keynames, *names, *comment_pos; const uchar *forminfo, *extra2; const uchar *frm_image_end = frm_image + frm_length; - uchar *record, *null_flags, *null_pos, *mysql57_vcol_null_pos; + uchar *record, *null_flags, *null_pos, *mysql57_vcol_null_pos= 0; const uchar *disk_buff, *strpos; ulong pos, record_offset; ulong rec_buff_length; @@ -2387,6 +2387,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, DBUG_ASSERT(field_nr < share->fields); reg_field= share->field[field_nr]; } + else + reg_field= 0; // Safety vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE; vcol_info->set_vcol_type((enum_vcol_info_type) type); @@ -7368,7 +7370,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) DBUG_ASSERT(vcol_info); DBUG_ASSERT(vcol_info->expr); - bool update, swap_values= 0; + bool update= 0, swap_values= 0; switch (update_mode) { case VCOL_UPDATE_FOR_READ: update= !vcol_info->stored_in_db diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 42b7bc81261..ad5ef9c5c55 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -452,7 +452,7 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, File file; IO_CACHE cache; Log_event_writer writer(&cache, 0); - Format_description_log_event *ev; + Format_description_log_event *ev= 0; int len= my_snprintf(filename, PATH_MAX, "%s/GRA_%lld_%lld_v2.log", wsrep_data_home_dir, (longlong) thd->thread_id, diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 09681d4daa4..1b6078cc3d9 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -2692,7 +2692,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) htrc("Cond type=%d\n", cond->type()); if (cond->type() == COND::COND_ITEM) { - char *pb0, *pb1, *pb2, *ph0, *ph1, *ph2; + char *pb0, *pb1, *pb2, *ph0= 0, *ph1= 0, *ph2= 0; bool bb = false, bh = false; Item_cond *cond_item= (Item_cond *)cond; diff --git a/storage/connect/tabext.cpp b/storage/connect/tabext.cpp index e3518126a49..b099321eff5 100644 --- a/storage/connect/tabext.cpp +++ b/storage/connect/tabext.cpp @@ -293,7 +293,7 @@ bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt) if (Srcdef) { if ((catp = strstr(Srcdef, "%s"))) { - char *fil1, *fil2; + char *fil1= 0, *fil2; PSZ ph = ((EXTDEF*)To_Def)->Phpos; if (!ph) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index d0c0316bf13..7b0597f27ea 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1873,7 +1873,7 @@ buf_flush_batch( buf_pool_mutex_enter(buf_pool); - ulint count = 0; + ulint count __attribute__((unused))= 0; /* Note: The buffer pool mutex is released and reacquired within the flush functions. */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 37c4c09e553..45d00e9a2ff 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2046,7 +2046,7 @@ innobase_release_temporary_latches( DBUG_ASSERT(hton == innodb_hton_ptr); if (!srv_was_started) { - } else if (trx_t* trx = thd_to_trx(thd)) { + } else if (trx_t* trx __attribute__((unused))= thd_to_trx(thd)) { trx_assert_no_search_latch(trx); } @@ -13107,7 +13107,7 @@ create_table_info_t::set_tablespace_type( int create_table_info_t::initialize() { - trx_t* parent_trx; + trx_t* parent_trx __attribute__((unused)); DBUG_ENTER("create_table_info_t::initialize"); diff --git a/storage/innobase/include/ut0dbg.h b/storage/innobase/include/ut0dbg.h index 706579a3b9f..a860196e3db 100644 --- a/storage/innobase/include/ut0dbg.h +++ b/storage/innobase/include/ut0dbg.h @@ -62,7 +62,7 @@ ut_dbg_assertion_failed( /** Debug assertion */ #define ut_ad DBUG_ASSERT -#ifdef UNIV_DEBUG +#if defined(UNIV_DEBUG) || !defined(DBUG_OFF) /** Debug statement. Does nothing unless UNIV_DEBUG is defined. */ #define ut_d(EXPR) EXPR #else diff --git a/storage/innobase/include/ut0stage.h b/storage/innobase/include/ut0stage.h index baad5cd77b4..a4ff0a1c874 100644 --- a/storage/innobase/include/ut0stage.h +++ b/storage/innobase/include/ut0stage.h @@ -272,7 +272,7 @@ current phase. inline void ut_stage_alter_t::inc( - ulint inc_val /* = 1 */) + ulint inc_val __attribute__((unused)) /* = 1 */) { if (m_progress == NULL) { return; diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 0ddd8b226e2..959e31c3598 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -55,7 +55,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, uint internal_table= flags & HA_CREATE_INTERNAL_TABLE; ulong reclength, real_reclength,min_pack_length; char kfilename[FN_REFLEN], klinkname[FN_REFLEN], *klinkname_ptr; - char dfilename[FN_REFLEN], dlinkname[FN_REFLEN], *dlinkname_ptr; + char dfilename[FN_REFLEN], dlinkname[FN_REFLEN], *dlinkname_ptr= 0; ulong pack_reclength; ulonglong tot_length,max_rows, tmp; enum en_fieldtype type; diff --git a/storage/maria/ma_ft_update.c b/storage/maria/ma_ft_update.c index 51f27520dc1..ddf2a7251ab 100644 --- a/storage/maria/ma_ft_update.c +++ b/storage/maria/ma_ft_update.c @@ -28,6 +28,8 @@ void _ma_ft_segiterator_init(MARIA_HA *info, uint keynr, const uchar *record, ftsi->num=info->s->keyinfo[keynr].keysegs; ftsi->seg=info->s->keyinfo[keynr].seg; ftsi->rec=record; + ftsi->pos= 0; /* Avoid warnings from gcc */ + ftsi->len= 0; /* Avoid warnings from gcc */ DBUG_VOID_RETURN; } diff --git a/storage/myisam/ft_update.c b/storage/myisam/ft_update.c index 8f437476121..f851c0236ae 100644 --- a/storage/myisam/ft_update.c +++ b/storage/myisam/ft_update.c @@ -28,6 +28,8 @@ void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const uchar *record, ftsi->num=info->s->keyinfo[keynr].keysegs; ftsi->seg=info->s->keyinfo[keynr].seg; ftsi->rec=record; + ftsi->pos= 0; /* Avoid warnings from gcc */ + ftsi->len= 0; /* Avoid warnings from gcc */ DBUG_VOID_RETURN; } diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index c0967a60d13..ab45a16a96c 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -47,7 +47,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, uint internal_table= flags & HA_CREATE_INTERNAL_TABLE; ulong reclength, real_reclength,min_pack_length; char kfilename[FN_REFLEN],klinkname[FN_REFLEN], *klinkname_ptr; - char dfilename[FN_REFLEN],dlinkname[FN_REFLEN], *dlinkname_ptr; + char dfilename[FN_REFLEN],dlinkname[FN_REFLEN], *dlinkname_ptr= 0; ulong pack_reclength; ulonglong tot_length,max_rows, tmp; enum en_fieldtype type; diff --git a/support-files/build-tags b/support-files/build-tags index e0616661a75..8e8ed251cd7 100755 --- a/support-files/build-tags +++ b/support-files/build-tags @@ -8,7 +8,7 @@ then echo sql mysys strings client storage dbug libmysql sql-common \ extra mysys_ssl strings regex pcre vio include \ tools unittest plugin libmysqld | \ - xargs -n1 git ls-files | grep -v '\.jar$' | \ + xargs -n1 git ls-files | grep -v '\.jar$' | grep -v '\xz$' | xargs etags -o TAGS --append else find . -type f ! -name "*.jar" | -- cgit v1.2.1 From 71fa413c165e644f8f1433356f95fed12579fe3e Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 8 May 2017 02:44:55 +0300 Subject: MDEV-10139 Support for SEQUENCE objects - SETVAL(sequence_name, next_value, is_used, round) - ALTER SEQUENCE, including RESTART WITH Other things: - Added handler::extra() option HA_EXTRA_PREPARE_FOR_ALTER_TABLE to signal ha_sequence() that it should allow write_row statments. - ALTER ONLINE TABLE now works with SEQUENCE:s --- include/my_base.h | 4 +- mysql-test/r/mysqld--help.result | 2 +- mysql-test/suite/sql_sequence/alter.result | 238 +++++++++++++++ mysql-test/suite/sql_sequence/alter.test | 139 +++++++++ mysql-test/suite/sql_sequence/create.result | 2 + mysql-test/suite/sql_sequence/create.test | 2 + mysql-test/suite/sql_sequence/next.result | 10 + mysql-test/suite/sql_sequence/next.test | 3 +- mysql-test/suite/sql_sequence/setval.result | 246 ++++++++++++++++ mysql-test/suite/sql_sequence/setval.test | 126 ++++++++ .../sys_vars/r/sysvars_server_notembedded.result | 4 +- sql/ha_partition.cc | 1 + sql/ha_sequence.cc | 21 +- sql/ha_sequence.h | 4 + sql/item_func.cc | 75 ++++- sql/item_func.h | 22 ++ sql/lex.h | 2 + sql/mysqld.cc | 1 + sql/sp_head.cc | 1 + sql/sql_alter.h | 23 ++ sql/sql_cmd.h | 1 + sql/sql_lex.cc | 16 +- sql/sql_lex.h | 6 + sql/sql_parse.cc | 7 +- sql/sql_prepare.cc | 1 + sql/sql_sequence.cc | 320 ++++++++++++++++----- sql/sql_sequence.h | 37 ++- sql/sql_table.cc | 1 + sql/sql_yacc.yy | 83 +++++- sql/sql_yacc_ora.yy | 83 +++++- storage/mroonga/ha_mroonga.cpp | 3 + 31 files changed, 1399 insertions(+), 85 deletions(-) create mode 100644 mysql-test/suite/sql_sequence/alter.result create mode 100644 mysql-test/suite/sql_sequence/alter.test create mode 100644 mysql-test/suite/sql_sequence/setval.result create mode 100644 mysql-test/suite/sql_sequence/setval.test diff --git a/include/my_base.h b/include/my_base.h index ea8fd623b28..57b16ad985b 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -202,7 +202,9 @@ enum ha_extra_function { HA_EXTRA_DETACH_CHILDREN, HA_EXTRA_DETACH_CHILD, /* Inform handler we will force a close as part of flush */ - HA_EXTRA_PREPARE_FOR_FORCED_CLOSE + HA_EXTRA_PREPARE_FOR_FORCED_CLOSE, + /* Inform handler that we will do an alter table */ + HA_EXTRA_PREPARE_FOR_ALTER_TABLE, }; /* Compatible option, to be deleted in 6.0 */ diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 778bfb13bd3..09c8bf9813b 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1396,7 +1396,7 @@ performance-schema-max-rwlock-instances -1 performance-schema-max-socket-classes 10 performance-schema-max-socket-instances -1 performance-schema-max-stage-classes 150 -performance-schema-max-statement-classes 189 +performance-schema-max-statement-classes 190 performance-schema-max-table-handles -1 performance-schema-max-table-instances -1 performance-schema-max-thread-classes 50 diff --git a/mysql-test/suite/sql_sequence/alter.result b/mysql-test/suite/sql_sequence/alter.result new file mode 100644 index 00000000000..43afe2377c3 --- /dev/null +++ b/mysql-test/suite/sql_sequence/alter.result @@ -0,0 +1,238 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 'test.t1' +# +# Test alter sequence +# +CREATE SEQUENCE t1 nocache engine=myisam; +select * from t1; +next_value min_value max_value start increment cache cycle round +1 1 9223372036854775806 1 1 0 0 0 +select next value for t1; +next value for t1 +1 +alter sequence t1 start=50; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 50 minvalue 1 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +2 1 9223372036854775806 50 1 0 0 0 +select next value for t1; +next value for t1 +2 +alter sequence t1 minvalue=-100; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 50 minvalue -100 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +3 -100 9223372036854775806 50 1 0 0 0 +alter sequence t1 minvalue=100 start=100; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 100 minvalue 100 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +3 100 9223372036854775806 100 1 0 0 0 +alter sequence t1 maxvalue=500; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 100 minvalue 100 maxvalue 500 increment by 1 nocache nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +3 100 500 100 1 0 0 0 +drop sequence t1; +CREATE SEQUENCE t1 engine=myisam; +alter sequence t1 nocache; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=MyISAM +alter sequence t1 cache=100; +flush tables; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 100 nocycle ENGINE=MyISAM +alter sequence t1 nocache; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=MyISAM +flush tables; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +1 1 9223372036854775806 1 1 0 0 0 +select next value for t1; +next value for t1 +1 +select next value for t1; +next value for t1 +2 +select next value for t1; +next value for t1 +3 +select next_value, round from t1; +next_value round +4 0 +drop sequence t1; +CREATE SEQUENCE t1 maxvalue=100 engine=myisam; +alter sequence t1 no maxvalue; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +1 1 9223372036854775806 1 1 1000 0 0 +alter sequence t1 cycle; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 cycle ENGINE=MyISAM +alter sequence t1 nocycle; +alter sequence t1 start=15 restart minvalue=10 maxvalue=20 cycle; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 15 minvalue 10 maxvalue 20 increment by 1 cache 1000 cycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +15 10 20 15 1 1000 1 0 +select NEXT VALUE for t1 from seq_1_to_10; +NEXT VALUE for t1 +15 +16 +17 +18 +19 +20 +10 +11 +12 +13 +alter sequence t1 restart with 17 minvalue=10 maxvalue=20 cycle; +select NEXT VALUE for t1 from seq_1_to_10; +NEXT VALUE for t1 +17 +18 +19 +20 +10 +11 +12 +13 +14 +15 +drop sequence t1; +CREATE SEQUENCE t1 maxvalue=100; +alter sequence t1 increment=-2 start with 50 minvalue=-100; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 50 minvalue -100 maxvalue 100 increment by -2 cache 1000 nocycle ENGINE=MyISAM +select * from t1; +next_value min_value max_value start increment cache cycle round +1 -100 100 50 -2 1000 0 0 +select NEXT VALUE for t1 from seq_1_to_10; +NEXT VALUE for t1 +1 +-1 +-3 +-5 +-7 +-9 +-11 +-13 +-15 +-17 +drop sequence t1; +# +# InnoDB (some things work different with InnoDB) + +CREATE SEQUENCE t1 cache 10 engine=innodb; +select * from t1; +next_value min_value max_value start increment cache cycle round +1 1 9223372036854775806 1 1 10 0 0 +select next value for t1; +next value for t1 +1 +alter sequence t1 start=100; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 100 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 10 nocycle ENGINE=InnoDB +select * from t1; +next_value min_value max_value start increment cache cycle round +11 1 9223372036854775806 100 1 10 0 0 +select next value for t1; +next value for t1 +11 +drop sequence t1; +# +# ALTER TABLE +# +CREATE SEQUENCE t1 engine=innodb; +select next value for t1; +next value for t1 +1 +alter table t1 rename t2; +select next value for t2; +next value for t2 +1001 +rename table t2 to t1; +select next value for t1; +next value for t1 +2001 +alter table t1 comment="foo"; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB COMMENT='foo' +alter table t1 engine=myisam; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM COMMENT='foo' +alter table t1 engine=innodb; +show create sequence t1; +Table Create Table +t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB COMMENT='foo' +select * from t1; +next_value min_value max_value start increment cache cycle round +3001 1 9223372036854775806 1 1 1000 0 0 +drop sequence t1; +CREATE SEQUENCE t1 engine=myisam; +alter sequence t1 minvalue=100; +ERROR HY000: Sequence 'test.t1' values are conflicting +drop sequence t1; +CREATE SEQUENCE t1 engine=myisam; +alter sequence t1 minvalue=25 maxvalue=20; +ERROR HY000: Sequence 'test.t1' values are conflicting +drop sequence t1; +create table t1 (a int); +alter sequence t1 minvalue=100; +ERROR 42S02: 'test.t1' is not a SEQUENCE +drop table t1; +alter sequence if exists t1 minvalue=100; +Warnings: +Note 4067 Unknown SEQUENCE: 'test.t1' +alter sequence t1 minvalue=100; +ERROR 42S02: Table 'test.t1' doesn't exist +create sequence t1; +alter sequence t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1 +drop sequence t1; +CREATE SEQUENCE t1 maxvalue=100; +alter sequence t1 increment=-2 start with 50; +select next value for t1; +next value for t1 +1 +select next value for t1; +ERROR HY000: Sequence 'test.t1' has run out +select * from t1; +next_value min_value max_value start increment cache cycle round +0 1 100 50 -2 1000 0 0 +alter sequence t1 restart; +select next value for t1; +next value for t1 +50 +alter sequence t1 restart with 90; +select next value for t1; +next value for t1 +90 +drop sequence t1; diff --git a/mysql-test/suite/sql_sequence/alter.test b/mysql-test/suite/sql_sequence/alter.test new file mode 100644 index 00000000000..7454f5900f7 --- /dev/null +++ b/mysql-test/suite/sql_sequence/alter.test @@ -0,0 +1,139 @@ +--source include/have_sequence.inc +--source include/have_innodb.inc + +drop table if exists t1; + +--echo # +--echo # Test alter sequence +--echo # + +CREATE SEQUENCE t1 nocache engine=myisam; +select * from t1; +select next value for t1; +alter sequence t1 start=50; +show create sequence t1; +select * from t1; +select next value for t1; + +alter sequence t1 minvalue=-100; +show create sequence t1; +select * from t1; +alter sequence t1 minvalue=100 start=100; +show create sequence t1; +select * from t1; + +alter sequence t1 maxvalue=500; +show create sequence t1; +select * from t1; +drop sequence t1; + +CREATE SEQUENCE t1 engine=myisam; +alter sequence t1 nocache; +show create sequence t1; +alter sequence t1 cache=100; +flush tables; +show create sequence t1; +alter sequence t1 nocache; +show create sequence t1; +flush tables; +show create sequence t1; +select * from t1; +select next value for t1; +select next value for t1; +select next value for t1; +select next_value, round from t1; +drop sequence t1; + +CREATE SEQUENCE t1 maxvalue=100 engine=myisam; +alter sequence t1 no maxvalue; +show create sequence t1; +select * from t1; +alter sequence t1 cycle; +show create sequence t1; +alter sequence t1 nocycle; +alter sequence t1 start=15 restart minvalue=10 maxvalue=20 cycle; +show create sequence t1; +select * from t1; +select NEXT VALUE for t1 from seq_1_to_10; +alter sequence t1 restart with 17 minvalue=10 maxvalue=20 cycle; +select NEXT VALUE for t1 from seq_1_to_10; +drop sequence t1; + +CREATE SEQUENCE t1 maxvalue=100; +alter sequence t1 increment=-2 start with 50 minvalue=-100; +show create sequence t1; +select * from t1; +select NEXT VALUE for t1 from seq_1_to_10; +drop sequence t1; + +--echo # +--echo # InnoDB (some things work different with InnoDB) +--echo + +CREATE SEQUENCE t1 cache 10 engine=innodb; +select * from t1; +select next value for t1; +alter sequence t1 start=100; +show create sequence t1; +select * from t1; +select next value for t1; +drop sequence t1; + +--echo # +--echo # ALTER TABLE +--echo # + +CREATE SEQUENCE t1 engine=innodb; +select next value for t1; +alter table t1 rename t2; +select next value for t2; +rename table t2 to t1; +select next value for t1; +alter table t1 comment="foo"; +show create sequence t1; +alter table t1 engine=myisam; +show create sequence t1; +alter table t1 engine=innodb; +show create sequence t1; +select * from t1; +drop sequence t1; + +# +# Some error testing +# + +CREATE SEQUENCE t1 engine=myisam; +--error ER_SEQUENCE_INVALID_DATA +alter sequence t1 minvalue=100; +drop sequence t1; + +CREATE SEQUENCE t1 engine=myisam; +--error ER_SEQUENCE_INVALID_DATA +alter sequence t1 minvalue=25 maxvalue=20; +drop sequence t1; + +create table t1 (a int); +--error ER_NOT_SEQUENCE +alter sequence t1 minvalue=100; +drop table t1; + +alter sequence if exists t1 minvalue=100; +--error ER_NO_SUCH_TABLE +alter sequence t1 minvalue=100; + +create sequence t1; +--error ER_PARSE_ERROR +alter sequence t1; +drop sequence t1; + +CREATE SEQUENCE t1 maxvalue=100; +alter sequence t1 increment=-2 start with 50; +select next value for t1; +--error ER_SEQUENCE_RUN_OUT +select next value for t1; +select * from t1; +alter sequence t1 restart; +select next value for t1; +alter sequence t1 restart with 90; +select next value for t1; +drop sequence t1; diff --git a/mysql-test/suite/sql_sequence/create.result b/mysql-test/suite/sql_sequence/create.result index 59dfe62acee..4962752c7d9 100644 --- a/mysql-test/suite/sql_sequence/create.result +++ b/mysql-test/suite/sql_sequence/create.result @@ -186,6 +186,8 @@ create sequence t1 start with 10 maxvalue=9223372036854775807; ERROR HY000: Sequence 'test.t1' values are conflicting create sequence t1 start with 10 minvalue=-9223372036854775808; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '9223372036854775808' at line 1 +create sequence t1 RESTART WITH 10; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'RESTART' at line 1 create or replace sequence t1 start with 10 NO MINVALUE minvalue=1; drop sequence t1; create sequence t1; diff --git a/mysql-test/suite/sql_sequence/create.test b/mysql-test/suite/sql_sequence/create.test index 6cb6dedd91b..cf094c2cedd 100644 --- a/mysql-test/suite/sql_sequence/create.test +++ b/mysql-test/suite/sql_sequence/create.test @@ -118,6 +118,8 @@ create or replace sequence t1 start with 10 min_value=1 NO MINVALUE; create sequence t1 start with 10 maxvalue=9223372036854775807; --error ER_PARSE_ERROR create sequence t1 start with 10 minvalue=-9223372036854775808; +--error ER_PARSE_ERROR +create sequence t1 RESTART WITH 10; # This should probably give an error create or replace sequence t1 start with 10 NO MINVALUE minvalue=1; diff --git a/mysql-test/suite/sql_sequence/next.result b/mysql-test/suite/sql_sequence/next.result index fc28152a2b7..84f91bc0bdd 100644 --- a/mysql-test/suite/sql_sequence/next.result +++ b/mysql-test/suite/sql_sequence/next.result @@ -390,6 +390,16 @@ next_value min_value max_value start increment cache cycle round select next value for s1; next value for s1 3984356 +explain extended select next value for s1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select nextval(`test`.`s1`) AS `next value for s1` +explain extended select previous value for s1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select lastval(`test`.`s1`) AS `previous value for s1` drop sequence s1; create table t1 (a int); select next value for t1; diff --git a/mysql-test/suite/sql_sequence/next.test b/mysql-test/suite/sql_sequence/next.test index 426ee5709a1..472feafb2c6 100644 --- a/mysql-test/suite/sql_sequence/next.test +++ b/mysql-test/suite/sql_sequence/next.test @@ -182,9 +182,10 @@ drop table t1,s1; CREATE OR REPLACE SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999 INCREMENT BY 1 START WITH 3984356 nocache CYCLE engine='innodb'; select * from s1; select next value for s1; +explain extended select next value for s1; +explain extended select previous value for s1; drop sequence s1; - # # Some error testing # diff --git a/mysql-test/suite/sql_sequence/setval.result b/mysql-test/suite/sql_sequence/setval.result new file mode 100644 index 00000000000..2fe46ff90c2 --- /dev/null +++ b/mysql-test/suite/sql_sequence/setval.result @@ -0,0 +1,246 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 'test.t1' +# +# Test setval function +# +CREATE SEQUENCE t1 cache 10 engine=myisam; +select next_value,round from t1; +next_value round +1 0 +do setval(t1,10); +select next_value,round from t1; +next_value round +11 0 +select next value for t1; +next value for t1 +11 +do setval(t1,12,1); +select next_value,round from t1; +next_value round +21 0 +select next value for t1; +next value for t1 +13 +do setval(t1,15,0); +select next_value,round from t1; +next_value round +21 0 +select next value for t1; +next value for t1 +15 +select setval(t1,16,0); +setval(t1,16,0) +16 +select next value for t1; +next value for t1 +16 +do setval(t1,1000,0); +select next value for t1; +next value for t1 +1000 +select next_value,round from t1; +next_value round +1010 0 +do setval(t1,2000,0); +select next value for t1; +next value for t1 +2000 +select next_value,round from t1; +next_value round +2010 0 +select setval(t1,1000,0); +setval(t1,1000,0) +NULL +select next value for t1; +next value for t1 +2001 +select setval(t1,1000,TRUE); +setval(t1,1000,TRUE) +NULL +select next value for t1; +next value for t1 +2002 +select next_value,round from t1; +next_value round +2010 0 +select setval(t1,2002,0); +setval(t1,2002,0) +NULL +select next value for t1; +next value for t1 +2003 +select setval(t1,2010,0); +setval(t1,2010,0) +2010 +select next value for t1; +next value for t1 +2010 +select next_value,round from t1; +next_value round +2020 0 +drop sequence t1; +# +# Testing with cycle +# +CREATE SEQUENCE t1 cache=10 maxvalue=100 cycle engine=innodb; +select next_value,round from t1; +next_value round +1 0 +select setval(t1,100,0); +setval(t1,100,0) +100 +select next_value,round from t1; +next_value round +100 0 +select next value for t1; +next value for t1 +100 +select next_value,round from t1; +next_value round +101 0 +select setval(t1,100,0); +setval(t1,100,0) +NULL +select next_value,round from t1; +next_value round +101 0 +select next value for t1; +next value for t1 +1 +select next_value,round from t1; +next_value round +11 1 +select next value for t1; +next value for t1 +2 +select setval(t1,100,0,1); +setval(t1,100,0,1) +100 +select next_value,round from t1; +next_value round +100 1 +select next value for t1; +next value for t1 +100 +select setval(t1,100,1,2); +setval(t1,100,1,2) +100 +select next_value,round from t1; +next_value round +101 2 +select next value for t1; +next value for t1 +1 +select setval(t1,100,0,3); +setval(t1,100,0,3) +100 +select next_value,round from t1; +next_value round +100 3 +select next value for t1; +next value for t1 +100 +drop sequence t1; +# +# Testing extreme values +# +CREATE SEQUENCE t1 cache=10 maxvalue=100 engine=innodb; +select next_value,round from t1; +next_value round +1 0 +select setval(t1,200); +setval(t1,200) +200 +select next_value,round from t1; +next_value round +101 0 +select next value for t1; +ERROR HY000: Sequence 'test.t1' has run out +drop sequence t1; +CREATE SEQUENCE t1 cache=10 maxvalue=100 cycle engine=innodb; +select next_value,round from t1; +next_value round +1 0 +select setval(t1,200); +setval(t1,200) +200 +select next_value,round from t1; +next_value round +101 0 +select next value for t1; +next value for t1 +1 +drop sequence t1; +CREATE SEQUENCE t1 cache=10 maxvalue=0 increment=-10; +select setval(t1,-10); +setval(t1,-10) +-10 +select next_value,round from t1; +next_value round +-20 0 +select next value for t1; +next value for t1 +-20 +select setval(t1,-15); +setval(t1,-15) +NULL +select next_value,round from t1; +next_value round +-120 0 +select next value for t1; +next value for t1 +-30 +select setval(t1,-500,FALSE); +setval(t1,-500,FALSE) +-500 +select next value for t1; +next value for t1 +-500 +select next value for t1; +next value for t1 +-510 +select setval(t1,-525,0); +setval(t1,-525,0) +-525 +select next value for t1; +next value for t1 +-525 +select next value for t1; +next value for t1 +-535 +drop sequence t1; +CREATE SEQUENCE t1 cache=10 maxvalue=0 increment=-10; +select setval(t1,-10,0); +setval(t1,-10,0) +-10 +select next_value,round from t1; +next_value round +-10 0 +select next value for t1; +next value for t1 +-10 +drop sequence t1; +# +# Other testing +# +CREATE SEQUENCE t1; +select setval(t1,10,0),setval(t1,15,1),setval(t1,5,1); +setval(t1,10,0) setval(t1,15,1) setval(t1,5,1) +10 15 NULL +select next value for t1; +next value for t1 +16 +select next_value,round from t1; +next_value round +1016 0 +explain extended select setval(t1,100),setval(t1,100,TRUE),setval(t1,100,FALSE,50); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select setval(`test`.`t1`,100,1,0) AS `setval(t1,100)`,setval(`test`.`t1`,100,1,0) AS `setval(t1,100,TRUE)`,setval(`test`.`t1`,100,0,50) AS `setval(t1,100,FALSE,50)` +drop sequence t1; +create table t1 (a int); +select setval(t1,10); +ERROR 42S02: 'test.t1' is not a SEQUENCE +drop table t1; diff --git a/mysql-test/suite/sql_sequence/setval.test b/mysql-test/suite/sql_sequence/setval.test new file mode 100644 index 00000000000..fe0c0669494 --- /dev/null +++ b/mysql-test/suite/sql_sequence/setval.test @@ -0,0 +1,126 @@ +--source include/have_sequence.inc +--source include/have_innodb.inc + +drop table if exists t1; + +--echo # +--echo # Test setval function +--echo # + +CREATE SEQUENCE t1 cache 10 engine=myisam; +select next_value,round from t1; +do setval(t1,10); +select next_value,round from t1; +select next value for t1; +do setval(t1,12,1); +select next_value,round from t1; +select next value for t1; +do setval(t1,15,0); +select next_value,round from t1; +select next value for t1; +select setval(t1,16,0); +select next value for t1; +do setval(t1,1000,0); +select next value for t1; +select next_value,round from t1; +do setval(t1,2000,0); +select next value for t1; +select next_value,round from t1; +# Set smaller value +select setval(t1,1000,0); +select next value for t1; +select setval(t1,1000,TRUE); +select next value for t1; +select next_value,round from t1; +select setval(t1,2002,0); +select next value for t1; +select setval(t1,2010,0); +select next value for t1; +select next_value,round from t1; +drop sequence t1; + +--echo # +--echo # Testing with cycle +--echo # + +CREATE SEQUENCE t1 cache=10 maxvalue=100 cycle engine=innodb; +select next_value,round from t1; +select setval(t1,100,0); +select next_value,round from t1; +select next value for t1; +select next_value,round from t1; +select setval(t1,100,0); +select next_value,round from t1; +select next value for t1; +select next_value,round from t1; +select next value for t1; +select setval(t1,100,0,1); +select next_value,round from t1; +select next value for t1; +select setval(t1,100,1,2); +select next_value,round from t1; +select next value for t1; +select setval(t1,100,0,3); +select next_value,round from t1; +select next value for t1; +drop sequence t1; + +--echo # +--echo # Testing extreme values +--echo # + +CREATE SEQUENCE t1 cache=10 maxvalue=100 engine=innodb; +select next_value,round from t1; +select setval(t1,200); +select next_value,round from t1; +--error ER_SEQUENCE_RUN_OUT +select next value for t1; +drop sequence t1; + +CREATE SEQUENCE t1 cache=10 maxvalue=100 cycle engine=innodb; +select next_value,round from t1; +select setval(t1,200); +select next_value,round from t1; +select next value for t1; +drop sequence t1; + +CREATE SEQUENCE t1 cache=10 maxvalue=0 increment=-10; +select setval(t1,-10); +select next_value,round from t1; +select next value for t1; +select setval(t1,-15); +select next_value,round from t1; +select next value for t1; +select setval(t1,-500,FALSE); +select next value for t1; +select next value for t1; +select setval(t1,-525,0); +select next value for t1; +select next value for t1; +drop sequence t1; + +CREATE SEQUENCE t1 cache=10 maxvalue=0 increment=-10; +select setval(t1,-10,0); +select next_value,round from t1; +select next value for t1; +drop sequence t1; + +--echo # +--echo # Other testing +--echo # + +CREATE SEQUENCE t1; +select setval(t1,10,0),setval(t1,15,1),setval(t1,5,1); +select next value for t1; +select next_value,round from t1; +explain extended select setval(t1,100),setval(t1,100,TRUE),setval(t1,100,FALSE,50); +drop sequence t1; + +# +# Some error testing +# + +create table t1 (a int); +--error ER_NOT_SEQUENCE +select setval(t1,10); +drop table t1; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index fcc93fbac82..0c8647fc946 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -3063,9 +3063,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 189 +GLOBAL_VALUE 190 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 189 +DEFAULT_VALUE 190 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 6ce17090efd..f293c40ccdd 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -7149,6 +7149,7 @@ int ha_partition::extra(enum ha_extra_function operation) case HA_EXTRA_QUICK: case HA_EXTRA_PREPARE_FOR_DROP: case HA_EXTRA_FLUSH_CACHE: + case HA_EXTRA_PREPARE_FOR_ALTER_TABLE: { DBUG_RETURN(loop_extra(operation)); } diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 5ff5a4eb213..a918da92be2 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -201,7 +201,7 @@ int ha_sequence::write_row(uchar *buf) /* User tries to write a row - - Check that row is an accurate object + - Check that the new row is an accurate object - Update the first row in the table */ @@ -290,6 +290,25 @@ int ha_sequence::info(uint flag) DBUG_RETURN(false); } + +int ha_sequence::extra(enum ha_extra_function operation) +{ + if (operation == HA_EXTRA_PREPARE_FOR_ALTER_TABLE) + { + /* In case of ALTER TABLE allow ::write_row() to copy rows */ + sequence->initialized= SEQUENCE::SEQ_IN_PREPARE; + } + return file->extra(operation); +} + +bool ha_sequence::check_if_incompatible_data(HA_CREATE_INFO *create_info, + uint table_changes) +{ + /* Table definition is locked for SEQUENCE tables */ + return(COMPATIBLE_DATA_YES); +} + + int ha_sequence::external_lock(THD *thd, int lock_type) { int error= file->external_lock(thd, lock_type); diff --git a/sql/ha_sequence.h b/sql/ha_sequence.h index 3aacd62c5cb..f753d038114 100644 --- a/sql/ha_sequence.h +++ b/sql/ha_sequence.h @@ -84,6 +84,10 @@ public: int info(uint); LEX_CSTRING *engine_name() { return hton_name(file->ht); } int external_lock(THD *thd, int lock_type); + int extra(enum ha_extra_function operation); + /* For ALTER ONLINE TABLE */ + bool check_if_incompatible_data(HA_CREATE_INFO *create_info, + uint table_changes); /* Functions that are directly mapped to the underlying handler */ int rnd_init(bool scan) diff --git a/sql/item_func.cc b/sql/item_func.cc index 8df5c301f3a..c3048a04d61 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6786,7 +6786,7 @@ longlong Item_func_nextval::val_int() } } entry->null_value= null_value= 0; - value= table->s->sequence->next_value(table,0, &error); + value= table->s->sequence->next_value(table, 0, &error); entry->value= value; entry->set_version(table); @@ -6878,3 +6878,76 @@ longlong Item_func_lastval::val_int() null_value= entry->null_value; DBUG_RETURN(entry->value); } + + +/* + Sets next value to be returned from sequences + + SELECT setval('foo', 42, 0); Next nextval will return 43 + SELECT setval('foo', 42, 0, true); Same as above + SELECT setval('foo', 42, 0, false); Next nextval will return 42 +*/ + +longlong Item_func_setval::val_int() +{ + longlong value; + int error; + TABLE *table= table_list->table; + DBUG_ASSERT(table && table->s->sequence); + DBUG_ENTER("Item_func_setval::val_int"); + + value= nextval; + error= table->s->sequence->set_value(table, nextval, round, is_used); + if (error) + { + null_value= 1; + value= 0; + } + DBUG_RETURN(value); +} + + +/* Print for setval */ + +void Item_func_setval::print(String *str, enum_query_type query_type) +{ + char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; + const char *d_name= table_list->db, *t_name= table_list->table_name; + bool use_db_name= d_name && d_name[0]; + THD *thd= table_list->table->in_use; + + str->append(func_name()); + str->append('('); + + /* + for next_val we assume that table_list has been updated to contain + the current db. + */ + + if (lower_case_table_names > 0) + { + strmake(t_name_buff, t_name, MAX_ALIAS_NAME-1); + my_casedn_str(files_charset_info, t_name_buff); + t_name= t_name_buff; + if (use_db_name) + { + strmake(d_name_buff, d_name, MAX_ALIAS_NAME-1); + my_casedn_str(files_charset_info, d_name_buff); + d_name= d_name_buff; + } + } + + if (use_db_name) + { + append_identifier(thd, str, d_name, (uint)strlen(d_name)); + str->append('.'); + } + append_identifier(thd, str, t_name, (uint) strlen(t_name)); + str->append(','); + str->append_longlong(nextval); + str->append(','); + str->append_longlong(is_used); + str->append(','); + str->append_ulonglong(round); + str->append(')'); +} diff --git a/sql/item_func.h b/sql/item_func.h index 74c986545cd..18612dbe79f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2863,6 +2863,7 @@ public: } }; + /* Implementation for sequences: LASTVAL(sequence), PostgreSQL style */ class Item_func_lastval :public Item_func_nextval @@ -2877,6 +2878,27 @@ public: }; +/* Implementation for sequences: SETVAL(sequence), PostgreSQL style */ + +class Item_func_setval :public Item_func_nextval +{ + longlong nextval; + ulonglong round; + bool is_used; +public: + Item_func_setval(THD *thd, TABLE_LIST *table, longlong nextval_arg, + ulonglong round_arg, bool is_used_arg) + : Item_func_nextval(thd, table), + nextval(nextval_arg), round(round_arg), is_used(is_used_arg) + {} + longlong val_int(); + const char *func_name() const { return "setval"; } + void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + + Item *get_system_var(THD *thd, enum_var_type var_type, LEX_CSTRING name, LEX_CSTRING component); extern bool check_reserved_words(const LEX_CSTRING *name); diff --git a/sql/lex.h b/sql/lex.h index e67b207a75d..f2dac95fce5 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -522,6 +522,7 @@ static SYMBOL symbols[] = { { "REQUIRE", SYM(REQUIRE_SYM)}, { "RESET", SYM(RESET_SYM)}, { "RESIGNAL", SYM(RESIGNAL_SYM)}, + { "RESTART", SYM(RESTART_SYM)}, { "RESTORE", SYM(RESTORE_SYM)}, { "RESTRICT", SYM(RESTRICT)}, { "RESUME", SYM(RESUME_SYM)}, @@ -562,6 +563,7 @@ static SYMBOL symbols[] = { { "SESSION", SYM(SESSION_SYM)}, { "SERVER", SYM(SERVER_SYM)}, { "SET", SYM(SET)}, + { "SETVAL", SYM(SETVAL_SYM)}, { "SHARE", SYM(SHARE_SYM)}, { "SHOW", SYM(SHOW)}, { "SHUTDOWN", SYM(SHUTDOWN)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 065f4d83367..eb39e542c41 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3767,6 +3767,7 @@ SHOW_VAR com_status_vars[]= { {"alter_function", STMT_STATUS(SQLCOM_ALTER_FUNCTION)}, {"alter_procedure", STMT_STATUS(SQLCOM_ALTER_PROCEDURE)}, {"alter_server", STMT_STATUS(SQLCOM_ALTER_SERVER)}, + {"alter_sequence", STMT_STATUS(SQLCOM_ALTER_SEQUENCE)}, {"alter_table", STMT_STATUS(SQLCOM_ALTER_TABLE)}, {"alter_tablespace", STMT_STATUS(SQLCOM_ALTER_TABLESPACE)}, {"alter_user", STMT_STATUS(SQLCOM_ALTER_USER)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 12b956623f8..80730a9b060 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -260,6 +260,7 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_CREATE_USER: case SQLCOM_CREATE_ROLE: case SQLCOM_ALTER_TABLE: + case SQLCOM_ALTER_SEQUENCE: case SQLCOM_ALTER_USER: case SQLCOM_GRANT: case SQLCOM_GRANT_ROLE: diff --git a/sql/sql_alter.h b/sql/sql_alter.h index beec5090343..c0232dd7358 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -384,6 +384,29 @@ public: }; +/** + Sql_cmd_alter_sequence represents the ALTER SEQUENCE statement. +*/ +class Sql_cmd_alter_sequence : public Sql_cmd +{ +public: + /** + Constructor, used to represent a ALTER TABLE statement. + */ + Sql_cmd_alter_sequence() + {} + + ~Sql_cmd_alter_sequence() + {} + + enum_sql_command sql_command_code() const + { + return SQLCOM_ALTER_SEQUENCE; + } + bool execute(THD *thd); +}; + + /** Sql_cmd_alter_table_tablespace represents ALTER TABLE IMPORT/DISCARD TABLESPACE statements. diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 875dcf0e575..4ae9353d6ff 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -98,6 +98,7 @@ enum enum_sql_command { SQLCOM_EXECUTE_IMMEDIATE, SQLCOM_CREATE_SEQUENCE, SQLCOM_DROP_SEQUENCE, + SQLCOM_ALTER_SEQUENCE, /* When a command is added here, be sure it's also added in mysqld.cc diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3c8f088d196..8cabe795d21 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -6404,7 +6404,6 @@ Item *LEX::create_item_func_nextval(THD *thd, Table_ident *table_ident) MDL_SHARED_WRITE))) return NULL; return new (thd->mem_root) Item_func_nextval(thd, table); - } @@ -6442,6 +6441,21 @@ Item *LEX::create_item_func_lastval(THD *thd, } +Item *LEX::create_item_func_setval(THD *thd, Table_ident *table_ident, + longlong nextval, ulonglong round, + bool is_used) +{ + TABLE_LIST *table; + if (!(table= current_select->add_table_to_list(thd, table_ident, 0, + TL_OPTION_SEQUENCE, + TL_WRITE_ALLOW_WRITE, + MDL_SHARED_WRITE))) + return NULL; + return new (thd->mem_root) Item_func_setval(thd, table, nextval, round, + is_used); +} + + Item *LEX::create_item_ident(THD *thd, const LEX_CSTRING *a, const LEX_CSTRING *b, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b90d3402afe..85ce07be5a8 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3275,6 +3275,12 @@ public: Item *create_item_func_lastval(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *name); + /* + Create an item for "SETVAL(sequence_name, value [, is_used [, round]]) + */ + Item *create_item_func_setval(THD *thd, Table_ident *ident, longlong value, + ulonglong round, bool is_used); + /* Create an item for a name in LIMIT clause: LIMIT var @param THD - THD, for mem_root diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b6955ee885f..edf4f77f70c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -454,6 +454,7 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask) (thd->variables.option_bits & OPTION_GTID_BEGIN)); break; case SQLCOM_ALTER_TABLE: + case SQLCOM_ALTER_SEQUENCE: /* If ALTER TABLE of non-temporary table, do implicit commit */ skip= (lex->tmp_table()); break; @@ -555,6 +556,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | CF_INSERTS_DATA; + sql_command_flags[SQLCOM_ALTER_SEQUENCE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | + CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; @@ -6213,9 +6216,11 @@ end_with_restore_list: case SQLCOM_REPAIR: case SQLCOM_TRUNCATE: case SQLCOM_ALTER_TABLE: - thd->query_plan_flags|= QPLAN_ADMIN; DBUG_ASSERT(first_table == all_tables && first_table != 0); /* fall through */ + case SQLCOM_ALTER_SEQUENCE: + thd->query_plan_flags|= QPLAN_ADMIN; + /* fall through */ case SQLCOM_SIGNAL: case SQLCOM_RESIGNAL: case SQLCOM_GET_DIAGNOSTICS: diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 2a523fd61b7..0e15bf45cc7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2480,6 +2480,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_DROP_SEQUENCE: case SQLCOM_RENAME_TABLE: case SQLCOM_ALTER_TABLE: + case SQLCOM_ALTER_SEQUENCE: case SQLCOM_COMMIT: case SQLCOM_CREATE_INDEX: case SQLCOM_DROP_INDEX: diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 6b0a03a4e07..a6e7b073251 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -22,6 +22,7 @@ #include "sql_base.h" #include "transaction.h" #include "lock.h" +#include "sql_acl.h" struct Field_definition { @@ -162,7 +163,7 @@ void sequence_definition::store_fields(TABLE *table) /* - Check the sequence fields through seq_fields when create sequence.qq + Check the sequence fields through seq_fields when createing a sequence. RETURN VALUES false Success @@ -269,7 +270,6 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list) Reprepare_observer *save_reprepare_observer; sequence_definition *seq= lex->create_info.seq_create_info; bool temporary_table= table_list->table != 0; - MY_BITMAP *save_write_set; DBUG_ENTER("sequence_insert"); /* If not temporary table */ @@ -316,33 +316,7 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list) } seq->reserved_until= seq->start; - seq->store_fields(table); - /* Store the sequence values in table share */ - table->s->sequence->copy(seq); - - /* - Sequence values will be replicated as a statement - like 'create sequence'. So disable binary log temporarily - */ - tmp_disable_binlog(thd); - save_write_set= table->write_set; - table->write_set= &table->s->all_set; - table->s->sequence->initialized= SEQUENCE::SEQ_IN_PREPARE; - error= table->file->ha_write_row(table->record[0]); - table->s->sequence->initialized= SEQUENCE::SEQ_UNINTIALIZED; - reenable_binlog(thd); - table->write_set= save_write_set; - - if (error) - table->file->print_error(error, MYF(0)); - else - { - /* - Sequence structure is up to date and table has one row, - sequence is now usable - */ - table->s->sequence->initialized= SEQUENCE::SEQ_READY_TO_USE; - } + error= seq->write_initial_sequence(table); trans_commit_stmt(thd); trans_commit_implicit(thd); @@ -463,7 +437,7 @@ int SEQUENCE::read_stored_values() DBUG_RETURN(error); } read_fields(table); - adjust_values(); + adjust_values(reserved_until); all_values_used= 0; DBUG_RETURN(0); @@ -474,12 +448,12 @@ int SEQUENCE::read_stored_values() Adjust values after reading a the stored state */ -void SEQUENCE::adjust_values() +void SEQUENCE::adjust_values(longlong next_value) { - offset= 0; - next_free_value= reserved_until; + next_free_value= next_value; if (!(real_increment= increment)) { + longlong offset= 0; longlong off, to_add; /* Use auto_increment_increment and auto_increment_offset */ @@ -514,6 +488,72 @@ void SEQUENCE::adjust_values() } +/** + Write initial sequence information for CREATE and ALTER to sequence table +*/ + +int sequence_definition::write_initial_sequence(TABLE *table) +{ + int error; + THD *thd= table->in_use; + MY_BITMAP *save_write_set; + + store_fields(table); + /* Store the sequence values in table share */ + table->s->sequence->copy(this); + /* + Sequence values will be replicated as a statement + like 'create sequence'. So disable binary log temporarily + */ + tmp_disable_binlog(thd); + save_write_set= table->write_set; + table->write_set= &table->s->all_set; + table->s->sequence->initialized= SEQUENCE::SEQ_IN_PREPARE; + error= table->file->ha_write_row(table->record[0]); + table->s->sequence->initialized= SEQUENCE::SEQ_UNINTIALIZED; + reenable_binlog(thd); + table->write_set= save_write_set; + if (error) + table->file->print_error(error, MYF(0)); + else + { + /* + Sequence structure is up to date and table has one row, + sequence is now usable + */ + table->s->sequence->initialized= SEQUENCE::SEQ_READY_TO_USE; + } + return error; +} + + +/** + Store current sequence values into the sequence table +*/ + +int sequence_definition::write(TABLE *table) +{ + int error; + MY_BITMAP *save_rpl_write_set, *save_write_set; + + /* Log a full insert (ok as table is small) */ + save_rpl_write_set= table->rpl_write_set; + + /* Update table */ + save_write_set= table->write_set; + table->rpl_write_set= table->write_set= &table->s->all_set; + store_fields(table); + /* Tell ha_sequence::write_row that we already hold the mutex */ + ((ha_sequence*) table->file)->sequence_locked= 1; + if ((error= table->file->ha_write_row(table->record[0]))) + table->file->print_error(error, MYF(0)); + ((ha_sequence*) table->file)->sequence_locked= 0; + table->rpl_write_set= save_rpl_write_set; + table->write_set= save_write_set; + return error; +} + + /** Get next value for sequence @@ -546,7 +586,6 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) { longlong res_value, org_reserved_until, add_to; bool out_of_values; - MY_BITMAP *save_rpl_write_set, *save_write_set; DBUG_ENTER("SEQUENCE::next_value"); *error= 0; @@ -554,24 +593,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) lock(); res_value= next_free_value; - - /* Increment next_free_value */ - if (real_increment > 0) - { - if (next_free_value + real_increment > max_value || - next_free_value > max_value - real_increment) - next_free_value= max_value + 1; - else - next_free_value+= real_increment; - } - else - { - if (next_free_value + real_increment < min_value || - next_free_value < min_value - real_increment) - next_free_value= min_value - 1; - else - next_free_value+= real_increment; - } + next_free_value= increment_value(next_free_value); if ((real_increment > 0 && res_value < reserved_until) || (real_increment < 0 && res_value > reserved_until)) @@ -621,7 +643,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) goto err; round++; reserved_until= real_increment >0 ? min_value : max_value; - adjust_values(); // Fix next_free_value + adjust_values(reserved_until); // Fix next_free_value /* We have to do everything again to ensure that the given range was not empty, which could happen if increment == 0 @@ -629,25 +651,11 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) DBUG_RETURN(next_value(table, 1, error)); } - /* Log a full insert (ok as table is small) */ - save_rpl_write_set= table->rpl_write_set; - - /* Update table */ - save_write_set= table->write_set; - table->rpl_write_set= table->write_set= &table->s->all_set; - store_fields(table); - /* Tell ha_sequence::write_row that we already hold the mutex */ - ((ha_sequence*) table->file)->sequence_locked= 1; - if ((*error= table->file->ha_write_row(table->record[0]))) + if ((*error= write(table))) { - table->file->print_error(*error, MYF(0)); - /* Restore original range */ reserved_until= org_reserved_until; next_free_value= res_value; } - ((ha_sequence*) table->file)->sequence_locked= 0; - table->rpl_write_set= save_rpl_write_set; - table->write_set= save_write_set; unlock(); DBUG_RETURN(res_value); @@ -681,3 +689,179 @@ void SEQUENCE_LAST_VALUE::set_version(TABLE *table) { memcpy(table_version, table->s->tabledef_version.str, MY_UUID_SIZE); } + +/** + Set the next value for sequence + + @param in table Sequence table + @param in next_val Next free value + @param in next_round Round for 'next_value' (in cace of cycles) + @param in is_used 1 if next_val is already used + +  @retval 0 ok, value adjusted + 1 value was less than current value or + error when storing value + + @comment + A new value is set only if "nextval,next_round" is less than + "next_free_value,round". This is needed as in replication + setvalue() calls may come out to the slave out-of-order. + Storing only the highest value ensures that sequence object will always + contain the highest used value when the slave is promoted to a master. +*/ + +bool SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round, + bool is_used) +{ + bool error= 1; + bool needs_to_be_stored= 0; + longlong org_reserved_until= reserved_until; + longlong org_next_free_value= next_free_value; + ulonglong org_round= round; + DBUG_ENTER("SEQUENCE::set_value"); + + lock(); + if (is_used) + next_val= increment_value(next_val); + + if (round > next_round) + goto end; + if (round == next_round) + { + if (real_increment > 0 ? + next_val < next_free_value : + next_val > next_free_value) + goto end; + if (next_val == next_free_value) + { + error= 0; + goto end; + } + } + else if (cycle == 0) + goto end; // round < next_round && no cycles + else + needs_to_be_stored= 1; + + round= next_round; + adjust_values(next_val); + if ((real_increment > 0 ? + next_free_value > reserved_until : + next_free_value < reserved_until) || + needs_to_be_stored) + { + reserved_until= next_free_value; + if (write(table)) + { + reserved_until= org_reserved_until; + next_free_value= org_next_free_value; + round= org_round; + goto end; + } + } + error= 0; + +end: + unlock(); + DBUG_RETURN(error); +} + + +bool Sql_cmd_alter_sequence::execute(THD *thd) +{ + int error= 0; + int trapped_errors= 0; + LEX *lex= thd->lex; + TABLE_LIST *first_table= lex->query_tables; + TABLE *table; + sequence_definition *new_seq= lex->create_info.seq_create_info; + SEQUENCE *seq; + No_such_table_error_handler no_such_table_handler; + DBUG_ENTER("Sql_cmd_alter_sequence::execute"); + + if (check_access(thd, ALTER_ACL, first_table->db, + &first_table->grant.privilege, + &first_table->grant.m_internal, + 0, 0)) + DBUG_RETURN(TRUE); /* purecov: inspected */ + + if (check_grant(thd, ALTER_ACL, first_table, FALSE, UINT_MAX, FALSE)) + DBUG_RETURN(TRUE); /* purecov: inspected */ + + if (lex->check_exists) + thd->push_internal_handler(&no_such_table_handler); + error= open_and_lock_tables(thd, first_table, FALSE, 0); + if (lex->check_exists) + { + trapped_errors= no_such_table_handler.safely_trapped_errors(); + thd->pop_internal_handler(); + } + if (error) + { + if (trapped_errors) + { + StringBuffer tbl_name; + tbl_name.append(first_table->db); + tbl_name.append('.'); + tbl_name.append(first_table->table_name); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_SEQUENCES, + ER_THD(thd, ER_UNKNOWN_SEQUENCES), + tbl_name.c_ptr_safe()); + my_ok(thd); + DBUG_RETURN(FALSE); + } + DBUG_RETURN(TRUE); + } + + table= first_table->table; + seq= table->s->sequence; + new_seq->reserved_until= seq->reserved_until; + + /* Copy from old sequence those fields that the user didn't specified */ + if (!(new_seq->used_fields & seq_field_used_increment)) + new_seq->increment= seq->increment; + if (!(new_seq->used_fields & seq_field_used_min_value)) + new_seq->min_value= seq->min_value; + if (!(new_seq->used_fields & seq_field_used_max_value)) + new_seq->max_value= seq->max_value; + if (!(new_seq->used_fields & seq_field_used_start)) + new_seq->start= seq->start; + if (!(new_seq->used_fields & seq_field_used_cache)) + new_seq->cache= seq->cache; + if (!(new_seq->used_fields & seq_field_used_cycle)) + new_seq->cycle= seq->cycle; + + /* If we should restart from a new value */ + if (new_seq->used_fields & seq_field_used_restart) + { + if (!(new_seq->used_fields & seq_field_used_restart_value)) + new_seq->restart= new_seq->start; + new_seq->reserved_until= new_seq->restart; + } + + /* Let check_and_adjust think all fields are used */ + new_seq->used_fields= ~0; + if (new_seq->check_and_adjust()) + { + my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), + first_table->db, + first_table->table_name); + error= 1; + goto end; + } + + if (!(error= new_seq->write(table))) + { + /* Store the sequence values in table share */ + table->s->sequence->copy(new_seq); + } + trans_commit_stmt(thd); + trans_commit_implicit(thd); + if (!error) + my_ok(thd); + +end: + close_thread_tables(thd); + DBUG_RETURN(error); +} diff --git a/sql/sql_sequence.h b/sql/sql_sequence.h index 1409f86649f..ffe5ded4cff 100644 --- a/sql/sql_sequence.h +++ b/sql/sql_sequence.h @@ -20,6 +20,11 @@ #define seq_field_used_min_value 1 #define seq_field_used_max_value 2 #define seq_field_used_start 4 +#define seq_field_used_increment 8 +#define seq_field_used_cache 16 +#define seq_field_used_cycle 32 +#define seq_field_used_restart 64 +#define seq_field_used_restart_value 128 /** sequence_definition is used when defining a sequence as part of create @@ -41,11 +46,14 @@ public: ulonglong round; bool cycle; uint used_fields; // Which fields where used in CREATE + longlong restart; // alter sequence restart value bool check_and_adjust(); void store_fields(TABLE *table); void read_fields(TABLE *table); - void print_dbug() + int write_initial_sequence(TABLE *table); + int write(TABLE *table); + inline void print_dbug() { DBUG_PRINT("sequence", ("reserved: %lld start: %lld increment: %lld min_value: %lld max_value: %lld cache: %lld round: %lld", reserved_until, start, increment, min_value, @@ -80,13 +88,35 @@ public: mysql_mutex_unlock(&mutex); } /* This must be called after sequence data has been updated */ - void adjust_values(); + void adjust_values(longlong next_value); void copy(sequence_definition *seq) { sequence_definition::operator= (*seq); - adjust_values(); + adjust_values(reserved_until); } longlong next_value(TABLE *table, bool second_round, int *error); + bool set_value(TABLE *table, longlong next_value, ulonglong round_arg, + bool is_used); + longlong increment_value(longlong value) + { + if (real_increment > 0) + { + if (value + real_increment > max_value || + value > max_value - real_increment) + value= max_value + 1; + else + value+= real_increment; + } + else + { + if (value + real_increment < min_value || + value < min_value - real_increment) + value= min_value - 1; + else + value+= real_increment; + } + return value; + } bool all_values_used; seq_init initialized; @@ -100,7 +130,6 @@ private: merged with global auto_increment_offset and auto_increment_increment */ longlong real_increment; - longlong offset; }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2ad8c2d5562..f985f6e73fc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9631,6 +9631,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, thd->abort_on_warning= !ignore && thd->is_strict_mode(); from->file->info(HA_STATUS_VARIABLE); + to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE); to->file->ha_start_bulk_insert(from->file->stats.records, ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e8120c325fb..c065cd7dcf7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1386,6 +1386,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token REPLICATION %token REQUIRE_SYM %token RESET_SYM +%token RESTART_SYM %token RESIGNAL_SYM /* SQL-2003-R */ %token RESOURCES %token RESTORE_SYM @@ -1427,6 +1428,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SERVER_SYM %token SERVER_OPTIONS %token SET /* SQL-2003-R */ +%token SETVAL_SYM /* PostgreSQL sequence function */ %token SET_VAR %token SHARE_SYM %token SHIFT_LEFT /* OPERATOR */ @@ -1699,7 +1701,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ws_nweights ws_level_flag_desc ws_level_flag_reverse ws_level_flags opt_ws_levels ws_level_list ws_level_list_item ws_level_number - ws_level_range ws_level_list_or_range + ws_level_range ws_level_list_or_range bool %type ulonglong_num real_ulonglong_num size_number @@ -2632,14 +2634,15 @@ sequence_def: { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; } | NOMINVALUE_SYM { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; } | MAXVALUE_SYM opt_equal longlong_num - { Lex->create_info.seq_create_info->max_value= $3; Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; @@ -2648,11 +2651,13 @@ sequence_def: { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; } | NOMAXVALUE_SYM { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; } | START_SYM opt_with longlong_num { @@ -2662,22 +2667,46 @@ sequence_def: | INCREMENT_SYM opt_by longlong_num { Lex->create_info.seq_create_info->increment= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_increment; } | CACHE_SYM opt_equal longlong_num { Lex->create_info.seq_create_info->cache= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache; } | NOCACHE_SYM { Lex->create_info.seq_create_info->cache= 0; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache; } | CYCLE_SYM { Lex->create_info.seq_create_info->cycle= 1; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle; } | NOCYCLE_SYM { Lex->create_info.seq_create_info->cycle= 0; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle; + } + | RESTART_SYM + { + if (Lex->sql_command != SQLCOM_ALTER_SEQUENCE) + { + thd->parse_error(ER_SYNTAX_ERROR, "RESTART"); + YYABORT; + } + Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart; + } + | RESTART_SYM opt_with longlong_num + { + if (Lex->sql_command != SQLCOM_ALTER_SEQUENCE) + { + thd->parse_error(ER_SYNTAX_ERROR, "RESTART"); + YYABORT; + } + Lex->create_info.seq_create_info->restart= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart | seq_field_used_restart_value; } ; @@ -7276,6 +7305,33 @@ alter: Lex->create_info.set($2); Lex->sql_command= SQLCOM_ALTER_USER; } + | ALTER SEQUENCE_SYM opt_if_exists_table_element + { + LEX *lex= Lex; + lex->name= null_clex_str; + lex->table_type= TABLE_TYPE_UNKNOWN; + lex->sql_command= SQLCOM_ALTER_SEQUENCE; + lex->create_info.init(); + lex->no_write_to_binlog= 0; + DBUG_ASSERT(!lex->m_sql_cmd); + } + table_ident + { + LEX *lex= Lex; + if (!(lex->create_info.seq_create_info= new (thd->mem_root) + sequence_definition()) || + !lex->select_lex.add_table_to_list(thd, $5, NULL, + TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) + MYSQL_YYABORT; + } + sequence_defs + { + /* Create a generic ALTER SEQUENCE statment. */ + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence(); + if (Lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } ; ev_alter_on_schedule_completion: @@ -9408,6 +9464,21 @@ column_default_non_parenthesized_expr: if (!($$= Lex->create_item_func_lastval(thd, $3))) MYSQL_YYABORT; } + | SETVAL_SYM '(' table_ident ',' longlong_num ')' + { + if (!($$= Lex->create_item_func_setval(thd, $3, $5, 0, 1))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ')' + { + if (!($$= Lex->create_item_func_setval(thd, $3, $5, 0, $7))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ',' ulonglong_num ')' + { + if (!($$= Lex->create_item_func_setval(thd, $3, $5, $9, $7))) + MYSQL_YYABORT; + } ; simple_expr: @@ -11953,6 +12024,12 @@ choice: | DEFAULT { $$= HA_CHOICE_UNDEF; } ; +bool: + ulong_num { $$= $1 != 0; } + | TRUE_SYM { $$= 1; } + | FALSE_SYM { $$= 0; } + + procedure_clause: PROCEDURE_SYM ident /* Procedure name */ { @@ -14787,6 +14864,7 @@ keyword_sp_not_data_type: | REPEATABLE_SYM {} | REPLICATION {} | RESOURCES {} + | RESTART_SYM {} | RESUME_SYM {} | RETURNED_SQLSTATE_SYM {} | RETURNS_SYM {} @@ -14806,6 +14884,7 @@ keyword_sp_not_data_type: | SEQUENCE_SYM {} | SERIALIZABLE_SYM {} | SESSION_SYM {} + | SETVAL_SYM {} | SIMPLE_SYM {} | SHARE_SYM {} | SLAVE_POS_SYM {} diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 91b541410bc..61577b53006 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -795,6 +795,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token REPLICATION %token REQUIRE_SYM %token RESET_SYM +%token RESTART_SYM %token RESIGNAL_SYM /* SQL-2003-R */ %token RESOURCES %token RESTORE_SYM @@ -836,6 +837,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SERVER_SYM %token SERVER_OPTIONS %token SET /* SQL-2003-R */ +%token SETVAL_SYM /* PostgreSQL sequence function */ %token SET_VAR %token SHARE_SYM %token SHIFT_LEFT /* OPERATOR */ @@ -1117,7 +1119,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ws_nweights ws_level_flag_desc ws_level_flag_reverse ws_level_flags opt_ws_levels ws_level_list ws_level_list_item ws_level_number - ws_level_range ws_level_list_or_range + ws_level_range ws_level_list_or_range bool %type ulonglong_num real_ulonglong_num size_number @@ -2073,14 +2075,15 @@ sequence_def: { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; } | NOMINVALUE_SYM { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; } | MAXVALUE_SYM opt_equal longlong_num - { Lex->create_info.seq_create_info->max_value= $3; Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; @@ -2089,11 +2092,13 @@ sequence_def: { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; } | NOMAXVALUE_SYM { if (Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value) MYSQL_YYABORT; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; } | START_SYM opt_with longlong_num { @@ -2103,22 +2108,46 @@ sequence_def: | INCREMENT_SYM opt_by longlong_num { Lex->create_info.seq_create_info->increment= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_increment; } | CACHE_SYM opt_equal longlong_num { Lex->create_info.seq_create_info->cache= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache; } | NOCACHE_SYM { Lex->create_info.seq_create_info->cache= 0; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache; } | CYCLE_SYM { Lex->create_info.seq_create_info->cycle= 1; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle; } | NOCYCLE_SYM { Lex->create_info.seq_create_info->cycle= 0; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle; + } + | RESTART_SYM + { + if (Lex->sql_command != SQLCOM_ALTER_SEQUENCE) + { + thd->parse_error(ER_SYNTAX_ERROR, "RESTART"); + YYABORT; + } + Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart; + } + | RESTART_SYM opt_with longlong_num + { + if (Lex->sql_command != SQLCOM_ALTER_SEQUENCE) + { + thd->parse_error(ER_SYNTAX_ERROR, "RESTART"); + YYABORT; + } + Lex->create_info.seq_create_info->restart= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart | seq_field_used_restart_value; } ; @@ -7259,6 +7288,33 @@ alter: Lex->create_info.set($2); Lex->sql_command= SQLCOM_ALTER_USER; } + | ALTER SEQUENCE_SYM opt_if_exists_table_element + { + LEX *lex= Lex; + lex->name= null_clex_str; + lex->table_type= TABLE_TYPE_UNKNOWN; + lex->sql_command= SQLCOM_ALTER_SEQUENCE; + lex->create_info.init(); + lex->no_write_to_binlog= 0; + DBUG_ASSERT(!lex->m_sql_cmd); + } + table_ident + { + LEX *lex= Lex; + if (!(lex->create_info.seq_create_info= new (thd->mem_root) + sequence_definition()) || + !lex->select_lex.add_table_to_list(thd, $5, NULL, + TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) + MYSQL_YYABORT; + } + sequence_defs + { + /* Create a generic ALTER SEQUENCE statment. */ + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence(); + if (Lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } ; ev_alter_on_schedule_completion: @@ -9460,6 +9516,21 @@ column_default_non_parenthesized_expr: if (!($$= Lex->create_item_func_lastval(thd, $3))) MYSQL_YYABORT; } + | SETVAL_SYM '(' table_ident ',' longlong_num ')' + { + if (!($$= Lex->create_item_func_setval(thd, $3, $5, 0, 1))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ')' + { + if (!($$= Lex->create_item_func_setval(thd, $3, $5, 0, $7))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ',' ulonglong_num ')' + { + if (!($$= Lex->create_item_func_setval(thd, $3, $5, $9, $7))) + MYSQL_YYABORT; + } ; simple_expr: @@ -12035,6 +12106,12 @@ choice: | DEFAULT { $$= HA_CHOICE_UNDEF; } ; +bool: + ulong_num { $$= $1 != 0; } + | TRUE_SYM { $$= 1; } + | FALSE_SYM { $$= 0; } + + procedure_clause: PROCEDURE_SYM ident /* Procedure name */ { @@ -14981,6 +15058,7 @@ keyword_sp_not_data_type: | REPEATABLE_SYM {} | REPLICATION {} | RESOURCES {} + | RESTART_SYM {} | RESUME_SYM {} | RETURNED_SQLSTATE_SYM {} | RETURNS_SYM {} @@ -14999,6 +15077,7 @@ keyword_sp_not_data_type: | SEQUENCE_SYM {} | SERIALIZABLE_SYM {} | SESSION_SYM {} + | SETVAL_SYM {} | SIMPLE_SYM {} | SHARE_SYM {} | SLAVE_POS_SYM {} diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 2c83c3f891e..cb353db53b0 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -463,6 +463,9 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation) case HA_EXTRA_PREPARE_FOR_DROP: inspected = "HA_EXTRA_PREPARE_FOR_DROP"; break; + case HA_EXTRA_PREPARE_FOR_ALTER_TABLE: + inspected = "HA_EXTRA_PREPARE_FOR_ALTER_TABLE"; + break; case HA_EXTRA_PREPARE_FOR_UPDATE: inspected = "HA_EXTRA_PREPARE_FOR_UPDATE"; break; -- cgit v1.2.1 From 18ad176809999275ac7e86a586d41c8c9141f4a4 Mon Sep 17 00:00:00 2001 From: halfspawn Date: Thu, 4 May 2017 15:57:19 +0200 Subject: MDEV-12685 Oracle-compatible function CHR() --- mysql-test/extra/rpl_tests/rpl_charset.test | 28 ++++++++++++ mysql-test/r/func_str.result | 16 +++++++ mysql-test/suite/rpl/r/rpl_charset.result | 23 ++++++++++ mysql-test/t/func_str.test | 10 +++++ sql/item_create.cc | 24 ++++++++++ sql/item_strfunc.cc | 68 +++++++++++++++++++---------- sql/item_strfunc.h | 18 ++++++++ 7 files changed, 164 insertions(+), 23 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_charset.test b/mysql-test/extra/rpl_tests/rpl_charset.test index 37ca2e28eec..e67122cbb4c 100644 --- a/mysql-test/extra/rpl_tests/rpl_charset.test +++ b/mysql-test/extra/rpl_tests/rpl_charset.test @@ -117,4 +117,32 @@ update t1 set pk='test' where pk=@p; drop table t1; # End of 4.1 tests + + +--echo # +--echo # Start of 10.3 tests +--echo # + + +--echo # +--echo # MDEV-12685 Oracle-compatible function CHR() +--echo # + +connection master; +CREATE DATABASE db1 DEFAULT CHARACTER SET latin1 COLLATE latin1_bin; +USE db1; +CREATE TABLE t1 AS SELECT CHR(0x60); +sync_slave_with_master; +SHOW CREATE TABLE db1.t1; +connection master; +USE test; +DROP DATABASE db1; +sync_slave_with_master; + + +--echo # +--echo # End of 10.3 tests +--echo # + + --source include/rpl_end.inc diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 9d3e5587426..6ba3a5a8ace 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -4843,6 +4843,22 @@ YQ== 61 Yq== 62 DROP TABLE t1; # +# MDEV-12685 Oracle-compatible function CHR() +# +select chr(65); +chr(65) +A +create database mysqltest1 CHARACTER SET = 'utf8' COLLATE = 'utf8_bin'; +use mysqltest1; +select charset(chr(65)), length(chr(65)),char_length(chr(65)); +charset(chr(65)) length(chr(65)) char_length(chr(65)) +utf8 1 1 +select charset(chr(14844588)), length(chr(14844588)),char_length(chr(14844588)); +charset(chr(14844588)) length(chr(14844588)) char_length(chr(14844588)) +utf8 3 1 +drop database mysqltest1; +use test; +# # End of 10.1 tests # # diff --git a/mysql-test/suite/rpl/r/rpl_charset.result b/mysql-test/suite/rpl/r/rpl_charset.result index a96cb26dd9d..5bda623172b 100644 --- a/mysql-test/suite/rpl/r/rpl_charset.result +++ b/mysql-test/suite/rpl/r/rpl_charset.result @@ -121,4 +121,27 @@ primary key (`pk`) set @p=_latin1 'test'; update t1 set pk='test' where pk=@p; drop table t1; +# +# Start of 10.3 tests +# +# +# MDEV-12685 Oracle-compatible function CHR() +# +connection master; +CREATE DATABASE db1 DEFAULT CHARACTER SET latin1 COLLATE latin1_bin; +USE db1; +CREATE TABLE t1 AS SELECT CHR(0x60); +connection slave; +SHOW CREATE TABLE db1.t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `CHR(0x60)` varchar(4) COLLATE latin1_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_bin +connection master; +USE test; +DROP DATABASE db1; +connection slave; +# +# End of 10.3 tests +# include/rpl_end.inc diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index bb3251b3e31..29a9510db00 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1853,6 +1853,16 @@ SELECT f1,HEX(f2) FROM t1 WHERE f1='YQ==' AND (f2= from_base64( SELECT f1,HEX(f2) FROM t1 WHERE f1='YQ==' AND (f2= from_base64("Yq==") OR f2= from_base64("YQ==")); DROP TABLE t1; +--echo # +--echo # MDEV-12685 Oracle-compatible function CHR() +--echo # +select chr(65); +create database mysqltest1 CHARACTER SET = 'utf8' COLLATE = 'utf8_bin'; +use mysqltest1; +select charset(chr(65)), length(chr(65)),char_length(chr(65)); +select charset(chr(14844588)), length(chr(14844588)),char_length(chr(14844588)); +drop database mysqltest1; +use test; --echo # --echo # End of 10.1 tests diff --git a/sql/item_create.cc b/sql/item_create.cc index f678bb44f21..75c2189e86c 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -517,6 +517,19 @@ protected: }; +class Create_func_chr : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_chr s_singleton; + +protected: + Create_func_chr() {} + virtual ~Create_func_chr() {} +}; + + class Create_func_convexhull : public Create_func_arg1 { public: @@ -3788,6 +3801,16 @@ Create_func_centroid::create_1_arg(THD *thd, Item *arg1) } +Create_func_chr Create_func_chr::s_singleton; + +Item* +Create_func_chr::create_1_arg(THD *thd, Item *arg1) +{ + CHARSET_INFO *cs_db= thd->variables.collation_database; + return new (thd->mem_root) Item_func_chr(thd, arg1, cs_db); +} + + Create_func_convexhull Create_func_convexhull::s_singleton; Item* @@ -6831,6 +6854,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)}, { { C_STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)}, { { C_STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)}, + { { C_STRING_WITH_LEN("CHR") }, BUILDER(Create_func_chr)}, { { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)}, { { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)}, { { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)}, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4cf3a54af90..64dcc6b65fa 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2905,29 +2905,51 @@ String *Item_func_char::val_str(String *str) { int32 num=(int32) args[i]->val_int(); if (!args[i]->null_value) - { - char tmp[4]; - if (num & 0xFF000000L) - { - mi_int4store(tmp, num); - str->append(tmp, 4, &my_charset_bin); - } - else if (num & 0xFF0000L) - { - mi_int3store(tmp, num); - str->append(tmp, 3, &my_charset_bin); - } - else if (num & 0xFF00L) - { - mi_int2store(tmp, num); - str->append(tmp, 2, &my_charset_bin); - } - else - { - tmp[0]= (char) num; - str->append(tmp, 1, &my_charset_bin); - } - } + append_char(str, num); + } + str->realloc(str->length()); // Add end 0 (for Purify) + return check_well_formed_result(str); +} + + +void Item_func_char::append_char(String *str, int32 num) +{ + char tmp[4]; + if (num & 0xFF000000L) + { + mi_int4store(tmp, num); + str->append(tmp, 4, &my_charset_bin); + } + else if (num & 0xFF0000L) + { + mi_int3store(tmp, num); + str->append(tmp, 3, &my_charset_bin); + } + else if (num & 0xFF00L) + { + mi_int2store(tmp, num); + str->append(tmp, 2, &my_charset_bin); + } + else + { + tmp[0]= (char) num; + str->append(tmp, 1, &my_charset_bin); + } +} + + +String *Item_func_chr::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + str->length(0); + str->set_charset(collation.collation); + int32 num=(int32) args[0]->val_int(); + if (!args[0]->null_value) + append_char(str, num); + else + { + null_value= 1; + return 0; } 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 267408187f3..6e31d489574 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -946,7 +946,11 @@ public: Item_func_char(THD *thd, List &list, CHARSET_INFO *cs): Item_str_func(thd, list) { collation.set(cs); } + Item_func_char(THD *thd, Item *arg1, CHARSET_INFO *cs): + Item_str_func(thd, arg1) + { collation.set(cs); } String *val_str(String *); + void append_char(String * str, int32 num); void fix_length_and_dec() { max_length= arg_count * 4; @@ -956,6 +960,20 @@ public: { return get_item_copy(thd, mem_root, this); } }; +class Item_func_chr :public Item_func_char +{ +public: + Item_func_chr(THD *thd, Item *arg1, CHARSET_INFO *cs): + Item_func_char(thd, arg1, cs) {} + String *val_str(String *); + void fix_length_and_dec() + { + max_length= 4; + } + const char *func_name() const { return "chr"; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; class Item_func_repeat :public Item_str_func { -- cgit v1.2.1 From cd32f842148d57c33e13a22a663278b7faa4ed24 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 10 May 2017 08:30:56 +0400 Subject: MDEV-12770 Add Type_handler::decimal_precision() + MDEV-12769 This patch for MDEV-12770 is also fixing: MDEV-12769 Arithmetic operators with temporal types create excessive column types --- mysql-test/r/func_time.result | 18 +++++----- mysql-test/r/type_datetime_hires.result | 12 +++---- mysql-test/r/type_time.result | 12 +++---- mysql-test/r/type_time_hires.result | 12 +++---- mysql-test/r/type_timestamp_hires.result | 12 +++---- sql/item.cc | 22 ------------- sql/item.h | 5 ++- sql/sql_type.cc | 56 ++++++++++++++++++++++++++++++++ sql/sql_type.h | 14 ++++++++ 9 files changed, 107 insertions(+), 56 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index a05c6a78cdb..4a37c56d28f 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -950,10 +950,10 @@ sec_to_time(1) + 0, from_unixtime(1) + 0; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `now() - now()` bigint(21) NOT NULL, - `curtime() - curtime()` bigint(12) NOT NULL, - `sec_to_time(1) + 0` bigint(12) DEFAULT NULL, - `from_unixtime(1) + 0` bigint(21) DEFAULT NULL + `now() - now()` bigint(16) NOT NULL, + `curtime() - curtime()` int(9) NOT NULL, + `sec_to_time(1) + 0` int(9) DEFAULT NULL, + `from_unixtime(1) + 0` bigint(16) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; SELECT SEC_TO_TIME(3300000); @@ -2054,11 +2054,11 @@ SEC_TO_TIME(1.123456)+0.1, SEC_TO_TIME(1.1234567)+0.1; SHOW COLUMNS FROM t1; Field Type Null Key Default Extra -SEC_TO_TIME(1)+0.1 decimal(12,1) YES NULL -SEC_TO_TIME(1.1)+0.1 decimal(13,1) YES NULL -SEC_TO_TIME(1.12)+0.1 decimal(14,2) YES NULL -SEC_TO_TIME(1.123456)+0.1 decimal(18,6) YES NULL -SEC_TO_TIME(1.1234567)+0.1 decimal(18,6) YES NULL +SEC_TO_TIME(1)+0.1 decimal(9,1) YES NULL +SEC_TO_TIME(1.1)+0.1 decimal(9,1) YES NULL +SEC_TO_TIME(1.12)+0.1 decimal(10,2) YES NULL +SEC_TO_TIME(1.123456)+0.1 decimal(14,6) YES NULL +SEC_TO_TIME(1.1234567)+0.1 decimal(14,6) YES NULL DROP TABLE t1; CREATE TABLE t1 (a DATE) ENGINE=MyISAM; INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); diff --git a/mysql-test/r/type_datetime_hires.result b/mysql-test/r/type_datetime_hires.result index e2c2f83a96c..003ecf15e69 100644 --- a/mysql-test/r/type_datetime_hires.result +++ b/mysql-test/r/type_datetime_hires.result @@ -131,18 +131,18 @@ show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `a` datetime(4) DEFAULT NULL, - `a+0` decimal(25,4) DEFAULT NULL, - `a-1` decimal(25,4) DEFAULT NULL, - `a*1` decimal(25,4) DEFAULT NULL, - `a/2` decimal(28,8) DEFAULT NULL + `a+0` decimal(19,4) DEFAULT NULL, + `a-1` decimal(19,4) DEFAULT NULL, + `a*1` decimal(19,4) DEFAULT NULL, + `a/2` decimal(22,8) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `max(a)` datetime(4) DEFAULT NULL, `min(a)` datetime(4) DEFAULT NULL, - `sum(a)` decimal(46,4) DEFAULT NULL, - `avg(a)` decimal(28,8) DEFAULT NULL + `sum(a)` decimal(40,4) DEFAULT NULL, + `avg(a)` decimal(22,8) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2, t3; create table t1 (f0_datetime datetime(0), f1_datetime datetime(1), f2_datetime datetime(2), f3_datetime datetime(3), f4_datetime datetime(4), f5_datetime datetime(5), f6_datetime datetime(6)); diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index 3f125598f9b..8e1b626342a 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -221,7 +221,7 @@ MAX(t0)+1 101011 SHOW COLUMNS FROM t2; Field Type Null Key Default Extra -MAX(t0)+1 bigint(12) YES NULL +MAX(t0)+1 int(9) YES NULL DROP TABLE t2,t1; CREATE TABLE t1 (t0 TIME); INSERT INTO t1 VALUES ('10:10:10'); @@ -234,7 +234,7 @@ MAX(t0)+1.1 101011.1 SHOW COLUMNS FROM t2; Field Type Null Key Default Extra -MAX(t0)+1.1 decimal(12,1) YES NULL +MAX(t0)+1.1 decimal(9,1) YES NULL DROP TABLE t2,t1; CREATE TABLE t1 (t0 TIME); INSERT INTO t1 VALUES ('10:10:10'); @@ -260,7 +260,7 @@ MAX(t1)+1 101011.0 SHOW COLUMNS FROM t2; Field Type Null Key Default Extra -MAX(t1)+1 decimal(13,1) YES NULL +MAX(t1)+1 decimal(9,1) YES NULL DROP TABLE t2,t1; CREATE TABLE t1 (t0 DATETIME); INSERT INTO t1 VALUES ('2001-01-01 10:10:10'); @@ -273,7 +273,7 @@ MAX(t0)+1 20010101101011 SHOW COLUMNS FROM t2; Field Type Null Key Default Extra -MAX(t0)+1 bigint(21) YES NULL +MAX(t0)+1 bigint(16) YES NULL DROP TABLE t2,t1; CREATE TABLE t1 (t0 DATETIME); INSERT INTO t1 VALUES ('2001-01-01 10:10:10'); @@ -286,7 +286,7 @@ MAX(t0)+1.1 20010101101011.1 SHOW COLUMNS FROM t2; Field Type Null Key Default Extra -MAX(t0)+1.1 decimal(21,1) YES NULL +MAX(t0)+1.1 decimal(16,1) YES NULL DROP TABLE t2,t1; CREATE TABLE t1 (t0 DATETIME); INSERT INTO t1 VALUES ('2001-01-01 10:10:10'); @@ -312,7 +312,7 @@ MAX(t1)+1 20010101101011.0 SHOW COLUMNS FROM t2; Field Type Null Key Default Extra -MAX(t1)+1 decimal(22,1) YES NULL +MAX(t1)+1 decimal(16,1) YES NULL DROP TABLE t2,t1; # # MDEV-4858 Wrong results for a huge unsigned value inserted into a TIME column diff --git a/mysql-test/r/type_time_hires.result b/mysql-test/r/type_time_hires.result index a9345a7e83f..47185116bea 100644 --- a/mysql-test/r/type_time_hires.result +++ b/mysql-test/r/type_time_hires.result @@ -145,18 +145,18 @@ show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `a` time(4) DEFAULT NULL, - `a+0` decimal(16,4) DEFAULT NULL, - `a-1` decimal(16,4) DEFAULT NULL, - `a*1` decimal(16,4) DEFAULT NULL, - `a/2` decimal(19,8) DEFAULT NULL + `a+0` decimal(12,4) DEFAULT NULL, + `a-1` decimal(12,4) DEFAULT NULL, + `a*1` decimal(12,4) DEFAULT NULL, + `a/2` decimal(15,8) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `max(a)` time(4) DEFAULT NULL, `min(a)` time(4) DEFAULT NULL, - `sum(a)` decimal(37,4) DEFAULT NULL, - `avg(a)` decimal(19,8) DEFAULT NULL + `sum(a)` decimal(33,4) DEFAULT NULL, + `avg(a)` decimal(15,8) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2, t3; create table t1 (f0_time time(0), f1_time time(1), f2_time time(2), f3_time time(3), f4_time time(4), f5_time time(5), f6_time time(6)); diff --git a/mysql-test/r/type_timestamp_hires.result b/mysql-test/r/type_timestamp_hires.result index 7179277aa9a..fa6adc075ed 100644 --- a/mysql-test/r/type_timestamp_hires.result +++ b/mysql-test/r/type_timestamp_hires.result @@ -131,18 +131,18 @@ show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `a` timestamp(4) NOT NULL DEFAULT current_timestamp(4) ON UPDATE current_timestamp(4), - `a+0` decimal(25,4) NOT NULL, - `a-1` decimal(25,4) NOT NULL, - `a*1` decimal(25,4) NOT NULL, - `a/2` decimal(28,8) DEFAULT NULL + `a+0` decimal(19,4) NOT NULL, + `a-1` decimal(19,4) NOT NULL, + `a*1` decimal(19,4) NOT NULL, + `a/2` decimal(22,8) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `max(a)` timestamp(4) NULL DEFAULT NULL, `min(a)` timestamp(4) NULL DEFAULT NULL, - `sum(a)` decimal(46,4) DEFAULT NULL, - `avg(a)` decimal(28,8) DEFAULT NULL + `sum(a)` decimal(40,4) DEFAULT NULL, + `avg(a)` decimal(22,8) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2, t3; create table t1 (f0_timestamp timestamp(0), f1_timestamp timestamp(1), f2_timestamp timestamp(2), f3_timestamp timestamp(3), f4_timestamp timestamp(4), f5_timestamp timestamp(5), f6_timestamp timestamp(6)); diff --git a/sql/item.cc b/sql/item.cc index e775862ca3a..3ecca83ea17 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -541,28 +541,6 @@ Item::Item(THD *thd, Item *item): } -uint Item::decimal_precision() const -{ - Item_result restype= result_type(); - - if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - { - uint prec= - my_decimal_length_to_precision(max_char_length(), decimals, - unsigned_flag); - return MY_MIN(prec, DECIMAL_MAX_PRECISION); - } - uint res= max_char_length(); - /* - Return at least one decimal digit, even if Item::max_char_length() - returned 0. This is important to avoid attempts to create fields of types - INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL: - CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a; - */ - return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1; -} - - void Item::print_parenthesised(String *str, enum_query_type query_type, enum precedence parent_prec) { diff --git a/sql/item.h b/sql/item.h index ad34320c560..c81f4833ebd 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1143,7 +1143,10 @@ public: inline uint float_length(uint decimals_par) const { return decimals < FLOATING_POINT_DECIMALS ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} /* Returns total number of decimal digits */ - virtual uint decimal_precision() const; + virtual uint decimal_precision() const + { + return type_handler()->Item_decimal_precision(this); + } /* Returns the number of integer part digits only */ inline int decimal_int_part() const { return my_decimal_int_part(decimal_precision(), decimals); } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 7d0bd9004da..f632b47680c 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3953,6 +3953,62 @@ uint Type_handler_temporal_result:: /***************************************************************************/ +uint Type_handler_string_result::Item_decimal_precision(const Item *item) const +{ + uint res= item->max_char_length(); + /* + Return at least one decimal digit, even if Item::max_char_length() + returned 0. This is important to avoid attempts to create fields of types + INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL: + CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a; + */ + return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1; +} + +uint Type_handler_real_result::Item_decimal_precision(const Item *item) const +{ + uint res= item->max_char_length(); + return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1; +} + +uint Type_handler_decimal_result::Item_decimal_precision(const Item *item) const +{ + uint prec= my_decimal_length_to_precision(item->max_char_length(), + item->decimals, + item->unsigned_flag); + return MY_MIN(prec, DECIMAL_MAX_PRECISION); +} + +uint Type_handler_int_result::Item_decimal_precision(const Item *item) const +{ + uint prec= my_decimal_length_to_precision(item->max_char_length(), + item->decimals, + item->unsigned_flag); + return MY_MIN(prec, DECIMAL_MAX_PRECISION); +} + +uint Type_handler_time_common::Item_decimal_precision(const Item *item) const +{ + return 7 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); +} + +uint Type_handler_date_common::Item_decimal_precision(const Item *item) const +{ + return 8; +} + +uint Type_handler_datetime_common::Item_decimal_precision(const Item *item) const +{ + return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); +} + +uint Type_handler_timestamp_common::Item_decimal_precision(const Item *item) const +{ + return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); +} + +/***************************************************************************/ + bool Type_handler_real_result:: subquery_type_allows_materialization(const Item *inner, const Item *outer) const diff --git a/sql/sql_type.h b/sql/sql_type.h index c741e2117ec..8abc8e61510 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -639,6 +639,7 @@ public: virtual uint Item_time_precision(Item *item) const; virtual uint Item_datetime_precision(Item *item) const; virtual uint Item_decimal_scale(const Item *item) const; + virtual uint Item_decimal_precision(const Item *item) const= 0; /* Returns how many digits a divisor adds into a division result. See Item::divisor_precision_increment() in item.h for more comments. @@ -935,6 +936,11 @@ public: DBUG_ASSERT(0); return 0; } + uint Item_decimal_precision(const Item *item) const + { + DBUG_ASSERT(0); + return DECIMAL_MAX_PRECISION; + } bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -1156,6 +1162,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; @@ -1217,6 +1224,7 @@ public: const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; uint32 max_display_length(const Item *item) const; + uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -1278,6 +1286,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; @@ -1408,6 +1417,7 @@ public: { return Item_temporal_precision(item, false); } + uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -1703,6 +1713,7 @@ public: { return Item_decimal_scale_with_seconds(item); } + uint Item_decimal_precision(const Item *item) const; uint Item_divisor_precision_increment(const Item *item) const { return Item_divisor_precision_increment_with_seconds(item); @@ -1780,6 +1791,7 @@ public: { return MYSQL_TIMESTAMP_DATE; } + uint Item_decimal_precision(const Item *item) const; String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; @@ -1828,6 +1840,7 @@ public: { return Item_decimal_scale_with_seconds(item); } + uint Item_decimal_precision(const Item *item) const; uint Item_divisor_precision_increment(const Item *item) const { return Item_divisor_precision_increment_with_seconds(item); @@ -1889,6 +1902,7 @@ public: { return Item_decimal_scale_with_seconds(item); } + uint Item_decimal_precision(const Item *item) const; uint Item_divisor_precision_increment(const Item *item) const { return Item_divisor_precision_increment_with_seconds(item); -- cgit v1.2.1 From 0f642188ccdd309056f3a2a29be6cf3cc83dc256 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 10 May 2017 09:27:15 +0400 Subject: MDEV-12771 Remove Item_func_xxx::decimal_precision() for case and abbreviations --- sql/item_cmpfunc.cc | 22 ---------------------- sql/item_cmpfunc.h | 15 --------------- 2 files changed, 37 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 18c55d872db..717a65489f6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2218,16 +2218,6 @@ void Item_func_between::print(String *str, enum_query_type query_type) } -uint Item_func_case_abbreviation2::decimal_precision2(Item **args) const -{ - int arg0_int_part= args[0]->decimal_int_part(); - int arg1_int_part= args[1]->decimal_int_part(); - int max_int_part= MY_MAX(arg0_int_part, arg1_int_part); - int precision= max_int_part + decimals; - return MY_MIN(precision, DECIMAL_MAX_PRECISION); -} - - double Item_func_ifnull::real_op() { @@ -3201,18 +3191,6 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_ } -uint Item_func_case::decimal_precision() const -{ - int max_int_part=0; - for (uint i=0 ; i < ncases ; i+=2) - set_if_bigger(max_int_part, args[i+1]->decimal_int_part()); - - if (else_expr_num != -1) - set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part()); - return MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION); -} - - /** @todo Fix this so that it prints the whole CASE expression diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index affba859725..6d604b3a2fc 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1009,7 +1009,6 @@ protected: if (!aggregate_for_result(func_name(), items, 2, true)) fix_attributes(items, 2); } - uint decimal_precision2(Item **args) const; void cache_type_info(const Item *source, bool maybe_null_arg) { @@ -1064,10 +1063,6 @@ public: const char *func_name() const { return "ifnull"; } table_map not_null_tables() const { return 0; } - uint decimal_precision() const - { - return Item_func_case_abbreviation2::decimal_precision2(args); - } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } }; @@ -1128,10 +1123,6 @@ public: { fix_length_and_dec2_eliminate_null(args + 1); } - uint decimal_precision() const - { - return Item_func_case_abbreviation2::decimal_precision2(args + 1); - } const char *func_name() const { return "if"; } bool eval_not_null_tables(void *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref); @@ -1156,10 +1147,6 @@ public: { fix_length_and_dec2_eliminate_null(args + 1); } - uint decimal_precision() const - { - return Item_func_case_abbreviation2::decimal_precision2(args + 1); - } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } }; @@ -1219,7 +1206,6 @@ public: my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); bool walk(Item_processor processor, bool walk_subquery, void *arg); - uint decimal_precision() const { return args[2]->decimal_precision(); } const char *func_name() const { return "nullif"; } void print(String *str, enum_query_type query_type); void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, @@ -2056,7 +2042,6 @@ public: bool date_op(MYSQL_TIME *ltime, uint fuzzydate); bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); - uint decimal_precision() const; table_map not_null_tables() const { return 0; } const char *func_name() const { return "case"; } enum precedence precedence() const { return BETWEEN_PRECEDENCE; } -- cgit v1.2.1 From 191638416b3dbc206b4955639533e87cd488550c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 10 May 2017 11:02:02 +0400 Subject: MDEV-12772 Add Field::get_typelib() and Item::get_typelib() --- sql/field.h | 2 ++ sql/item.cc | 15 ++++----------- sql/item.h | 7 +++++++ sql/item_sum.h | 1 + 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sql/field.h b/sql/field.h index cdb80a5973a..1d6039d3cdf 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1289,6 +1289,7 @@ public: uint fill_cache_field(struct st_cache_field *copy); virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); } + virtual TYPELIB *get_typelib() const { return NULL; } virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual CHARSET_INFO *charset_for_protocol(void) const { return binary() ? &my_charset_bin : charset(); } @@ -3547,6 +3548,7 @@ public: /* enum and set are sorted as integers */ CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } uint decimals() const { return 0; } + TYPELIB *get_typelib() const { return typelib; } virtual uchar *pack(uchar *to, const uchar *from, uint max_length); virtual const uchar *unpack(uchar *to, const uchar *from, diff --git a/sql/item.cc b/sql/item.cc index 3ecca83ea17..20945027dbc 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9986,21 +9986,14 @@ void Item_type_holder::get_full_info(Item *item) if (Item_type_holder::real_type_handler() == &type_handler_enum || Item_type_holder::real_type_handler() == &type_handler_set) { - if (item->type() == Item::SUM_FUNC_ITEM && - (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC || - ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC)) - item = ((Item_sum*)item)->get_arg(0); + TYPELIB *item_typelib= item->get_typelib(); /* We can have enum/set type after merging only if we have one enum|set field (or MIN|MAX(enum|set field)) and number of NULL fields */ - DBUG_ASSERT((enum_set_typelib && - item->real_type_handler() == &type_handler_null) || - (!enum_set_typelib && - item->real_item()->type() == Item::FIELD_ITEM && - (item->real_type_handler() == &type_handler_enum || - item->real_type_handler() == &type_handler_set) && - ((Field_enum*)((Item_field *) item->real_item())->field)->typelib)); + DBUG_ASSERT(item->real_type_handler() == &type_handler_null || + (enum_set_typelib && !item_typelib) || + (!enum_set_typelib && item_typelib)); if (!enum_set_typelib) { enum_set_typelib= ((Field_enum*)((Item_field *) item->real_item())->field)->typelib; diff --git a/sql/item.h b/sql/item.h index c81f4833ebd..4ef23755f94 100644 --- a/sql/item.h +++ b/sql/item.h @@ -787,6 +787,7 @@ public: { return type_handler()->max_display_length(this); } + virtual TYPELIB *get_typelib() const { return NULL; } Item_cache* get_cache(THD *thd) const { return type_handler()->Item_get_cache(thd, this); @@ -2682,6 +2683,7 @@ public: return &type_handler_null; return field->type_handler(); } + TYPELIB *get_typelib() const { return field->get_typelib(); } enum_monotonicity_info get_monotonicity_info() const { return MONOTONIC_STRICT_INCREASING; @@ -4321,6 +4323,11 @@ public: { return ref ? (*ref)->real_item() : this; } + TYPELIB *get_typelib() const + { + return ref ? (*ref)->get_typelib() : NULL; + } + bool walk(Item_processor processor, bool walk_subquery, void *arg) { if (ref && *ref) diff --git a/sql/item_sum.h b/sql/item_sum.h index dee480ccf0a..c1485738b11 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1044,6 +1044,7 @@ protected: } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + TYPELIB *get_typelib() const { return args[0]->get_typelib(); } void update_field(); void min_max_update_str_field(); void min_max_update_real_field(); -- cgit v1.2.1 From 533506b4edb5873dc25ae335dbd018da37235f2b Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 10 May 2017 18:14:08 +0400 Subject: MDEV-12777 Change Lex_field_type_st::m_type from enum_field_types to Type_handler pointer --- sql/field.cc | 2 +- sql/sql_class.cc | 11 +++++ sql/sql_class.h | 1 + sql/sql_yacc.yy | 112 +++++++++++++++++++++++------------------- sql/sql_yacc_ora.yy | 139 ++++++++++++++++++++++++++++------------------------ sql/structs.h | 21 ++++---- 6 files changed, 159 insertions(+), 127 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index b0345788bf3..3bff4213f7c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9787,7 +9787,7 @@ void Column_definition::set_attributes(const Lex_field_type_st &type, DBUG_ASSERT(length == 0); DBUG_ASSERT(decimals == 0); - set_handler_by_real_type(type.field_type()); + set_handler(type.type_handler()); charset= cs; if (type.length()) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b586cd138de..5b8aa9ce2aa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1246,6 +1246,17 @@ extern "C" my_thread_id next_thread_id_noinline() } #endif + +const Type_handler *THD::type_handler_for_date() const +{ + if (!(variables.sql_mode & MODE_ORACLE)) + return &type_handler_newdate; + if (opt_mysql56_temporal_format) + return &type_handler_datetime2; + return &type_handler_datetime; +} + + /* Init common variables that has to be reset on start and on change_user */ diff --git a/sql/sql_class.h b/sql/sql_class.h index c1e80761235..58145703499 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3192,6 +3192,7 @@ public: { return !MY_TEST(variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES); } + const Type_handler *type_handler_for_date() const; inline my_time_t query_start() { query_start_used=1; return start_time; } inline ulong query_start_sec_part() { query_start_sec_part_used=1; return start_time_sec_part; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c065cd7dcf7..c401a1d8b3a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -782,6 +782,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) Create_field *create_field; Spvar_definition *spvar_definition; Row_definition_list *spvar_definition_list; + const Type_handler *type_handler; CHARSET_INFO *charset; Condition_information_item *cond_info_item; DYNCALL_CREATE_DEF *dyncol_def; @@ -836,7 +837,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) enum Item_udftype udf_type; enum Key::Keytype key_type; enum Statement_information_item::Name stmt_info_item_name; - enum enum_field_types field_type; enum enum_filetype filetype; enum enum_tx_isolation tx_isolation; enum enum_var_type var_type; @@ -1645,7 +1645,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type text_string hex_or_bin_String opt_gconcat_separator -%type int_type real_type +%type int_type real_type %type type_with_opt_collate field_type field_type_numeric @@ -6296,7 +6296,7 @@ field_type_numeric: | real_type opt_precision field_options { $$.set($1, $2); } | FLOAT_SYM float_options field_options { - $$.set(MYSQL_TYPE_FLOAT, $2); + $$.set(&type_handler_float, $2); if ($2.length() && !$2.dec()) { int err; @@ -6305,60 +6305,60 @@ field_type_numeric: my_yyabort_error((ER_WRONG_FIELD_SPEC, MYF(0), Lex->last_field->field_name.str)); if (tmp_length > PRECISION_FOR_FLOAT) - $$.set(MYSQL_TYPE_DOUBLE); + $$.set(&type_handler_double); else - $$.set(MYSQL_TYPE_FLOAT); + $$.set(&type_handler_float); } } | BIT_SYM opt_field_length_default_1 { - $$.set(MYSQL_TYPE_BIT, $2); + $$.set(&type_handler_bit, $2); } | BOOL_SYM { - $$.set(MYSQL_TYPE_TINY, "1"); + $$.set(&type_handler_tiny, "1"); } | BOOLEAN_SYM { - $$.set(MYSQL_TYPE_TINY, "1"); + $$.set(&type_handler_tiny, "1"); } | DECIMAL_SYM float_options field_options - { $$.set(MYSQL_TYPE_NEWDECIMAL, $2);} + { $$.set(&type_handler_newdecimal, $2);} | NUMERIC_SYM float_options field_options - { $$.set(MYSQL_TYPE_NEWDECIMAL, $2);} + { $$.set(&type_handler_newdecimal, $2);} | FIXED_SYM float_options field_options - { $$.set(MYSQL_TYPE_NEWDECIMAL, $2);} + { $$.set(&type_handler_newdecimal, $2);} ; field_type_string: char opt_field_length_default_1 opt_binary { - $$.set(MYSQL_TYPE_STRING, $2); + $$.set(&type_handler_string, $2); } | nchar opt_field_length_default_1 opt_bin_mod { - $$.set(MYSQL_TYPE_STRING, $2); + $$.set(&type_handler_string, $2); bincmp_collation(national_charset_info, $3); } | BINARY opt_field_length_default_1 { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_STRING, $2); + $$.set(&type_handler_string, $2); } | varchar field_length opt_binary { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | nvarchar field_length opt_bin_mod { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); bincmp_collation(national_charset_info, $3); } | VARBINARY field_length { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } ; @@ -6379,18 +6379,23 @@ field_type_temporal: buff, "YEAR(4)"); } } - $$.set(MYSQL_TYPE_YEAR, $2); + $$.set(&type_handler_year, $2); } - | DATE_SYM - { $$.set(MYSQL_TYPE_DATE); } + | DATE_SYM { $$.set(thd->type_handler_for_date()); } | TIME_SYM opt_field_length - { $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_TIME2 : MYSQL_TYPE_TIME, $2); } + { + $$.set(opt_mysql56_temporal_format ? + static_cast(&type_handler_time2) : + static_cast(&type_handler_time), + $2); + } | TIMESTAMP opt_field_length { if (thd->variables.sql_mode & MODE_MAXDB) $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME, $2); + static_cast(&type_handler_datetime2) : + static_cast(&type_handler_datetime), + $2); else { /* @@ -6399,13 +6404,19 @@ field_type_temporal: */ if (!opt_explicit_defaults_for_timestamp) Lex->last_field->flags|= NOT_NULL_FLAG; - $$.set(opt_mysql56_temporal_format ? MYSQL_TYPE_TIMESTAMP2 - : MYSQL_TYPE_TIMESTAMP, $2); + $$.set(opt_mysql56_temporal_format ? + static_cast(&type_handler_timestamp2): + static_cast(&type_handler_timestamp), + $2); } } | DATETIME opt_field_length - { $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME, $2); } + { + $$.set(opt_mysql56_temporal_format ? + static_cast(&type_handler_datetime2) : + static_cast(&type_handler_datetime), + $2); + } ; @@ -6413,19 +6424,19 @@ field_type_lob: TINYBLOB { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_TINY_BLOB); + $$.set(&type_handler_tiny_blob); } | BLOB_SYM opt_field_length { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_BLOB, $2); + $$.set(&type_handler_blob, $2); } | spatial_type float_options srid_option { #ifdef HAVE_SPATIAL Lex->charset=&my_charset_bin; Lex->last_field->geom_type= $1; - $$.set(MYSQL_TYPE_GEOMETRY, $2); + $$.set(&type_handler_geometry, $2); #else my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, sym_group_geom.needed_define)); @@ -6434,38 +6445,38 @@ field_type_lob: | MEDIUMBLOB { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_MEDIUM_BLOB); + $$.set(&type_handler_medium_blob); } | LONGBLOB { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_LONG_BLOB); + $$.set(&type_handler_long_blob); } | LONG_SYM VARBINARY { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_MEDIUM_BLOB); + $$.set(&type_handler_medium_blob); } | LONG_SYM varchar opt_binary - { $$.set(MYSQL_TYPE_MEDIUM_BLOB); } + { $$.set(&type_handler_medium_blob); } | TINYTEXT opt_binary - { $$.set(MYSQL_TYPE_TINY_BLOB); } + { $$.set(&type_handler_tiny_blob); } | TEXT_SYM opt_field_length opt_binary - { $$.set(MYSQL_TYPE_BLOB, $2); } + { $$.set(&type_handler_blob, $2); } | MEDIUMTEXT opt_binary - { $$.set(MYSQL_TYPE_MEDIUM_BLOB); } + { $$.set(&type_handler_medium_blob); } | LONGTEXT opt_binary - { $$.set(MYSQL_TYPE_LONG_BLOB); } + { $$.set(&type_handler_long_blob); } | LONG_SYM opt_binary - { $$.set(MYSQL_TYPE_MEDIUM_BLOB); } + { $$.set(&type_handler_medium_blob); } ; field_type_misc: ENUM '(' string_list ')' opt_binary - { $$.set(MYSQL_TYPE_ENUM); } + { $$.set(&type_handler_enum); } | SET '(' string_list ')' opt_binary - { $$.set(MYSQL_TYPE_SET); } + { $$.set(&type_handler_set); } ; spatial_type: @@ -6502,23 +6513,22 @@ nvarchar: ; int_type: - INT_SYM { $$=MYSQL_TYPE_LONG; } - | TINYINT { $$=MYSQL_TYPE_TINY; } - | SMALLINT { $$=MYSQL_TYPE_SHORT; } - | MEDIUMINT { $$=MYSQL_TYPE_INT24; } - | BIGINT { $$=MYSQL_TYPE_LONGLONG; } + INT_SYM { $$= &type_handler_long; } + | TINYINT { $$= &type_handler_tiny; } + | SMALLINT { $$= &type_handler_short; } + | MEDIUMINT { $$= &type_handler_int24; } + | BIGINT { $$= &type_handler_longlong; } ; real_type: REAL { $$= thd->variables.sql_mode & MODE_REAL_AS_FLOAT ? - MYSQL_TYPE_FLOAT : MYSQL_TYPE_DOUBLE; + static_cast(&type_handler_float) : + static_cast(&type_handler_double); } - | DOUBLE_SYM - { $$=MYSQL_TYPE_DOUBLE; } - | DOUBLE_SYM PRECISION - { $$=MYSQL_TYPE_DOUBLE; } + | DOUBLE_SYM { $$= &type_handler_double; } + | DOUBLE_SYM PRECISION { $$= &type_handler_double; } ; srid_option: diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 61577b53006..e4cdd81ce80 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -191,6 +191,7 @@ void ORAerror(THD *thd, const char *s) Create_field *create_field; Spvar_definition *spvar_definition; Row_definition_list *spvar_definition_list; + const Type_handler *type_handler; CHARSET_INFO *charset; Condition_information_item *cond_info_item; DYNCALL_CREATE_DEF *dyncol_def; @@ -245,7 +246,6 @@ void ORAerror(THD *thd, const char *s) enum Item_udftype udf_type; enum Key::Keytype key_type; enum Statement_information_item::Name stmt_info_item_name; - enum enum_field_types field_type; enum enum_filetype filetype; enum enum_tx_isolation tx_isolation; enum enum_var_type var_type; @@ -1059,7 +1059,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type text_string hex_or_bin_String opt_gconcat_separator -%type int_type real_type +%type int_type real_type %type type_with_opt_collate field_type sp_param_type_with_opt_collate @@ -6178,7 +6178,7 @@ field_type_numeric: | real_type opt_precision field_options { $$.set($1, $2); } | FLOAT_SYM float_options field_options { - $$.set(MYSQL_TYPE_FLOAT, $2); + $$.set(&type_handler_float, $2); if ($2.length() && !$2.dec()) { int err; @@ -6187,76 +6187,76 @@ field_type_numeric: my_yyabort_error((ER_WRONG_FIELD_SPEC, MYF(0), Lex->last_field->field_name.str)); if (tmp_length > PRECISION_FOR_FLOAT) - $$.set(MYSQL_TYPE_DOUBLE); + $$.set(&type_handler_double); else - $$.set(MYSQL_TYPE_FLOAT); + $$.set(&type_handler_float); } } | BIT_SYM opt_field_length_default_1 { - $$.set(MYSQL_TYPE_BIT, $2); + $$.set(&type_handler_bit, $2); } | BOOL_SYM { - $$.set(MYSQL_TYPE_TINY, "1"); + $$.set(&type_handler_tiny, "1"); } | BOOLEAN_SYM { - $$.set(MYSQL_TYPE_TINY, "1"); + $$.set(&type_handler_tiny, "1"); } | DECIMAL_SYM float_options field_options - { $$.set(MYSQL_TYPE_NEWDECIMAL, $2);} + { $$.set(&type_handler_newdecimal, $2);} | NUMBER_SYM float_options field_options { if ($2.length() != 0) - $$.set(MYSQL_TYPE_NEWDECIMAL, $2); + $$.set(&type_handler_newdecimal, $2); else - $$.set(MYSQL_TYPE_DOUBLE); + $$.set(&type_handler_double); } | NUMERIC_SYM float_options field_options - { $$.set(MYSQL_TYPE_NEWDECIMAL, $2);} + { $$.set(&type_handler_newdecimal, $2);} | FIXED_SYM float_options field_options - { $$.set(MYSQL_TYPE_NEWDECIMAL, $2);} + { $$.set(&type_handler_newdecimal, $2);} ; field_type_string: char opt_field_length_default_1 opt_binary { - $$.set(MYSQL_TYPE_STRING, $2); + $$.set(&type_handler_string, $2); } | nchar opt_field_length_default_1 opt_bin_mod { - $$.set(MYSQL_TYPE_STRING, $2); + $$.set(&type_handler_string, $2); bincmp_collation(national_charset_info, $3); } | BINARY opt_field_length_default_1 { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_STRING, $2); + $$.set(&type_handler_string, $2); } | varchar field_length opt_binary { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | VARCHAR2 field_length opt_binary { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | nvarchar field_length opt_bin_mod { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); bincmp_collation(national_charset_info, $3); } | VARBINARY field_length { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | RAW field_length { Lex->charset= &my_charset_bin; - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } ; @@ -6264,40 +6264,40 @@ field_type_string: sp_param_field_type_string: char opt_field_length_default_sp_param_char opt_binary { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | nchar opt_field_length_default_sp_param_char opt_bin_mod { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); bincmp_collation(national_charset_info, $3); } | BINARY opt_field_length_default_sp_param_char { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | varchar opt_field_length_default_sp_param_varchar opt_binary { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | VARCHAR2 opt_field_length_default_sp_param_varchar opt_binary { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | nvarchar opt_field_length_default_sp_param_varchar opt_bin_mod { - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); bincmp_collation(national_charset_info, $3); } | VARBINARY opt_field_length_default_sp_param_varchar { Lex->charset= &my_charset_bin; - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } | RAW opt_field_length_default_sp_param_varchar { Lex->charset= &my_charset_bin; - $$.set(MYSQL_TYPE_VARCHAR, $2); + $$.set(&type_handler_varchar, $2); } ; @@ -6319,19 +6319,23 @@ field_type_temporal: buff, "YEAR(4)"); } } - $$.set(MYSQL_TYPE_YEAR, $2); + $$.set(&type_handler_year, $2); } - | DATE_SYM - { $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME, 0); } + | DATE_SYM { $$.set(thd->type_handler_for_date()); } | TIME_SYM opt_field_length - { $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_TIME2 : MYSQL_TYPE_TIME, $2); } + { + $$.set(opt_mysql56_temporal_format ? + static_cast(&type_handler_time2) : + static_cast(&type_handler_time), + $2); + } | TIMESTAMP opt_field_length { if (thd->variables.sql_mode & MODE_MAXDB) $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME, $2); + static_cast(&type_handler_datetime2) : + static_cast(&type_handler_datetime), + $2); else { /* @@ -6340,13 +6344,19 @@ field_type_temporal: */ if (!opt_explicit_defaults_for_timestamp) Lex->last_field->flags|= NOT_NULL_FLAG; - $$.set(opt_mysql56_temporal_format ? MYSQL_TYPE_TIMESTAMP2 - : MYSQL_TYPE_TIMESTAMP, $2); + $$.set(opt_mysql56_temporal_format ? + static_cast(&type_handler_timestamp2): + static_cast(&type_handler_timestamp), + $2); } } | DATETIME opt_field_length - { $$.set(opt_mysql56_temporal_format ? - MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME, $2); } + { + $$.set(opt_mysql56_temporal_format ? + static_cast(&type_handler_datetime2) : + static_cast(&type_handler_datetime), + $2); + } ; @@ -6354,19 +6364,19 @@ field_type_lob: TINYBLOB { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_TINY_BLOB); + $$.set(&type_handler_tiny_blob); } | BLOB_SYM opt_field_length { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_LONG_BLOB); + $$.set(&type_handler_long_blob); } | spatial_type float_options srid_option { #ifdef HAVE_SPATIAL Lex->charset=&my_charset_bin; Lex->last_field->geom_type= $1; - $$.set(MYSQL_TYPE_GEOMETRY, $2); + $$.set(&type_handler_geometry, $2); #else my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, sym_group_geom.needed_define)); @@ -6375,40 +6385,40 @@ field_type_lob: | MEDIUMBLOB { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_MEDIUM_BLOB); + $$.set(&type_handler_medium_blob); } | LONGBLOB { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_LONG_BLOB); + $$.set(&type_handler_long_blob); } | LONG_SYM VARBINARY { Lex->charset=&my_charset_bin; - $$.set(MYSQL_TYPE_MEDIUM_BLOB); + $$.set(&type_handler_medium_blob); } | LONG_SYM varchar opt_binary - { $$.set(MYSQL_TYPE_MEDIUM_BLOB); } + { $$.set(&type_handler_medium_blob); } | TINYTEXT opt_binary - { $$.set(MYSQL_TYPE_TINY_BLOB); } + { $$.set(&type_handler_tiny_blob); } | TEXT_SYM opt_field_length opt_binary - { $$.set(MYSQL_TYPE_BLOB, $2); } + { $$.set(&type_handler_blob, $2); } | MEDIUMTEXT opt_binary - { $$.set(MYSQL_TYPE_MEDIUM_BLOB); } + { $$.set(&type_handler_medium_blob); } | LONGTEXT opt_binary - { $$.set(MYSQL_TYPE_LONG_BLOB); } + { $$.set(&type_handler_long_blob); } | CLOB opt_binary - { $$.set(MYSQL_TYPE_LONG_BLOB); } + { $$.set(&type_handler_long_blob); } | LONG_SYM opt_binary - { $$.set(MYSQL_TYPE_MEDIUM_BLOB); } + { $$.set(&type_handler_medium_blob); } ; field_type_misc: ENUM '(' string_list ')' opt_binary - { $$.set(MYSQL_TYPE_ENUM); } + { $$.set(&type_handler_enum); } | SET '(' string_list ')' opt_binary - { $$.set(MYSQL_TYPE_SET); } + { $$.set(&type_handler_set); } ; spatial_type: @@ -6445,23 +6455,22 @@ nvarchar: ; int_type: - INT_SYM { $$=MYSQL_TYPE_LONG; } - | TINYINT { $$=MYSQL_TYPE_TINY; } - | SMALLINT { $$=MYSQL_TYPE_SHORT; } - | MEDIUMINT { $$=MYSQL_TYPE_INT24; } - | BIGINT { $$=MYSQL_TYPE_LONGLONG; } + INT_SYM { $$= &type_handler_long; } + | TINYINT { $$= &type_handler_tiny; } + | SMALLINT { $$= &type_handler_short; } + | MEDIUMINT { $$= &type_handler_int24; } + | BIGINT { $$= &type_handler_longlong; } ; real_type: REAL { $$= thd->variables.sql_mode & MODE_REAL_AS_FLOAT ? - MYSQL_TYPE_FLOAT : MYSQL_TYPE_DOUBLE; + static_cast(&type_handler_float) : + static_cast(&type_handler_double); } - | DOUBLE_SYM - { $$=MYSQL_TYPE_DOUBLE; } - | DOUBLE_SYM PRECISION - { $$=MYSQL_TYPE_DOUBLE; } + | DOUBLE_SYM { $$= &type_handler_double; } + | DOUBLE_SYM PRECISION { $$= &type_handler_double; } ; srid_option: diff --git a/sql/structs.h b/sql/structs.h index 1a143602eea..80371b1b8b6 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -29,6 +29,7 @@ #include /* USERNAME_LENGTH */ struct TABLE; +class Type_handler; class Field; class Index_statistics; @@ -581,27 +582,27 @@ public: struct Lex_field_type_st: public Lex_length_and_dec_st { private: - enum_field_types m_type; - void set(enum_field_types type, const char *length, const char *dec) + const Type_handler *m_handler; + void set(const Type_handler *handler, const char *length, const char *dec) { - m_type= type; + m_handler= handler; Lex_length_and_dec_st::set(length, dec); } public: - void set(enum_field_types type, Lex_length_and_dec_st length_and_dec) + void set(const Type_handler *handler, Lex_length_and_dec_st length_and_dec) { - m_type= type; + m_handler= handler; Lex_length_and_dec_st::operator=(length_and_dec); } - void set(enum_field_types type, const char *length) + void set(const Type_handler *handler, const char *length) { - set(type, length, 0); + set(handler, length, 0); } - void set(enum_field_types type) + void set(const Type_handler *handler) { - set(type, 0, 0); + set(handler, 0, 0); } - enum_field_types field_type() const { return m_type; } + const Type_handler *type_handler() const { return m_handler; } }; -- cgit v1.2.1 From 7beb8ff27498c4b2955c4908f16ec9b9321b1bee Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 11 May 2017 07:27:11 +0400 Subject: A --ps cleanup for MDEV-12658 Make the third parameter to LPAD and RPAD optional "mtr --ps func_str" failed: pad_str was erroneously appended with a new space on every PS execution. Adding pad_str.length(0) into fix_length_and_dec() to avoid this. --- sql/item_strfunc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 64dcc6b65fa..ee5646bdfc5 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3187,6 +3187,7 @@ void Item_func_pad::fix_length_and_dec() if (agg_arg_charsets_for_string_result(collation, &args[0], 1, 1)) return; pad_str.set_charset(collation.collation); + pad_str.length(0); pad_str.append(" ", 1); } -- cgit v1.2.1 From 238eb410053a2691f397933dd190238119cb0c97 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 11 May 2017 19:39:49 +0400 Subject: MDEV-12784 Change Item_func_length::print() to display octet_length() rather than length() --- mysql-test/r/ctype_binary.result | 4 +- mysql-test/r/ctype_cp1250_ch.result | 2 +- mysql-test/r/ctype_latin1.result | 8 ++-- mysql-test/r/ctype_latin2_ch.result | 2 +- mysql-test/r/ctype_tis620.result | 4 +- mysql-test/r/ctype_uca.result | 4 +- mysql-test/r/ctype_ucs.result | 4 +- mysql-test/r/ctype_utf8.result | 4 +- mysql-test/r/default.result | 2 +- mysql-test/r/func_compress.result | 2 +- mysql-test/r/func_str.result | 6 +-- mysql-test/r/range.result | 18 ++++----- mysql-test/r/range_mrr_icp.result | 18 ++++----- mysql-test/r/type_date.result | 18 ++++----- mysql-test/r/type_datetime.result | 12 +++--- mysql-test/r/type_float.result | 8 ++-- mysql-test/r/type_newdecimal.result | 6 +-- mysql-test/r/type_time.result | 44 +++++++++++----------- mysql-test/r/type_timestamp.result | 12 +++--- mysql-test/r/view.result | 2 +- mysql-test/suite/funcs_1/r/innodb_func_view.result | 8 ++-- mysql-test/suite/funcs_1/r/memory_func_view.result | 8 ++-- mysql-test/suite/funcs_1/r/myisam_func_view.result | 8 ++-- .../gcol/r/gcol_supported_sql_funcs_innodb.result | 6 +-- .../gcol/r/gcol_supported_sql_funcs_myisam.result | 6 +-- .../suite/vcol/r/vcol_supported_sql_funcs.result | 6 +-- sql/item_create.cc | 29 +++++++++++++- sql/item_func.cc | 2 +- sql/item_func.h | 14 +++---- 29 files changed, 146 insertions(+), 121 deletions(-) diff --git a/mysql-test/r/ctype_binary.result b/mysql-test/r/ctype_binary.result index 6c16b10f1ee..79080bde8ed 100644 --- a/mysql-test/r/ctype_binary.result +++ b/mysql-test/r/ctype_binary.result @@ -3037,7 +3037,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' DROP TABLE t1; # # End of MDEV-8694 @@ -3070,7 +3070,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a), CRC32(a) FROM t1 WHERE a='a' AND CRC32(a)= id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)`,crc32(`test`.`t1`.`a`) AS `CRC32(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)`,crc32(`test`.`t1`.`a`) AS `CRC32(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' SELECT a, HEX(a) FROM t1 WHERE HEX(a)='61'; a HEX(a) a 61 diff --git a/mysql-test/r/ctype_cp1250_ch.result b/mysql-test/r/ctype_cp1250_ch.result index d4f75778ace..5799331f73e 100644 --- a/mysql-test/r/ctype_cp1250_ch.result +++ b/mysql-test/r/ctype_cp1250_ch.result @@ -220,7 +220,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' DROP TABLE t1; # # End of MDEV-8694 diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index 4b92c8100ce..dab6bfc61df 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -7817,7 +7817,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 @@ -7938,7 +7938,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 @@ -8160,7 +8160,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a), CRC32(a) FROM t1 WHERE a='a' AND CRC32(a)= id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)`,crc32(`test`.`t1`.`a`) AS `CRC32(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and crc32(`test`.`t1`.`a`) = 3904355907 +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)`,crc32(`test`.`t1`.`a`) AS `CRC32(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and crc32(`test`.`t1`.`a`) = 3904355907 SELECT a, HEX(a) FROM t1 WHERE HEX(a)='61'; a HEX(a) a 61 @@ -8188,7 +8188,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND LENGTH(a)=2; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' and length(`test`.`t1`.`a`) = 2 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' and octet_length(`test`.`t1`.`a`) = 2 DROP TABLE t1; # # MDEV-8712 Wrong result for SELECT..WHERE latin1_bin_column=_latin1'a' AND latin1_bin_column='A' diff --git a/mysql-test/r/ctype_latin2_ch.result b/mysql-test/r/ctype_latin2_ch.result index 87357a49197..a396bc77fb6 100644 --- a/mysql-test/r/ctype_latin2_ch.result +++ b/mysql-test/r/ctype_latin2_ch.result @@ -160,7 +160,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 diff --git a/mysql-test/r/ctype_tis620.result b/mysql-test/r/ctype_tis620.result index d5b4c632c31..cf66c81c647 100644 --- a/mysql-test/r/ctype_tis620.result +++ b/mysql-test/r/ctype_tis620.result @@ -3230,7 +3230,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 @@ -3446,7 +3446,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 6c6dceba9cb..725e744c44e 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -8547,7 +8547,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' DROP TABLE t1; # # End of MDEV-8694 @@ -8705,7 +8705,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' DROP TABLE t1; # # End of MDEV-8694 diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 5b2fadb8168..101cfc47cf1 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -5465,7 +5465,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 @@ -5586,7 +5586,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index f6a88d49579..87ca13cd743 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -6918,7 +6918,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` = 'a' and `test`.`t1`.`a` not like 'a ' DROP TABLE t1; # # End of MDEV-8694 @@ -7039,7 +7039,7 @@ EXPLAIN EXTENDED SELECT a, LENGTH(a) FROM t1 WHERE a NOT LIKE 'a ' AND a='a'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' +Note 1003 select `test`.`t1`.`a` AS `a`,octet_length(`test`.`t1`.`a`) AS `LENGTH(a)` from `test`.`t1` where `test`.`t1`.`a` not like 'a ' and `test`.`t1`.`a` = 'a' DROP TABLE t1; # # End of MDEV-8694 diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result index 253cb412146..c18db932afa 100644 --- a/mysql-test/r/default.result +++ b/mysql-test/r/default.result @@ -2901,7 +2901,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) DEFAULT length(`a`), + `b` int(11) DEFAULT octet_length(`a`), `c` int(11) DEFAULT char_length(`a`), `d` int(11) DEFAULT bit_length(`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result index 6857813559f..60ddd866507 100644 --- a/mysql-test/r/func_compress.result +++ b/mysql-test/r/func_compress.result @@ -22,7 +22,7 @@ explain extended select uncompressed_length(compress(@test_compress_string))=len id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select uncompressed_length(compress(@`test_compress_string`)) = length(@`test_compress_string`) AS `uncompressed_length(compress(@test_compress_string))=length(@test_compress_string)` +Note 1003 select uncompressed_length(compress(@`test_compress_string`)) = octet_length(@`test_compress_string`) AS `uncompressed_length(compress(@test_compress_string))=length(@test_compress_string)` select uncompressed_length(compress(@test_compress_string)); uncompressed_length(compress(@test_compress_string)) 117 diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 6ba3a5a8ace..28ed3cef9b4 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -966,7 +966,7 @@ explain extended select length('\n\t\r\b\0\_\%\\'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select length('\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')` +Note 1003 select octet_length('\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')` explain extended select bit_length('\n\t\r\b\0\_\%\\'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used @@ -986,7 +986,7 @@ explain extended select length('hello'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select length('hello') AS `length('hello')` +Note 1003 select octet_length('hello') AS `length('hello')` explain extended select char(ascii('h')); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used @@ -1425,7 +1425,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 const PRIMARY PRIMARY 12 const 1 100.00 Using index 1 SIMPLE t1 ref code code 13 const 3 100.00 Using where; Using index Warnings: -Note 1003 select `test`.`t1`.`code` AS `code`,'a12' AS `id` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`code` = 'a12' and length(`test`.`t1`.`code`) = 5 +Note 1003 select `test`.`t1`.`code` AS `code`,'a12' AS `id` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`code` = 'a12' and octet_length(`test`.`t1`.`code`) = 5 DROP TABLE t1,t2; select encode(NULL, NULL); encode(NULL, NULL) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 28f5cf635d0..735a0069ba0 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -2581,7 +2581,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 12, "filtered": 100, - "attached_condition": "(t1.a,t2.e) in (((3,3)),((7,7)),((8,8))) and length(t2.f) = 1" + "attached_condition": "(t1.a,t2.e) in (((3,3)),((7,7)),((8,8))) and octet_length(t2.f) = 1" } } } @@ -2666,7 +2666,7 @@ EXPLAIN "used_key_parts": ["e"], "rows": 6, "filtered": 100, - "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1 and t2.d is not null" + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and octet_length(t2.f) = 1 and t2.d is not null" }, "table": { "table_name": "t1", @@ -2716,7 +2716,7 @@ EXPLAIN "rows": 5, "filtered": 100, "index_condition": "t2.d is not null", - "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1" + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and octet_length(t2.f) = 1" }, "table": { "table_name": "t1", @@ -2776,7 +2776,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and length(t2.f) = 1" + "attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and octet_length(t2.f) = 1" } } } @@ -2830,7 +2830,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),((7,7)),((8,8))) and length(t2.f) = 1" + "attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),((7,7)),((8,8))) and octet_length(t2.f) = 1" } } } @@ -2870,7 +2870,7 @@ EXPLAIN "rows": 13, "filtered": 100, "index_condition": "t1.a is not null", - "attached_condition": "(t1.a,2) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1" + "attached_condition": "(t1.a,2) in (((2,2)),((7,7)),((8,8))) and octet_length(t1.c) = 1" }, "table": { "table_name": "t2", @@ -2882,7 +2882,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "length(t2.f) = 1" + "attached_condition": "octet_length(t2.f) = 1" } } } @@ -2958,7 +2958,7 @@ EXPLAIN "rows": 13, "filtered": 100, "index_condition": "t1.a is not null", - "attached_condition": "(t1.a,1 + 1) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1" + "attached_condition": "(t1.a,1 + 1) in (((2,2)),((7,7)),((8,8))) and octet_length(t1.c) = 1" }, "table": { "table_name": "t2", @@ -2970,7 +2970,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "length(t2.f) = 1" + "attached_condition": "octet_length(t2.f) = 1" } } } diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index f2860aaab76..afce3c66c21 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -2588,7 +2588,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 12, "filtered": 100, - "attached_condition": "(t1.a,t2.e) in (((3,3)),((7,7)),((8,8))) and length(t2.f) = 1" + "attached_condition": "(t1.a,t2.e) in (((3,3)),((7,7)),((8,8))) and octet_length(t2.f) = 1" } } } @@ -2673,7 +2673,7 @@ EXPLAIN "used_key_parts": ["e"], "rows": 6, "filtered": 100, - "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1 and t2.d is not null", + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and octet_length(t2.f) = 1 and t2.d is not null", "mrr_type": "Rowid-ordered scan" }, "table": { @@ -2724,7 +2724,7 @@ EXPLAIN "rows": 5, "filtered": 100, "index_condition": "t2.d is not null", - "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1", + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and octet_length(t2.f) = 1", "mrr_type": "Rowid-ordered scan" }, "table": { @@ -2786,7 +2786,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and length(t2.f) = 1" + "attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and octet_length(t2.f) = 1" } } } @@ -2840,7 +2840,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),((7,7)),((8,8))) and length(t2.f) = 1" + "attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),((7,7)),((8,8))) and octet_length(t2.f) = 1" } } } @@ -2880,7 +2880,7 @@ EXPLAIN "rows": 13, "filtered": 100, "index_condition": "t1.a is not null", - "attached_condition": "(t1.a,2) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1", + "attached_condition": "(t1.a,2) in (((2,2)),((7,7)),((8,8))) and octet_length(t1.c) = 1", "mrr_type": "Rowid-ordered scan" }, "table": { @@ -2893,7 +2893,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "length(t2.f) = 1" + "attached_condition": "octet_length(t2.f) = 1" } } } @@ -2969,7 +2969,7 @@ EXPLAIN "rows": 13, "filtered": 100, "index_condition": "t1.a is not null", - "attached_condition": "(t1.a,1 + 1) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1", + "attached_condition": "(t1.a,1 + 1) in (((2,2)),((7,7)),((8,8))) and octet_length(t1.c) = 1", "mrr_type": "Rowid-ordered scan" }, "table": { @@ -2982,7 +2982,7 @@ EXPLAIN "ref": ["test.t1.a"], "rows": 3, "filtered": 100, - "attached_condition": "length(t2.f) = 1" + "attached_condition": "octet_length(t2.f) = 1" } } } diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 7c7494903b6..d56fac962fe 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -615,14 +615,14 @@ SELECT * FROM t1 WHERE LENGTH(a)=11+RAND() AND a=' 2001-01-01'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2001-01-01' and (length(DATE'2001-01-01')) = 11 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2001-01-01' and (octet_length(DATE'2001-01-01')) = 11 + rand() EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=11+RAND() AND a=' garbage '; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Warning 1292 Incorrect datetime value: ' garbage ' -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'0000-00-00' and (length(DATE'0000-00-00')) = 11 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'0000-00-00' and (octet_length(DATE'0000-00-00')) = 11 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATE); INSERT INTO t1 VALUES ('2001-01-01'),('2001-01-01'); @@ -641,7 +641,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=8+RAND() AND a='20010101'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2001-01-01' and (length(DATE'2001-01-01')) = 8 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2001-01-01' and (octet_length(DATE'2001-01-01')) = 8 + rand() DROP TABLE t1; # # MDEV-8706 Wrong result for SELECT..WHERE time_column=TIMESTAMP'2015-08-30 00:00:00' AND time_column='00:00:00' @@ -670,7 +670,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2015-08-30' and (length(DATE'2015-08-30')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2015-08-30' and (octet_length(DATE'2015-08-30')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATE); INSERT INTO t1 VALUES ('2015-08-30'),('2015-08-31'); @@ -695,7 +695,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'24:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2015-08-31' and (length(DATE'2015-08-31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2015-08-31' and (octet_length(DATE'2015-08-31')) = 30 + rand() DROP TABLE t1; # In this example '00:00:00' is not recognized as TIME'00:00:00' # and is treated as DATE'0000-00-00'. @@ -721,7 +721,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'0000-00-00' and (length(DATE'0000-00-00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'0000-00-00' and (octet_length(DATE'0000-00-00')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATE); INSERT INTO t1 VALUES ('2015-08-30'),('2015-08-31'); @@ -746,7 +746,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2015-08-30 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2015-08-30 00:00:00' and (length(DATE'2015-08-30')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2015-08-30 00:00:00' and (octet_length(DATE'2015-08-30')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATE); INSERT INTO t1 VALUES ('2015-08-30'),('2015-08-31'); @@ -769,7 +769,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2015-08-30 00:00:00.1 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2015-08-30 00:00:00.1' and (length(DATE'2015-08-30')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2015-08-30 00:00:00.1' and (octet_length(DATE'2015-08-30')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATE); INSERT INTO t1 VALUES ('2015-08-30'),('2015-08-31'); @@ -794,7 +794,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='2015-08-30 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2015-08-30' and (length(DATE'2015-08-30')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = DATE'2015-08-30' and (octet_length(DATE'2015-08-30')) = 30 + rand() DROP TABLE t1; SET timestamp=DEFAULT; # diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 4dd214b61b3..95e421821c1 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -984,7 +984,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Warning 1292 Truncated incorrect datetime value: '2001-01-01 00:00:00x' -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (length(TIMESTAMP'2001-01-01 00:00:00')) <> 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) <> 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATETIME);; INSERT INTO t1 VALUES ('2001-01-01 00:00:00'),('2001-01-01 00:00:01'); @@ -1006,14 +1006,14 @@ SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=' 2001-01-01 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (length(TIMESTAMP'2001-01-01 00:00:00')) = 19 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 19 + rand() EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=' garbage '; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Warning 1292 Incorrect datetime value: ' garbage ' -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-00 00:00:00' and (length(TIMESTAMP'0000-00-00 00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-00 00:00:00' and (octet_length(TIMESTAMP'0000-00-00 00:00:00')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATETIME);; INSERT INTO t1 VALUES ('2001-01-01 00:00:00'),('2001-01-01 00:00:01'); @@ -1038,7 +1038,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.0 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a DATETIME(6));; INSERT INTO t1 VALUES ('2001-01-01 00:00:00.000000'),('2001-01-01 00:00:01.000000'); @@ -1063,7 +1063,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.0 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (length(TIMESTAMP'2001-01-01 00:00:00.000000')) = 40 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00.000000')) = 40 + rand() DROP TABLE t1; SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30'); CREATE TABLE t1 (a DATETIME);; @@ -1089,7 +1089,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIME'00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (length(TIMESTAMP'2001-01-01 00:00:00')) = 40 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 40 + rand() DROP TABLE t1; # # MDEV-8795 Equal expression propagation does not work for temporal literals diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 43aed60749e..2d138542950 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -562,7 +562,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=RAND() AND a=100e0; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 100e0 and (length(100)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 100e0 and (octet_length(100)) <> rand() DROP TABLE t1; CREATE TABLE t1 (a DOUBLE(10,1)); INSERT INTO t1 VALUES (1.1),(1.2),(1.3); @@ -582,7 +582,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=RAND() AND a=1.10e0; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10e0 and (length(1.1)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10e0 and (octet_length(1.1)) <> rand() DROP TABLE t1; CREATE TABLE t1 (a DOUBLE(10,2)); INSERT INTO t1 VALUES (1.1),(1.2),(1.3); @@ -602,7 +602,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=RAND() AND a=1.10e0; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10e0 and (length(1.10)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10e0 and (octet_length(1.10)) <> rand() DROP TABLE t1; CREATE TABLE t1 (a DOUBLE(10,3)); INSERT INTO t1 VALUES (1.1),(1.2),(1.3); @@ -622,7 +622,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=RAND() AND a=1.10e0; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10e0 and (length(1.100)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10e0 and (octet_length(1.100)) <> rand() DROP TABLE t1; # # MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010 diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index ab0e2dbc71d..ba84ff50504 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -2086,7 +2086,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=rand() AND a=1.10; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10 and (length(1.1)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10 and (octet_length(1.1)) <> rand() DROP TABLE t1; CREATE TABLE t1 (a DECIMAL(10,2)); INSERT INTO t1 VALUES (1.1),(1.2),(1.3); @@ -2106,7 +2106,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=rand() AND a=1.10; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10 and (length(1.10)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10 and (octet_length(1.10)) <> rand() DROP TABLE t1; CREATE TABLE t1 (a DECIMAL(10,3)); INSERT INTO t1 VALUES (1.1),(1.2),(1.3); @@ -2126,7 +2126,7 @@ SELECT * FROM t1 WHERE LENGTH(a)!=rand() AND a=1.10; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10 and (length(1.100)) <> rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1.10 and (octet_length(1.100)) <> rand() DROP TABLE t1; # # MDEV-8741 Equal field propagation leaves some remainders after simplifying WHERE zerofill_column=2010 AND zerofill_column>=2010 diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index 8e1b626342a..1600732cec3 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -424,7 +424,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Warning 1292 Truncated incorrect time value: '00:00:00x' -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (length(TIME'00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (octet_length(TIME'00:00:00')) = 30 + rand() DROP TABLE t1; # Trailing fractional digits in string literals CREATE TABLE t1 (a TIME); @@ -447,7 +447,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (length(TIME'00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (octet_length(TIME'00:00:00')) = 30 + rand() DROP TABLE t1; # Trailing fractional digits in temporal literals CREATE TABLE t1 (a TIME); @@ -470,7 +470,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00.000000' and (length(TIME'00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00.000000' and (octet_length(TIME'00:00:00')) = 30 + rand() DROP TABLE t1; # Trailing fractional digits in temporal literals, same precision CREATE TABLE t1 (a TIME(6)); @@ -490,7 +490,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00.000000' and (length(TIME'00:00:00.000000')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00.000000' and (octet_length(TIME'00:00:00.000000')) = 30 + rand() DROP TABLE t1; # Leading spaces in string literals CREATE TABLE t1 (a TIME); @@ -513,7 +513,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=' 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (length(TIME'00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (octet_length(TIME'00:00:00')) = 30 + rand() DROP TABLE t1; # Numeric format in string literals CREATE TABLE t1 (a TIME); @@ -536,7 +536,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (length(TIME'00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'00:00:00' and (octet_length(TIME'00:00:00')) = 30 + rand() DROP TABLE t1; # # MDEV-8766 Wrong result for SELECT..WHERE LENGTH(time_column)=8 AND time_column=TIMESTAMP'2001-01-01 10:20:31' @@ -565,7 +565,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 10:20:31'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIMESTAMP literal with a bigger scale and fractional second truncation # Ok to propagate with precision truncation @@ -589,7 +589,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 10:20:31.1 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIMESTAMP literal with a bigger scale and no fractional second truncation # Ok to propagate @@ -615,7 +615,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 10:20:31.0 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIMESTAMP literal with a smaller scale # Ok to propagate @@ -638,7 +638,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 10:20:31.1 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (length(TIME'10:20:31.123000')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (octet_length(TIME'10:20:31.123000')) = 30 + rand() DROP TABLE t1; # TIME literal with a bigger scale and fractional second truncation # Ok to propagate with precision truncation @@ -662,7 +662,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'10:20:31.123'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIME literal with a bigger scale and no fractional second truncation # Ok to propagate @@ -688,7 +688,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'10:20:31.000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.000' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.000' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIME literal with a smaller scale # Ok to propagate @@ -711,7 +711,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIME'10:20:31.123'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123' and (length(TIME'10:20:31.123000')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123' and (octet_length(TIME'10:20:31.123000')) = 30 + rand() DROP TABLE t1; # TIME-alike string literal with a bigger scale and fractional second truncation # Ok to propagate with precision truncation @@ -735,7 +735,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='10:20:31.123'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIME-alike string literal with a bigger scale and no fractional second truncation # Ok to propagate @@ -761,7 +761,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='10:20:31.000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31' and (length(TIME'10:20:31')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31' and (octet_length(TIME'10:20:31')) = 30 + rand() DROP TABLE t1; # TIME-alike string literal with a smaller scale # Ok to propagate @@ -784,7 +784,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a='10:20:31.123'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (length(TIME'10:20:31.123000')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:31.123000' and (octet_length(TIME'10:20:31.123000')) = 30 + rand() DROP TABLE t1; SET timestamp=DEFAULT; SET @@old_mode=zero_date_time_cast; @@ -821,7 +821,7 @@ SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 10:20:30' AND LENGTH(a)=30+RAND(); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:30' and (length(TIME'10:20:30')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:30' and (octet_length(TIME'10:20:30')) = 30 + rand() # Old mode, TIMESTAMP literal, zon-zero YYYYMMDD, no propagation SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-01 10:20:30'; a @@ -834,13 +834,13 @@ SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-01 10:20:30' AND LENGTH(a)=8; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-01 10:20:30' and length(`test`.`t1`.`a`) = 8 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-01 10:20:30' and octet_length(`test`.`t1`.`a`) = 8 EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-01 10:20:30' AND LENGTH(a)=30+RAND(); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-01 10:20:30' and length(`test`.`t1`.`a`) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-01 10:20:30' and octet_length(`test`.`t1`.`a`) = 30 + rand() # Old mode, TIMESTAMP-alike string literal, zero YYYYMMDD, Ok to propagate SELECT * FROM t1 WHERE a='0000-00-00 10:20:30'; a @@ -859,7 +859,7 @@ SELECT * FROM t1 WHERE a='0000-00-00 10:20:30' AND LENGTH(a)=30+RAND(); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:30' and (length(TIME'10:20:30')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:30' and (octet_length(TIME'10:20:30')) = 30 + rand() # Old mode, TIMESTAMP-alike literal, zon-zero YYYYMMDD, no propagation SELECT * FROM t1 WHERE a='0000-00-01 10:20:30'; a @@ -872,13 +872,13 @@ SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and length(`test`.`t1`.`a`) = 8 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and octet_length(`test`.`t1`.`a`) = 8 EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=30+RAND(); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and length(`test`.`t1`.`a`) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and octet_length(`test`.`t1`.`a`) = 30 + rand() DROP TABLE t1; SET @@old_mode=DEFAULT; # diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index cf4f6df4b04..b0405bc4ad7 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -840,7 +840,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Warning 1292 Truncated incorrect datetime value: '2001-01-01 00:00:00x' -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (length(TIMESTAMP'2001-01-01 00:00:00')) <> 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) <> 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP);; INSERT INTO t1 VALUES ('2001-01-01 00:00:00'),('2001-01-01 00:00:01'); @@ -862,14 +862,14 @@ SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=' 2001-01-01 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (length(TIMESTAMP'2001-01-01 00:00:00')) = 19 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 19 + rand() EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=' garbage '; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: Warning 1292 Incorrect datetime value: ' garbage ' -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-00 00:00:00' and (length(TIMESTAMP'0000-00-00 00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'0000-00-00 00:00:00' and (octet_length(TIMESTAMP'0000-00-00 00:00:00')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP);; INSERT INTO t1 VALUES ('2001-01-01 00:00:00'),('2001-01-01 00:00:01'); @@ -894,7 +894,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.0 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP(6));; INSERT INTO t1 VALUES ('2001-01-01 00:00:00.000000'),('2001-01-01 00:00:01.000000'); @@ -919,7 +919,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.0 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (length(TIMESTAMP'2001-01-01 00:00:00.000000')) = 40 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00.000000')) = 40 + rand() DROP TABLE t1; SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30'); CREATE TABLE t1 (a TIMESTAMP);; @@ -945,7 +945,7 @@ SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIME'00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (length(TIMESTAMP'2001-01-01 00:00:00')) = 40 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 40 + rand() DROP TABLE t1; # # End of 10.1 tests diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 14b92e93133..2bb12c3d380 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -4582,7 +4582,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a` from `test`.`t1` left join `test`.`t2` on(`test`.`t2`.`a` = `test`.`t1`.`a`) where `test`.`t1`.`b` = 1 or `test`.`t1`.`a` = 'a' and length(`test`.`t1`.`a`) >= `test`.`t1`.`b` +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a` from `test`.`t1` left join `test`.`t2` on(`test`.`t2`.`a` = `test`.`t1`.`a`) where `test`.`t1`.`b` = 1 or `test`.`t1`.`a` = 'a' and octet_length(`test`.`t1`.`a`) >= `test`.`t1`.`b` DROP VIEW v1; DROP TABLE t1,t2; # Bug#798625: duplicate of the previous one, but without crash diff --git a/mysql-test/suite/funcs_1/r/innodb_func_view.result b/mysql-test/suite/funcs_1/r/innodb_func_view.result index 04e689cc651..481787e4eaa 100644 --- a/mysql-test/suite/funcs_1/r/innodb_func_view.result +++ b/mysql-test/suite/funcs_1/r/innodb_func_view.result @@ -857,7 +857,7 @@ my_varbinary_1000, id FROM t1_values WHERE select_id = 155 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_varbinary_1000`) AS `LENGTH(my_varbinary_1000)`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_varbinary_1000`) AS `LENGTH(my_varbinary_1000)`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 155 OR select_id IS NULL) order by id; @@ -871,7 +871,7 @@ my_binary_30, id FROM t1_values WHERE select_id = 154 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_binary_30`) AS `LENGTH(my_binary_30)`,`t1_values`.`my_binary_30` AS `my_binary_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_binary_30`) AS `LENGTH(my_binary_30)`,`t1_values`.`my_binary_30` AS `my_binary_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 154 OR select_id IS NULL) order by id; @@ -885,7 +885,7 @@ my_varchar_1000, id FROM t1_values WHERE select_id = 153 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_varchar_1000`) AS `LENGTH(my_varchar_1000)`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_varchar_1000`) AS `LENGTH(my_varchar_1000)`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 153 OR select_id IS NULL) order by id; @@ -899,7 +899,7 @@ my_char_30, id FROM t1_values WHERE select_id = 152 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_char_30`) AS `LENGTH(my_char_30)`,`t1_values`.`my_char_30` AS `my_char_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_char_30`) AS `LENGTH(my_char_30)`,`t1_values`.`my_char_30` AS `my_char_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 152 OR select_id IS NULL) order by id; diff --git a/mysql-test/suite/funcs_1/r/memory_func_view.result b/mysql-test/suite/funcs_1/r/memory_func_view.result index 765869a312d..3a75e4abac5 100644 --- a/mysql-test/suite/funcs_1/r/memory_func_view.result +++ b/mysql-test/suite/funcs_1/r/memory_func_view.result @@ -858,7 +858,7 @@ my_varbinary_1000, id FROM t1_values WHERE select_id = 155 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_varbinary_1000`) AS `LENGTH(my_varbinary_1000)`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_varbinary_1000`) AS `LENGTH(my_varbinary_1000)`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 155 OR select_id IS NULL) order by id; @@ -872,7 +872,7 @@ my_binary_30, id FROM t1_values WHERE select_id = 154 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_binary_30`) AS `LENGTH(my_binary_30)`,`t1_values`.`my_binary_30` AS `my_binary_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_binary_30`) AS `LENGTH(my_binary_30)`,`t1_values`.`my_binary_30` AS `my_binary_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 154 OR select_id IS NULL) order by id; @@ -886,7 +886,7 @@ my_varchar_1000, id FROM t1_values WHERE select_id = 153 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_varchar_1000`) AS `LENGTH(my_varchar_1000)`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_varchar_1000`) AS `LENGTH(my_varchar_1000)`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 153 OR select_id IS NULL) order by id; @@ -900,7 +900,7 @@ my_char_30, id FROM t1_values WHERE select_id = 152 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_char_30`) AS `LENGTH(my_char_30)`,`t1_values`.`my_char_30` AS `my_char_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_char_30`) AS `LENGTH(my_char_30)`,`t1_values`.`my_char_30` AS `my_char_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 152 OR select_id IS NULL) order by id; diff --git a/mysql-test/suite/funcs_1/r/myisam_func_view.result b/mysql-test/suite/funcs_1/r/myisam_func_view.result index 765869a312d..3a75e4abac5 100644 --- a/mysql-test/suite/funcs_1/r/myisam_func_view.result +++ b/mysql-test/suite/funcs_1/r/myisam_func_view.result @@ -858,7 +858,7 @@ my_varbinary_1000, id FROM t1_values WHERE select_id = 155 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_varbinary_1000`) AS `LENGTH(my_varbinary_1000)`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_varbinary_1000`) AS `LENGTH(my_varbinary_1000)`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 155 OR select_id IS NULL) order by id; @@ -872,7 +872,7 @@ my_binary_30, id FROM t1_values WHERE select_id = 154 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_binary_30`) AS `LENGTH(my_binary_30)`,`t1_values`.`my_binary_30` AS `my_binary_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_binary_30`) AS `LENGTH(my_binary_30)`,`t1_values`.`my_binary_30` AS `my_binary_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 154 OR select_id IS NULL) order by id; @@ -886,7 +886,7 @@ my_varchar_1000, id FROM t1_values WHERE select_id = 153 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_varchar_1000`) AS `LENGTH(my_varchar_1000)`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_varchar_1000`) AS `LENGTH(my_varchar_1000)`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 153 OR select_id IS NULL) order by id; @@ -900,7 +900,7 @@ my_char_30, id FROM t1_values WHERE select_id = 152 OR select_id IS NULL order by id; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection -v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select length(`t1_values`.`my_char_30`) AS `LENGTH(my_char_30)`,`t1_values`.`my_char_30` AS `my_char_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select octet_length(`t1_values`.`my_char_30`) AS `LENGTH(my_char_30)`,`t1_values`.`my_char_30` AS `my_char_30`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci SELECT v1.* FROM v1 WHERE v1.id IN (SELECT id FROM t1_values WHERE select_id = 152 OR select_id IS NULL) order by id; diff --git a/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_innodb.result b/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_innodb.result index f8f447d493d..5e165b42be7 100644 --- a/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_innodb.result @@ -915,7 +915,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, `b` varchar(10) DEFAULT NULL, - `c` varchar(20) GENERATED ALWAYS AS (insert(`a`,length(`a`),length(`b`),`b`)) VIRTUAL + `c` varchar(20) GENERATED ALWAYS AS (insert(`a`,octet_length(`a`),octet_length(`b`),`b`)) VIRTUAL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 insert into t1 values ('start,','end',default); select * from t1; @@ -978,7 +978,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) GENERATED ALWAYS AS (length(`a`)) VIRTUAL + `b` int(11) GENERATED ALWAYS AS (octet_length(`a`)) VIRTUAL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 insert into t1 values ('text',default); select * from t1; @@ -1142,7 +1142,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) GENERATED ALWAYS AS (length(`a`)) VIRTUAL + `b` int(11) GENERATED ALWAYS AS (octet_length(`a`)) VIRTUAL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 insert into t1 values ('text',default); select * from t1; diff --git a/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_myisam.result b/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_myisam.result index 9db5f0c7c38..7a18bf2d8fb 100644 --- a/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_supported_sql_funcs_myisam.result @@ -915,7 +915,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, `b` varchar(10) DEFAULT NULL, - `c` varchar(20) GENERATED ALWAYS AS (insert(`a`,length(`a`),length(`b`),`b`)) VIRTUAL + `c` varchar(20) GENERATED ALWAYS AS (insert(`a`,octet_length(`a`),octet_length(`b`),`b`)) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert into t1 values ('start,','end',default); select * from t1; @@ -978,7 +978,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) GENERATED ALWAYS AS (length(`a`)) VIRTUAL + `b` int(11) GENERATED ALWAYS AS (octet_length(`a`)) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert into t1 values ('text',default); select * from t1; @@ -1142,7 +1142,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) GENERATED ALWAYS AS (length(`a`)) VIRTUAL + `b` int(11) GENERATED ALWAYS AS (octet_length(`a`)) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert into t1 values ('text',default); select * from t1; diff --git a/mysql-test/suite/vcol/r/vcol_supported_sql_funcs.result b/mysql-test/suite/vcol/r/vcol_supported_sql_funcs.result index 9413dbdace7..dd767071dc9 100644 --- a/mysql-test/suite/vcol/r/vcol_supported_sql_funcs.result +++ b/mysql-test/suite/vcol/r/vcol_supported_sql_funcs.result @@ -915,7 +915,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, `b` varchar(10) DEFAULT NULL, - `c` varchar(20) GENERATED ALWAYS AS (insert(`a`,length(`a`),length(`b`),`b`)) VIRTUAL + `c` varchar(20) GENERATED ALWAYS AS (insert(`a`,octet_length(`a`),octet_length(`b`),`b`)) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert into t1 values ('start,','end',default); select * from t1; @@ -978,7 +978,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) GENERATED ALWAYS AS (length(`a`)) VIRTUAL + `b` int(11) GENERATED ALWAYS AS (octet_length(`a`)) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert into t1 values ('text',default); select * from t1; @@ -1142,7 +1142,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(10) DEFAULT NULL, - `b` int(11) GENERATED ALWAYS AS (length(`a`)) VIRTUAL + `b` int(11) GENERATED ALWAYS AS (octet_length(`a`)) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert into t1 values ('text',default); select * from t1; diff --git a/sql/item_create.cc b/sql/item_create.cc index 75c2189e86c..60b39035d1b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2166,6 +2166,18 @@ protected: virtual ~Create_func_length() {} }; +class Create_func_octet_length : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_octet_length s_singleton; + +protected: + Create_func_octet_length() {} + virtual ~Create_func_octet_length() {} +}; + #ifndef DBUG_OFF class Create_func_like_range_min : public Create_func_arg2 @@ -5672,7 +5684,20 @@ Create_func_length Create_func_length::s_singleton; Item* Create_func_length::create_1_arg(THD *thd, Item *arg1) { - return new (thd->mem_root) Item_func_length(thd, arg1); +#if 0 // Not yet + if (thd->variables.sql_mode & MODE_ORACLE) + return new (thd->mem_root) Item_func_char_length(thd, arg1); + else +#endif + return new (thd->mem_root) Item_func_octet_length(thd, arg1); +} + +Create_func_octet_length Create_func_octet_length::s_singleton; + +Item* +Create_func_octet_length::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_octet_length(thd, arg1); } @@ -7005,7 +7030,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)}, { { C_STRING_WITH_LEN("NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)}, { { C_STRING_WITH_LEN("OCT") }, BUILDER(Create_func_oct)}, - { { C_STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_length)}, + { { C_STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_octet_length)}, { { C_STRING_WITH_LEN("ORD") }, BUILDER(Create_func_ord)}, { { C_STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)}, { { C_STRING_WITH_LEN("PERIOD_ADD") }, BUILDER(Create_func_period_add)}, diff --git a/sql/item_func.cc b/sql/item_func.cc index c3048a04d61..4bfb463d825 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2770,7 +2770,7 @@ my_decimal *Item_func_min_max::val_decimal_native(my_decimal *dec) } -longlong Item_func_length::val_int() +longlong Item_func_octet_length::val_int() { DBUG_ASSERT(fixed == 1); String *res=args[0]->val_str(&value); diff --git a/sql/item_func.h b/sql/item_func.h index 18612dbe79f..3ff3047b335 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1548,24 +1548,24 @@ public: }; -class Item_func_length :public Item_int_func +class Item_func_octet_length :public Item_int_func { String value; public: - Item_func_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_octet_length(THD *thd, Item *a): Item_int_func(thd, a) {} longlong val_int(); - const char *func_name() const { return "length"; } + const char *func_name() const { return "octet_length"; } void fix_length_and_dec() { max_length=10; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy(thd, mem_root, this); } + { return get_item_copy(thd, mem_root, this); } }; -class Item_func_bit_length :public Item_func_length +class Item_func_bit_length :public Item_func_octet_length { public: - Item_func_bit_length(THD *thd, Item *a): Item_func_length(thd, a) {} + Item_func_bit_length(THD *thd, Item *a): Item_func_octet_length(thd, a) {} longlong val_int() - { DBUG_ASSERT(fixed == 1); return Item_func_length::val_int()*8; } + { DBUG_ASSERT(fixed == 1); return Item_func_octet_length::val_int()*8; } const char *func_name() const { return "bit_length"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } -- cgit v1.2.1 From 38acc29ccba3911318477baf6ddff79a9f8697a2 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 13 May 2017 16:52:53 +0300 Subject: Fixed buildbot failures with --embedded-server This push just fixes tests, nothing wrong in server --- mysql-test/suite/sql_sequence/read_only.test | 1 + mysql-test/suite/sys_vars/r/sysvars_server_embedded.result | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/sql_sequence/read_only.test b/mysql-test/suite/sql_sequence/read_only.test index d8743617ad2..04dab2bb525 100644 --- a/mysql-test/suite/sql_sequence/read_only.test +++ b/mysql-test/suite/sql_sequence/read_only.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/not_embedded.inc # # Test innodb read only diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 19315c6e733..7885cde4ad1 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2867,9 +2867,9 @@ READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES SESSION_VALUE NULL -GLOBAL_VALUE 189 +GLOBAL_VALUE 190 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE 189 +DEFAULT_VALUE 190 VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT Maximum number of statement instruments. -- cgit v1.2.1 From 7c44b8afb781c533898dfb7321dd5cbb88c32ce0 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 15 May 2017 14:58:05 +0400 Subject: MDEV-12798 Item_param does not preserve exact field type in EXECUTE IMMEDIATE 'CREATE TABLE AS SELECT ?' USING POINT(1,1) --- mysql-test/r/gis.result | 18 +++++++++ mysql-test/t/gis.test | 13 +++++++ sql/item.cc | 41 +-------------------- sql/item.h | 6 ++- sql/sql_type.cc | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_type.h | 33 +++++++++++++++++ 6 files changed, 169 insertions(+), 40 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 1a4a4bb48fd..df773a15ec2 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -4300,5 +4300,23 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP PROCEDURE p1; # +# MDEV-12798 Item_param does not preserve exact field type in EXECUTE IMMEDIATE 'CREATE TABLE AS SELECT ?' USING POINT(1,1) +# +EXECUTE IMMEDIATE 'CREATE TABLE t1 AS SELECT ?' USING POINT(1,1); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `?` point NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +PREPARE stmt FROM 'CREATE OR REPLACE TABLE t1 AS SELECT ?'; +EXECUTE stmt USING POINT(1,1); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `?` point NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 34797337b1d..ab9c792d523 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -2293,6 +2293,19 @@ CALL p1('multipolygon'); CALL p1('geometrycollection'); DROP PROCEDURE p1; +--echo # +--echo # MDEV-12798 Item_param does not preserve exact field type in EXECUTE IMMEDIATE 'CREATE TABLE AS SELECT ?' USING POINT(1,1) +--echo # +EXECUTE IMMEDIATE 'CREATE TABLE t1 AS SELECT ?' USING POINT(1,1); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +PREPARE stmt FROM 'CREATE OR REPLACE TABLE t1 AS SELECT ?'; +EXECUTE stmt USING POINT(1,1); +SHOW CREATE TABLE t1; +DROP TABLE t1; + + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item.cc b/sql/item.cc index 20945027dbc..e5ea5537acc 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3767,45 +3767,8 @@ bool Item_param::set_from_item(THD *thd, Item *item) struct st_value tmp; if (!item->save_in_value(&tmp)) { - unsigned_flag= item->unsigned_flag; - switch (item->cmp_type()) { - case REAL_RESULT: - set_double(tmp.value.m_double); - set_handler(&type_handler_double); - break; - case INT_RESULT: - set_int(tmp.value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS); - set_handler(&type_handler_longlong); - break; - case STRING_RESULT: - { - value.cs_info.set(thd, item->collation.collation); - /* - Exact value of max_length is not known unless data is converted to - charset of connection, so we have to set it later. - */ - set_handler(&type_handler_varchar); - - if (set_str(tmp.m_string.ptr(), tmp.m_string.length())) - DBUG_RETURN(1); - break; - } - case DECIMAL_RESULT: - { - set_decimal(&tmp.m_decimal, unsigned_flag); - set_handler(&type_handler_newdecimal); - break; - } - case TIME_RESULT: - { - set_time(&tmp.value.m_time, item->max_length, item->decimals); - set_handler(item->type_handler()); - break; - } - case ROW_RESULT: - DBUG_ASSERT(0); - set_null(); - } + if (item->type_handler()->Item_param_set_from_value(thd, this, item, &tmp)) + DBUG_RETURN(true); } else set_null(); diff --git a/sql/item.h b/sql/item.h index 4ef23755f94..0ff7deb479f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2943,7 +2943,8 @@ public: class Item_param :public Item_basic_value, private Settable_routine_parameter, public Rewritable_query_parameter, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type, + public Type_geometry_attributes { /* NO_VALUE is a special value meaning that the parameter has not been @@ -3075,6 +3076,9 @@ public: const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + Field::geometry_type get_geometry_type() const + { return Type_geometry_attributes::get_geometry_type(); }; + Item_param(THD *thd, const LEX_CSTRING *name_arg, uint pos_in_query_arg, uint len_in_query_arg); diff --git a/sql/sql_type.cc b/sql/sql_type.cc index f632b47680c..d17f9f5927e 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -4180,6 +4180,104 @@ bool Type_handler_time_common:: /***************************************************************************/ +bool Type_handler_row:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + DBUG_ASSERT(0); + param->set_null(); + return true; +} + + +bool Type_handler_real_result:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + param->unsigned_flag= attr->unsigned_flag; + param->set_double(val->value.m_double); + param->set_handler(&type_handler_double); + return false; +} + + +bool Type_handler_int_result:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + param->unsigned_flag= attr->unsigned_flag; + param->set_int(val->value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS); + param->set_handler(&type_handler_longlong); + return false; +} + + +bool Type_handler_decimal_result:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + param->unsigned_flag= attr->unsigned_flag; + param->set_decimal(&val->m_decimal, attr->unsigned_flag); + param->set_handler(&type_handler_newdecimal); + return false; +} + + +bool Type_handler_string_result:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + param->unsigned_flag= false; + param->value.cs_info.set(thd, attr->collation.collation); + /* + Exact value of max_length is not known unless data is converted to + charset of connection, so we have to set it later. + */ + param->set_handler(&type_handler_varchar); + return param->set_str(val->m_string.ptr(), val->m_string.length()); +} + + +bool Type_handler_temporal_result:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + param->unsigned_flag= attr->unsigned_flag; + param->set_time(&val->value.m_time, attr->max_length, attr->decimals); + param->set_handler(this); + return false; +} + + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const +{ + param->unsigned_flag= false; + param->value.cs_info.set(thd, &my_charset_bin); + param->set_handler(&type_handler_geometry); + param->set_geometry_type(attr->uint_geometry_type()); + return param->set_str(val->m_string.ptr(), val->m_string.length()); +} +#endif + +/***************************************************************************/ + bool Type_handler_null:: Item_send(Item *item, Protocol *protocol, st_value *buf) const { diff --git a/sql/sql_type.h b/sql/sql_type.h index 8abc8e61510..5c134e7ba25 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -28,6 +28,7 @@ class Field; class Item; +class Item_param; class Item_cache; class Item_func_or_sum; class Item_sum_hybrid; @@ -698,6 +699,10 @@ public: virtual uint32 max_display_length(const Item *item) const= 0; virtual bool Item_save_in_value(Item *item, st_value *value) const= 0; + virtual bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const= 0; virtual bool Item_send(Item *item, Protocol *p, st_value *buf) const= 0; virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; @@ -942,6 +947,10 @@ public: return DECIMAL_MAX_PRECISION; } bool Item_save_in_value(Item *item, st_value *value) const; + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { DBUG_ASSERT(0); @@ -1164,6 +1173,10 @@ public: SORT_FIELD_ATTR *attr) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; @@ -1226,6 +1239,10 @@ public: uint32 max_display_length(const Item *item) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_str(item, protocol, buf); @@ -1288,6 +1305,10 @@ public: SORT_FIELD_ATTR *attr) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; @@ -1343,6 +1364,10 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; uint32 max_display_length(const Item *item) const; bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, @@ -1419,6 +1444,10 @@ public: } uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_str(item, protocol, buf); @@ -2182,6 +2211,10 @@ public: { return false; // Materialization does not work with GEOMETRY columns } + bool Item_param_set_from_value(THD *thd, + Item_param *param, + const Type_all_attributes *attr, + const st_value *value) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, -- cgit v1.2.1 From 705fc43eaafccd7a41e541f3149a917850f4e2fb Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 10 May 2017 15:29:48 +0400 Subject: MDEV-12775 Reuse data type aggregation code for hybrid functions and UNION Introducing a new class Type_holder (used internally in sql_union.cc), to reuse exactly the same data type attribute aggregation Type_handler API for hybrid functions and UNION. This fixes a number of bugs in UNION: - MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression - MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT - MDEV-12594 UNION between fixed length double columns does not always preserve scale - MDEV-12595 UNION converts INT to BIGINT - MDEV-12599 UNION is not symmetric when mixing INT and CHAR Details: - sql_union.cc: Reusing attribute aggregation for UNION. Adding new methods: * st_select_lex_unit::join_union_type_handlers() * st_select_lex_unit::join_union_type_attributes() * st_select_lex_unit::join_union_item_types() Removing the old join_types()-based code. - Changing Type_handler::Item_hybrid_func_fix_attributes() to accept "name", Type_handler_hybrid_field_type, Type_all_attributes as three separate parameters instead of a single Item_hybrid_func parameter, to make it possible to pass both Item_hybrid_func and Type_holder. - Moving the former special GEOMETRY and ENUM/SET attribute aggregation code from Item_type_holder::join_types() to * Type_handler_typelib::Item_hybrid_func_fix_attributes(). * Type_handler_geometry::Item_hybrid_func_fix_attrubutes(). This makes GEOMETRY/ENUM/SET symmetric with all other data types (from the UNION point of view). Removing Item_type_holder::join_types() and Item_type_holder::get_full_info(). - Adding new methods into Type_all_attributes: * Type_all_attributes::set_geometry_type() and Item_hybrid_func::set_geometry_type(). * Adding Type_all_attributes::get_typelib(). * Adding Type_all_attributes::set_typelib(). - Adding Type_handler_typelib as a common parent for Type_handler_enum and Type_handler_set, to avoid code duplication: they have already had two common methods, and we're adding one more shared method. - Adding Type_all_attributes::set_maybe_null(), as some type handlers may want to set maybe_null (e.g. Type_handler_geometry) during data type attribute aggregation. - Changing Type_geometry_attributes() to accept Type_handler and Type_all_attributes as two separate parameters, instead of a single Item parameter, to make it possible to pass Type_holder. - Adding Item_args::add_argument(). - Moving Item_args::alloc_arguments() from "protected" to "public". - Moving Item_type_holder::Item_type_holder() from item.cc to item.h, as now it's very simple. Btw, this constructor should probably be eventually removed. It's now used only in sql_show.cc, which could be modified to use Item_return_decimal (for symmetry with Item_return_xxx created for all other data types). Or, another option: remove all Item_return_xxx and use Item_type_holder for all data types instead. - storage/tokudb/mysql-test/tokudb/r/type_float.result Recording new results (MDEV-12594). - mysql-test/r/cte_recursive.result Recording new results (MDEV-9497) - mysql-test/r/subselect*.result Recording new results (MDEV-12595) - mysql-test/r/metadata.result Recording new results (MDEV-9495) - mysql-test/r/temp_table.result Recording new results (MDEV-12594) - mysql-test/r/type_float.result Recording new results (MDEV-12594) --- mysql-test/r/cte_recursive.result | 2 +- mysql-test/r/metadata.result | 6 +- mysql-test/r/subselect.result | 2 +- mysql-test/r/subselect_no_exists_to_in.result | 2 +- mysql-test/r/subselect_no_mat.result | 2 +- mysql-test/r/subselect_no_opts.result | 2 +- mysql-test/r/subselect_no_scache.result | 2 +- mysql-test/r/subselect_no_semijoin.result | 2 +- mysql-test/r/temp_table.result | 16 +- mysql-test/r/type_float.result | 6 +- mysql-test/r/union.result | 215 +++++++++++++++++++- mysql-test/t/union.test | 127 ++++++++++++ sql/item.cc | 193 ------------------ sql/item.h | 66 +++++-- sql/item_func.cc | 4 +- sql/item_func.h | 4 + sql/sql_lex.h | 11 +- sql/sql_type.cc | 104 +++++++--- sql/sql_type.h | 91 +++++++-- sql/sql_union.cc | 217 +++++++++++++++++---- .../tokudb/mysql-test/tokudb/r/type_float.result | 6 +- 21 files changed, 755 insertions(+), 325 deletions(-) diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index f691db27239..946ba16ac5c 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -130,7 +130,7 @@ select t2.a+1 from t1,t2 where t1.a=t2.a select * from t1; show columns from v1; Field Type Null Key Default Extra -a bigint(20) YES NULL +a bigint(12) YES NULL # WITH RECURSIVE : types of t1 columns are determined by anchor parts create view v2 as with recursive diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 3ff332e03cc..cc249a7eab7 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -147,7 +147,7 @@ id data data 2 female no select t1.id from t1 union select t2.id from t2; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def id id 1 4 1 Y 32768 0 63 +def id id 246 4 1 Y 32768 0 63 id 1 2 @@ -168,12 +168,12 @@ def aaa @arg00 @arg00 8 20 1 Y 32768 0 63 1 select 1 union select 1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def 1 1 3 11 1 N 32769 0 63 +def 1 1 3 1 1 N 32769 0 63 1 1 select * from (select 1 union select 1) aaa; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def aaa 1 1 3 11 1 N 32769 0 63 +def aaa 1 1 3 1 1 N 32769 0 63 1 1 drop table t1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index b83ee20e784..95a872f1498 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1260,7 +1260,7 @@ a SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(20) NOT NULL + `a` int(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result index 87f33d1dbf4..7f07b974bb2 100644 --- a/mysql-test/r/subselect_no_exists_to_in.result +++ b/mysql-test/r/subselect_no_exists_to_in.result @@ -1264,7 +1264,7 @@ a SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(20) NOT NULL + `a` int(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 626990f2c9e..57c7a979d61 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -1267,7 +1267,7 @@ a SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(20) NOT NULL + `a` int(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 3637604646f..6e8be4a02a7 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -1263,7 +1263,7 @@ a SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(20) NOT NULL + `a` int(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index afebd27c192..1b437f6919d 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -1266,7 +1266,7 @@ a SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(20) NOT NULL + `a` int(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 0f0fc59341e..6094c7e029d 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -1263,7 +1263,7 @@ a SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(20) NOT NULL + `a` int(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (a int); diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index b833f4f9768..d1bec4a2af5 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -181,20 +181,20 @@ CREATE TABLE t2 ( c FLOAT(30,18) ); INSERT INTO t2 VALUES( 123456 ); SELECT AVG( c ) FROM t1 UNION SELECT 1; AVG( c ) -12139 -1 +12139.000000000000000000 +1.000000000000000000 SELECT 1 UNION SELECT AVG( c ) FROM t1; 1 -1 -12139 +1.000000000000000000 +12139.000000000000000000 SELECT 1 UNION SELECT * FROM t2 UNION SELECT 1; 1 -1 -123456 +1.000000000000000000 +123456.000000000000000000 SELECT c/1 FROM t1 UNION SELECT 1; c/1 -12139 -1 +12139.000000000000000000 +1.000000000000000000 DROP TABLE t1, t2; create temporary table t1 (a int); insert into t1 values (4711); diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 2d138542950..9a92ff21e9f 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -232,12 +232,12 @@ insert into t2 values ("1.23456780"); create table t3 select * from t2 union select * from t1; select * from t3; d -1.2345678 -100000000 +1.234567800 +100000000.000000000 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( - `d` double DEFAULT NULL + `d` double(18,9) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2, t3; create table t1 select 105213674794682365.00 + 0.0 x; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 9949defebf7..e0aa93d5c97 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -852,7 +852,7 @@ select * from t1; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `1` int(11) NOT NULL DEFAULT 0 + `1` int(2) NOT NULL DEFAULT 0 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 select _latin1"test" union select _latin2"testt" ; @@ -1608,7 +1608,7 @@ NULL binary(0) YES NULL CREATE TABLE t5 SELECT NULL UNION SELECT NULL; DESC t5; Field Type Null Key Default Extra -NULL binary(0) YES NULL +NULL null YES NULL CREATE TABLE t6 SELECT * FROM (SELECT * FROM (SELECT NULL)a) b UNION SELECT a FROM t1; DESC t6; @@ -2195,16 +2195,223 @@ CREATE OR REPLACE TABLE t1 AS SELECT 1 UNION SELECT 1; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `1` int(11) NOT NULL DEFAULT 0 + `1` int(1) NOT NULL DEFAULT 0 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `1` int(11) NOT NULL DEFAULT 0 + `1` int(1) NOT NULL DEFAULT 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression +# +CREATE TABLE t1 (a INT, b INT UNSIGNED); +INSERT INTO t1 VALUES (0x7FFFFFFF,0xFFFFFFFF); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(10,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t2 ORDER BY a; +a +2147483647 +4294967295 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT COALESCE(a,b), COALESCE(b,a) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `COALESCE(a,b)` decimal(10,0) DEFAULT NULL, + `COALESCE(b,a)` decimal(10,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t2; +COALESCE(a,b) COALESCE(b,a) +2147483647 4294967295 +DROP TABLE t2; +DROP TABLE t1; +# +# MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT +# +CREATE TABLE t1 AS SELECT COALESCE(10.1,CAST(10 AS UNSIGNED)) AS a; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` decimal(3,1) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 10.1 AS a UNION SELECT CAST(10 AS UNSIGNED); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` decimal(3,1) NOT NULL DEFAULT 0.0 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; # +# MDEV-12594 UNION between fixed length double columns does not always preserve scale +# +CREATE TABLE t1 (a FLOAT(20,4), b FLOAT(20,3), c FLOAT(20,4)); +INSERT INTO t1 VALUES (1111,2222,3333); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` float(20,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE OR REPLACE TABLE t2 SELECT a FROM t1 UNION SELECT c FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` float(20,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE OR REPLACE TABLE t2 SELECT b FROM t1 UNION SELECT b FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `b` float(20,3) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT c FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `c` float(20,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `c` float(20,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE OR REPLACE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` float(21,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `b` float(21,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# Corner case +CREATE TABLE t1 (a FLOAT(255,4), b FLOAT(255,3)); +INSERT INTO t1 VALUES (1111,2222); +CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `b` float(255,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# +# MDEV-12595 UNION converts INT to BIGINT +# +CREATE TABLE t1 AS SELECT +1, +-1, +COALESCE(1,1), +COALESCE(-1,-1), +COALESCE(1,-1), +COALESCE(-1,1); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(1) NOT NULL, + `-1` int(2) NOT NULL, + `COALESCE(1,1)` int(1) NOT NULL, + `COALESCE(-1,-1)` int(2) NOT NULL, + `COALESCE(1,-1)` int(2) NOT NULL, + `COALESCE(-1,1)` int(2) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT 1 AS c1,1 AS c2,-1 AS c3,-1 AS c4 UNION SELECT 1,-1,1,-1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(1) NOT NULL DEFAULT 0, + `c2` int(2) NOT NULL DEFAULT 0, + `c3` int(2) NOT NULL DEFAULT 0, + `c4` int(2) NOT NULL DEFAULT 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# MDEV-12599 UNION is not symmetric when mixing INT and CHAR +# +CREATE OR REPLACE TABLE t1 AS SELECT 1 AS c1, 'a' AS c2 UNION SELECT 'a', 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(1) NOT NULL DEFAULT '', + `c2` varchar(1) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 11112222 AS c1, 'a' AS c2 UNION SELECT 'a', 11112222; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(8) NOT NULL DEFAULT '', + `c2` varchar(8) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 111122223333 AS c1, 'a' AS c2 UNION SELECT 'a', 111122223333; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(12) NOT NULL DEFAULT '', + `c2` varchar(12) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 1111222233334444 AS c1, 'a' AS c2 UNION SELECT 'a', 1111222233334444; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(16) NOT NULL DEFAULT '', + `c2` varchar(16) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a INT(3), b VARCHAR(1)); +CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(11) DEFAULT NULL, + `b` varchar(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a BIGINT(3), b VARCHAR(1)); +CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(20) DEFAULT NULL, + `b` varchar(20) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a BIGINT(12), b VARCHAR(1)); +CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(20) DEFAULT NULL, + `b` varchar(20) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 04ab71588be..ce8b2bc9c2a 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1544,6 +1544,133 @@ CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0; SHOW CREATE TABLE t1; DROP TABLE t1; +--echo # +--echo # MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression +--echo # +CREATE TABLE t1 (a INT, b INT UNSIGNED); +INSERT INTO t1 VALUES (0x7FFFFFFF,0xFFFFFFFF); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1; +SHOW CREATE TABLE t2; +SELECT * FROM t2 ORDER BY a; +DROP TABLE t2; +CREATE TABLE t2 AS SELECT COALESCE(a,b), COALESCE(b,a) FROM t1; +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT +--echo # +CREATE TABLE t1 AS SELECT COALESCE(10.1,CAST(10 AS UNSIGNED)) AS a; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 10.1 AS a UNION SELECT CAST(10 AS UNSIGNED); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # MDEV-12594 UNION between fixed length double columns does not always preserve scale +--echo # +CREATE TABLE t1 (a FLOAT(20,4), b FLOAT(20,3), c FLOAT(20,4)); +INSERT INTO t1 VALUES (1111,2222,3333); + +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE OR REPLACE TABLE t2 SELECT a FROM t1 UNION SELECT c FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE OR REPLACE TABLE t2 SELECT b FROM t1 UNION SELECT b FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT c FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE OR REPLACE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +DROP TABLE t1; + +--echo # Corner case +CREATE TABLE t1 (a FLOAT(255,4), b FLOAT(255,3)); +INSERT INTO t1 VALUES (1111,2222); +CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + + +--echo # +--echo # MDEV-12595 UNION converts INT to BIGINT +--echo # +CREATE TABLE t1 AS SELECT + 1, + -1, + COALESCE(1,1), + COALESCE(-1,-1), + COALESCE(1,-1), + COALESCE(-1,1); +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 AS SELECT 1 AS c1,1 AS c2,-1 AS c3,-1 AS c4 UNION SELECT 1,-1,1,-1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +--echo # +--echo # MDEV-12599 UNION is not symmetric when mixing INT and CHAR +--echo # + +CREATE OR REPLACE TABLE t1 AS SELECT 1 AS c1, 'a' AS c2 UNION SELECT 'a', 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 AS SELECT 11112222 AS c1, 'a' AS c2 UNION SELECT 'a', 11112222; +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +CREATE OR REPLACE TABLE t1 AS SELECT 111122223333 AS c1, 'a' AS c2 UNION SELECT 'a', 111122223333; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 AS SELECT 1111222233334444 AS c1, 'a' AS c2 UNION SELECT 'a', 1111222233334444; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT(3), b VARCHAR(1)); +CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 (a BIGINT(3), b VARCHAR(1)); +CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 (a BIGINT(12), b VARCHAR(1)); +CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item.cc b/sql/item.cc index e5ea5537acc..a9c7604d154 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9772,199 +9772,6 @@ void Item_cache_row::set_null() }; -Item_type_holder::Item_type_holder(THD *thd, Item *item) - :Item(thd, item), - Type_handler_hybrid_field_type(item->real_type_handler()), - Type_geometry_attributes(item), - enum_set_typelib(0) -{ - DBUG_ASSERT(item->fixed); - maybe_null= item->maybe_null; - get_full_info(item); - DBUG_ASSERT(!decimals || result_type() != INT_RESULT); - prev_decimal_int_part= item->decimal_int_part(); -} - - -/** - Find field type which can carry current Item_type_holder type and - type of given Item. - - @param thd thread handler - @param item given item to join its parameters with this item ones - - @retval - TRUE error - types are incompatible - @retval - FALSE OK -*/ - -bool Item_type_holder::join_types(THD *thd, Item *item) -{ - uint max_length_orig= max_length; - uint decimals_orig= decimals; - DBUG_ENTER("Item_type_holder::join_types"); - DBUG_PRINT("info:", ("was type %s len %d, dec %d name %s", - real_type_handler()->name().ptr(), max_length, decimals, - (name.str ? name.str : ""))); - DBUG_PRINT("info:", ("in type %s len %d, dec %d", - item->real_type_handler()->name().ptr(), - item->max_length, item->decimals)); - const Type_handler *item_type_handler= item->real_type_handler(); - if (aggregate_for_result(item_type_handler)) - { - my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), - Item_type_holder::real_type_handler()->name().ptr(), - item_type_handler->name().ptr(), - "UNION"); - DBUG_RETURN(true); - } - - /* - At this point non-zero decimals in combination with integer data types - is possible in some cases: - SELECT * FROM (SELECT NULL) a UNION SELECT 1; - In the constructor Item_type_holder::Item_type_holder() the data type - handler was set to type_handler_null with decimals==NOT_FIXED_DEC. - After the above call for aggregate_for_result() for the literal 1 - which is on the right side of the UNION, the data type handler - changes to type_handler_longlong, while decimals is still NOT_FIXED_DEC. - */ - if (result_type() == INT_RESULT) - decimals= 0; - else - decimals= MY_MAX(decimals, item->decimals); - - Type_geometry_attributes::join(item); - - if (result_type() == DECIMAL_RESULT) - { - decimals= MY_MIN(MY_MAX(decimals, item->decimals), DECIMAL_MAX_SCALE); - int item_int_part= item->decimal_int_part(); - int item_prec = MY_MAX(prev_decimal_int_part, item_int_part) + decimals; - int precision= MY_MIN(item_prec, DECIMAL_MAX_PRECISION); - unsigned_flag&= item->unsigned_flag; - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - } - - switch (result_type()) - { - case STRING_RESULT: - { - const char *old_cs, *old_derivation; - uint32 old_max_chars= max_length / collation.collation->mbmaxlen; - old_cs= collation.collation->name; - old_derivation= collation.derivation_name(); - if (collation.aggregate(item->collation, MY_COLL_ALLOW_CONV)) - { - my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), - old_cs, old_derivation, - item->collation.collation->name, - item->collation.derivation_name(), - "UNION"); - DBUG_RETURN(TRUE); - } - /* - To figure out max_length, we have to take into account possible - expansion of the size of the values because of character set - conversions. - */ - if (collation.collation != &my_charset_bin) - { - max_length= MY_MAX(old_max_chars * collation.collation->mbmaxlen, - item->max_display_length() / - item->collation.collation->mbmaxlen * - collation.collation->mbmaxlen); - } - else - set_if_bigger(max_length, item->max_display_length()); - break; - } - case REAL_RESULT: - { - if (decimals != NOT_FIXED_DEC) - { - /* - For FLOAT(M,D)/DOUBLE(M,D) do not change precision - if both fields have the same M and D - */ - if (item->max_length != max_length_orig || - item->decimals != decimals_orig) - { - int delta1= max_length_orig - decimals_orig; - int delta2= item->max_length - item->decimals; - max_length= MY_MAX(delta1, delta2) + decimals; - if (Item_type_holder::real_type_handler() == &type_handler_float && - max_length > FLT_DIG + 2) - { - max_length= MAX_FLOAT_STR_LENGTH; - decimals= NOT_FIXED_DEC; - } - else if (Item_type_holder::real_type_handler() == &type_handler_double && - max_length > DBL_DIG + 2) - { - max_length= MAX_DOUBLE_STR_LENGTH; - decimals= NOT_FIXED_DEC; - } - } - } - else - max_length= (Item_type_holder::field_type() == MYSQL_TYPE_FLOAT) ? - FLT_DIG+6 : DBL_DIG+7; - break; - } - default: - max_length= MY_MAX(max_length, item->max_display_length()); - }; - maybe_null|= item->maybe_null; - get_full_info(item); - /* - Adjust data type for union, e.g.: - - convert type_handler_null to type_handler_string - - convert type_handler_olddecimal to type_handler_newdecimal - - adjust varchar/blob according to max_length - */ - set_handler(Item_type_holder:: - real_type_handler()->type_handler_for_union(this)); - - /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ - prev_decimal_int_part= decimal_int_part(); - DBUG_PRINT("info", ("become type: %s len: %u dec: %u", - real_type_handler()->name().ptr(), - max_length, (uint) decimals)); - DBUG_RETURN(FALSE); -} - - -/** - Get full information from Item about enum/set fields to be able to create - them later. - - @param item Item for information collection -*/ -void Item_type_holder::get_full_info(Item *item) -{ - if (Item_type_holder::real_type_handler() == &type_handler_enum || - Item_type_holder::real_type_handler() == &type_handler_set) - { - TYPELIB *item_typelib= item->get_typelib(); - /* - We can have enum/set type after merging only if we have one enum|set - field (or MIN|MAX(enum|set field)) and number of NULL fields - */ - DBUG_ASSERT(item->real_type_handler() == &type_handler_null || - (enum_set_typelib && !item_typelib) || - (!enum_set_typelib && item_typelib)); - if (!enum_set_typelib) - { - enum_set_typelib= ((Field_enum*)((Item_field *) item->real_item())->field)->typelib; - } - } -} - - double Item_type_holder::val_real() { DBUG_ASSERT(0); // should never be called diff --git a/sql/item.h b/sql/item.h index 0ff7deb479f..2de5214c99e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -787,7 +787,13 @@ public: { return type_handler()->max_display_length(this); } - virtual TYPELIB *get_typelib() const { return NULL; } + TYPELIB *get_typelib() const { return NULL; } + void set_maybe_null(bool maybe_null_arg) { maybe_null= maybe_null_arg; } + void set_typelib(TYPELIB *typelib) + { + // Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet. + DBUG_ASSERT(0); + } Item_cache* get_cache(THD *thd) const { return type_handler()->Item_get_cache(thd, this); @@ -1740,6 +1746,10 @@ public: { return Field::GEOM_GEOMETRY; }; uint uint_geometry_type() const { return get_geometry_type(); } + void set_geometry_type(uint type) + { + DBUG_ASSERT(0); + } String *check_well_formed_result(String *str, bool send_error= 0); bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); bool too_big_for_varchar() const @@ -1842,27 +1852,28 @@ class Type_geometry_attributes { uint m_geometry_type; static const uint m_geometry_type_unknown= Field::GEOM_GEOMETRYCOLLECTION + 1; - void copy(const Item *item) + void copy(const Type_handler *handler, const Type_all_attributes *gattr) { // Ignore implicit NULLs - m_geometry_type= item->type_handler() == &type_handler_geometry ? - item->uint_geometry_type() : + m_geometry_type= handler == &type_handler_geometry ? + gattr->uint_geometry_type() : m_geometry_type_unknown; } public: Type_geometry_attributes() :m_geometry_type(m_geometry_type_unknown) { } - Type_geometry_attributes(const Item *item) + Type_geometry_attributes(const Type_handler *handler, + const Type_all_attributes *gattr) :m_geometry_type(m_geometry_type_unknown) { - copy(item); + copy(handler, gattr); } void join(const Item *item) { // Ignore implicit NULLs if (m_geometry_type == m_geometry_type_unknown) - copy(item); + copy(item->type_handler(), item); else if (item->type_handler() == &type_handler_geometry) { m_geometry_type= @@ -1902,7 +1913,6 @@ class Item_args protected: Item **args, *tmp_arg[2]; uint arg_count; - bool alloc_arguments(THD *thd, uint count); void set_arguments(THD *thd, List &list); bool walk_args(Item_processor processor, bool walk_subquery, void *arg) { @@ -1961,6 +1971,11 @@ public: set_arguments(thd, list); } Item_args(THD *thd, const Item_args *other); + bool alloc_arguments(THD *thd, uint count); + void add_argument(Item *item) + { + args[arg_count++]= item; + } inline Item **arguments() const { return args; } inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } @@ -3079,6 +3094,9 @@ public: Field::geometry_type get_geometry_type() const { return Type_geometry_attributes::get_geometry_type(); }; + void set_geometry_type(uint type) + { Type_geometry_attributes::set_geometry_type(type); } + Item_param(THD *thd, const LEX_CSTRING *name_arg, uint pos_in_query_arg, uint len_in_query_arg); @@ -5841,12 +5859,29 @@ class Item_type_holder: public Item, { protected: TYPELIB *enum_set_typelib; - void get_full_info(Item *item); - - /* It is used to count decimal precision in join_types */ - int prev_decimal_int_part; public: - Item_type_holder(THD*, Item*); + Item_type_holder(THD *thd, Item *item) + :Item(thd, item), + Type_handler_hybrid_field_type(item->real_type_handler()), + enum_set_typelib(0) + { + DBUG_ASSERT(item->fixed); + maybe_null= item->maybe_null; + } + Item_type_holder(THD *thd, + const LEX_CSTRING *name_arg, + const Type_handler *handler, + const Type_all_attributes *attr, + bool maybe_null_arg) + :Item(thd), + Type_handler_hybrid_field_type(handler), + Type_geometry_attributes(handler, attr), + enum_set_typelib(attr->get_typelib()) + { + name= *name_arg; + Type_std_attributes::set(*attr); + maybe_null= maybe_null_arg; + } const Type_handler *type_handler() const { @@ -5864,7 +5899,6 @@ public: longlong val_int(); my_decimal *val_decimal(my_decimal *); String *val_str(String*); - bool join_types(THD *thd, Item *); Field *create_tmp_field(bool group, TABLE *table) { return Item_type_holder::real_type_handler()-> @@ -5875,6 +5909,10 @@ public: { return Type_geometry_attributes::get_geometry_type(); } + void set_geometry_type(uint type) + { + Type_geometry_attributes::set_geometry_type(type); + } Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4bfb463d825..cb5dd172634 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -546,7 +546,9 @@ my_decimal *Item_func::val_decimal(my_decimal *decimal_value) bool Item_hybrid_func::fix_attributes(Item **items, uint nitems) { bool rc= Item_hybrid_func::type_handler()-> - Item_hybrid_func_fix_attributes(current_thd, this, items, nitems); + Item_hybrid_func_fix_attributes(current_thd, + func_name(), this, this, + items, nitems); DBUG_ASSERT(!rc || current_thd->is_error()); return rc; } diff --git a/sql/item_func.h b/sql/item_func.h index 3ff3047b335..860a4fdcc7d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -398,6 +398,10 @@ public: { return Type_handler_hybrid_field_type::type_handler(); } Field::geometry_type get_geometry_type() const { return Type_geometry_attributes::get_geometry_type(); }; + void set_geometry_type(uint type) + { + Type_geometry_attributes::set_geometry_type(type); + } }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 85ce07be5a8..4ac407b260d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -640,6 +640,14 @@ protected: ulonglong found_rows_for_union; bool saved_error; + bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result, + ulong additional_options, + bool is_union_select); + bool join_union_item_types(THD *thd, List &types, uint count); + bool join_union_type_handlers(THD *thd, + class Type_holder *holders, uint count); + bool join_union_type_attributes(THD *thd, + class Type_holder *holders, uint count); public: // Ensures that at least all members used during cleanup() are initialized. st_select_lex_unit() @@ -749,9 +757,6 @@ public: /* UNION methods */ bool prepare(THD *thd, select_result *result, ulong additional_options); - bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result, - ulong additional_options, - bool is_union_select); bool optimize(); bool exec(); bool exec_recursive(); diff --git a/sql/sql_type.cc b/sql/sql_type.cc index d17f9f5927e..1b2798f9467 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -482,29 +482,18 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const /***************************************************************************/ -const Type_handler *Type_handler_enum::type_handler_for_item_field() const +const Type_handler *Type_handler_typelib::type_handler_for_item_field() const { return &type_handler_string; } -const Type_handler *Type_handler_enum::cast_to_int_type_handler() const +const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const { return &type_handler_longlong; } -const Type_handler *Type_handler_set::type_handler_for_item_field() const -{ - return &type_handler_string; -} - - -const Type_handler *Type_handler_set::cast_to_int_type_handler() const -{ - return &type_handler_longlong; -} - /***************************************************************************/ bool @@ -2080,7 +2069,10 @@ Type_handler_temporal_result::Item_get_cache(THD *thd, const Item *item) const /*************************************************************************/ bool Type_handler_int_result:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { uint unsigned_flag= items[0]->unsigned_flag; @@ -2089,7 +2081,7 @@ bool Type_handler_int_result:: if (unsigned_flag != items[i]->unsigned_flag) { // Convert a mixture of signed and unsigned int to decimal - func->set_handler(&type_handler_newdecimal); + handler->set_handler(&type_handler_newdecimal); func->aggregate_attributes_decimal(items, nitems); return false; } @@ -2100,7 +2092,10 @@ bool Type_handler_int_result:: bool Type_handler_real_result:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { func->aggregate_attributes_real(items, nitems); @@ -2109,7 +2104,10 @@ bool Type_handler_real_result:: bool Type_handler_decimal_result:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { func->aggregate_attributes_decimal(items, nitems); @@ -2118,26 +2116,59 @@ bool Type_handler_decimal_result:: bool Type_handler_string_result:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, + Item **items, uint nitems) const +{ + return func->aggregate_attributes_string(func_name, items, nitems); +} + + + +/* + We can have enum/set type after merging only if we have one enum|set + field (or MIN|MAX(enum|set field)) and number of NULL fields +*/ +bool Type_handler_typelib:: + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { - return func->aggregate_attributes_string(func->func_name(), items, nitems); + TYPELIB *typelib= NULL; + for (uint i= 0; i < nitems; i++) + { + if ((typelib= items[i]->get_typelib())) + break; + } + DBUG_ASSERT(typelib); // There must be at least one typelib + func->set_typelib(typelib); + return func->aggregate_attributes_string(func_name, items, nitems); } bool Type_handler_blob_common:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { - if (func->aggregate_attributes_string(func->func_name(), items, nitems)) + if (func->aggregate_attributes_string(func_name, items, nitems)) return true; - func->set_handler(blob_type_handler(func->max_length)); + handler->set_handler(blob_type_handler(func->max_length)); return false; } bool Type_handler_date_common:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { func->fix_attributes_date(); @@ -2146,7 +2177,10 @@ bool Type_handler_date_common:: bool Type_handler_time_common:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { func->aggregate_attributes_temporal(MIN_TIME_WIDTH, items, nitems); @@ -2155,7 +2189,10 @@ bool Type_handler_time_common:: bool Type_handler_datetime_common:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems); @@ -2164,7 +2201,10 @@ bool Type_handler_datetime_common:: bool Type_handler_timestamp_common:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems); @@ -2173,11 +2213,14 @@ bool Type_handler_timestamp_common:: #ifdef HAVE_SPATIAL bool Type_handler_geometry:: - Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item_hybrid_func_fix_attributes(THD *thd, + const char *func_name, + Type_handler_hybrid_field_type *handler, + Type_all_attributes *func, Item **items, uint nitems) const { DBUG_ASSERT(nitems > 0); - Type_geometry_attributes gattr(items[0]); + Type_geometry_attributes gattr(items[0]->type_handler(), items[0]); for (uint i= 1; i < nitems; i++) gattr.join(items[i]); func->set_geometry_type(gattr.get_geometry_type()); @@ -2185,7 +2228,7 @@ bool Type_handler_geometry:: func->unsigned_flag= false; func->decimals= 0; func->max_length= (uint32) UINT_MAX32; - func->maybe_null= true; + func->set_maybe_null(true); return false; } #endif @@ -2202,7 +2245,8 @@ bool Type_handler:: with aggregating for CASE-alike functions (e.g. COALESCE) for the majority of data type handlers. */ - return Item_hybrid_func_fix_attributes(thd, func, items, nitems); + return Item_hybrid_func_fix_attributes(thd, func->func_name(), + func, func, items, nitems); } diff --git a/sql/sql_type.h b/sql/sql_type.h index 5c134e7ba25..f41437ffe52 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -61,6 +61,7 @@ class Item_func_div; class Item_func_mod; class cmp_item; class in_vector; +class Type_handler_hybrid_field_type; class Sort_param; class Arg_comparator; struct st_value; @@ -468,6 +469,7 @@ public: :Type_std_attributes(other) { } virtual ~Type_all_attributes() {} + virtual void set_maybe_null(bool maybe_null_arg)= 0; // Returns total number of decimal digits virtual uint decimal_precision() const= 0; /* @@ -477,7 +479,9 @@ public: datatype indepented method. */ virtual uint uint_geometry_type() const= 0; - virtual TYPELIB *get_typelib() const { return NULL; } + virtual void set_geometry_type(uint type)= 0; + virtual TYPELIB *get_typelib() const= 0; + virtual void set_typelib(TYPELIB *typelib)= 0; }; @@ -774,7 +778,10 @@ public: const Item *cmp) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; - virtual bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + virtual bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const= 0; virtual bool Item_func_min_max_fix_attributes(THD *thd, @@ -973,7 +980,10 @@ public: Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const { DBUG_ASSERT(0); @@ -1181,7 +1191,10 @@ public: Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, Item **items, uint nitems) const; @@ -1251,7 +1264,10 @@ public: Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; @@ -1313,7 +1329,10 @@ public: Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; @@ -1466,7 +1485,10 @@ public: Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; @@ -1755,7 +1777,10 @@ public: } int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const; @@ -1822,7 +1847,10 @@ public: } uint Item_decimal_precision(const Item *item) const; String *print_item_value(THD *thd, Item *item, String *str) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; }; @@ -1879,7 +1907,10 @@ public: return Item_send_datetime(item, protocol, buf); } String *print_item_value(THD *thd, Item *item, String *str) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; }; @@ -1941,7 +1972,10 @@ public: return Item_send_datetime(item, protocol, buf); } String *print_item_value(THD *thd, Item *item, String *str) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; }; @@ -2123,7 +2157,10 @@ public: return false; // Materialization does not work with BLOB columns } bool is_param_long_data_type() const { return true; } - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, Item **items, uint nitems) const; }; @@ -2230,7 +2267,10 @@ public: bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; - bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *h, + Type_all_attributes *attr, Item **items, uint nitems) const; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; @@ -2250,16 +2290,28 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_geometry type_handler_geometry; #endif -class Type_handler_enum: public Type_handler_string_result +class Type_handler_typelib: public Type_handler_string_result +{ +public: + virtual ~Type_handler_typelib() { } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } + const Type_handler *type_handler_for_item_field() const; + const Type_handler *cast_to_int_type_handler() const; + bool Item_hybrid_func_fix_attributes(THD *thd, + const char *name, + Type_handler_hybrid_field_type *, + Type_all_attributes *atrr, + Item **items, uint nitems) const; +}; + + +class Type_handler_enum: public Type_handler_typelib { static const Name m_name_enum; public: virtual ~Type_handler_enum() {} const Name name() const { return m_name_enum; } - enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } - const Type_handler *type_handler_for_item_field() const; - const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2269,16 +2321,13 @@ public: }; -class Type_handler_set: public Type_handler_string_result +class Type_handler_set: public Type_handler_typelib { static const Name m_name_set; public: virtual ~Type_handler_set() {} const Name name() const { return m_name_set; } - enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } - const Type_handler *type_handler_for_item_field() const; - const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index bf25c0be74e..1c2ff2b012b 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -692,6 +692,179 @@ bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl, } +class Type_holder: public Sql_alloc, + public Item_args, + public Type_handler_hybrid_field_type, + public Type_all_attributes, + public Type_geometry_attributes +{ + TYPELIB *m_typelib; + bool m_maybe_null; +public: + Type_holder() + :m_typelib(NULL), + m_maybe_null(false) + { } + + void set_maybe_null(bool maybe_null_arg) { m_maybe_null= maybe_null_arg; } + bool get_maybe_null() const { return m_maybe_null; } + + uint decimal_precision() const + { + /* + Type_holder is not used directly to create fields, so + its virtual decimal_precision() is never called. + We should eventually extend create_result_table() to accept + an array of Type_holders directly, without having to allocate + Item_type_holder's and put them into List. + */ + DBUG_ASSERT(0); + return 0; + } + void set_geometry_type(uint type) + { + Type_geometry_attributes::set_geometry_type(type); + } + uint uint_geometry_type() const + { + return Type_geometry_attributes::get_geometry_type(); + } + void set_typelib(TYPELIB *typelib) + { + m_typelib= typelib; + } + TYPELIB *get_typelib() const + { + return m_typelib; + } + + bool aggregate_attributes(THD *thd) + { + for (uint i= 0; i < arg_count; i++) + m_maybe_null|= args[i]->maybe_null; + return + type_handler()->Item_hybrid_func_fix_attributes(thd, + "UNION", this, this, + args, arg_count); + } +}; + + +/** + Aggregate data type handlers for the "count" leftmost UNION parts. +*/ +bool st_select_lex_unit::join_union_type_handlers(THD *thd_arg, + Type_holder *holders, + uint count) +{ + DBUG_ENTER("st_select_lex_unit::join_union_type_handlers"); + SELECT_LEX *first_sl= first_select(), *sl= first_sl; + for (uint i= 0; i < count ; sl= sl->next_select(), i++) + { + Item *item; + List_iterator_fast it(sl->item_list); + for (uint pos= 0; (item= it++); pos++) + { + const Type_handler *item_type_handler= item->real_type_handler(); + if (sl == first_sl) + holders[pos].set_handler(item_type_handler); + else + { + if (first_sl->item_list.elements != sl->item_list.elements) + { + my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, + ER_THD(thd_arg, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), + MYF(0)); + DBUG_RETURN(true); + } + if (holders[pos].aggregate_for_result(item_type_handler)) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + holders[pos].type_handler()->name().ptr(), + item_type_handler->name().ptr(), + "UNION"); + DBUG_RETURN(true); + } + } + } + } + DBUG_RETURN(false); +} + + +/** + Aggregate data type attributes for the "count" leftmost UNION parts. +*/ +bool st_select_lex_unit::join_union_type_attributes(THD *thd_arg, + Type_holder *holders, + uint count) +{ + DBUG_ENTER("st_select_lex_unit::join_union_type_attributes"); + SELECT_LEX *sl, *first_sl= first_select(); + uint item_pos; + for (uint pos= 0; pos < first_sl->item_list.elements; pos++) + { + if (holders[pos].alloc_arguments(thd_arg, count)) + DBUG_RETURN(true); + } + for (item_pos= 0, sl= first_sl ; + item_pos < count; + sl= sl->next_select(), item_pos++) + { + Item *item_tmp; + List_iterator_fast itx(sl->item_list); + for (uint holder_pos= 0 ; (item_tmp= itx++); holder_pos++) + { + DBUG_ASSERT(item_tmp->fixed); + holders[holder_pos].add_argument(item_tmp); + } + } + for (uint pos= 0; pos < first_sl->item_list.elements; pos++) + { + if (holders[pos].aggregate_attributes(thd_arg)) + DBUG_RETURN(true); + } + DBUG_RETURN(false); +} + + +/** + Join data types for the leftmost "count" UNION parts + and store corresponding Item_type_holder's into "types". +*/ +bool st_select_lex_unit::join_union_item_types(THD *thd_arg, + List &types, + uint count) +{ + DBUG_ENTER("st_select_lex_unit::join_union_select_list_types"); + SELECT_LEX *first_sl= first_select(); + Type_holder *holders; + + if (!(holders= new (thd_arg->mem_root) + Type_holder[first_sl->item_list.elements]) || + join_union_type_handlers(thd_arg, holders, count) || + join_union_type_attributes(thd_arg, holders, count)) + DBUG_RETURN(true); + + types.empty(); + List_iterator_fast it(first_sl->item_list); + Item *item_tmp; + for (uint pos= 0; (item_tmp= it++); pos++) + { + /* Error's in 'new' will be detected after loop */ + types.push_back(new (thd_arg->mem_root) + Item_type_holder(thd_arg, + &item_tmp->name, + holders[pos].type_handler(), + &holders[pos]/*Type_all_attributes*/, + holders[pos].get_maybe_null())); + } + if (thd_arg->is_fatal_error) + DBUG_RETURN(true); // out of memory + DBUG_RETURN(false); +} + + bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ulong additional_options) { @@ -699,6 +872,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, SELECT_LEX *sl, *first_sl= first_select(); bool is_recursive= with_element && with_element->is_recursive; bool is_rec_result_table_created= false; + uint union_part_count= 0; select_result *tmp_result; bool is_union_select; bool have_except= FALSE, have_intersect= FALSE; @@ -811,7 +985,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, goto cont; } - for (;sl; sl= sl->next_select()) + for (;sl; sl= sl->next_select(), union_part_count++) { if (prepare_join(thd_arg, sl, tmp_result, additional_options, is_union_select)) @@ -834,43 +1008,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (is_recursive) { if (derived->with->rename_columns_of_derived_unit(thd, this)) - goto err; + goto err; if (check_duplicate_names(thd, sl->item_list, 0)) goto err; } - types.empty(); - List_iterator_fast it(sl->item_list); - Item *item_tmp; - while ((item_tmp= it++)) - { - /* Error's in 'new' will be detected after loop */ - types.push_back(new (thd_arg->mem_root) - Item_type_holder(thd_arg, item_tmp)); - } - - if (thd_arg->is_fatal_error) - goto err; // out of memory - } - else - { - if (types.elements != sl->item_list.elements) - { - my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, - ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); - goto err; - } - if (!is_rec_result_table_created) - { - List_iterator_fast it(sl->item_list); - List_iterator_fast tp(types); - Item *type, *item_tmp; - while ((type= tp++, item_tmp= it++)) - { - DBUG_ASSERT(item_tmp->fixed); - if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp)) - DBUG_RETURN(TRUE); - } - } } if (is_recursive) { @@ -883,6 +1024,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ulonglong create_options; create_options= (first_sl->options | thd_arg->variables.option_bits | TMP_TABLE_ALL_COLUMNS); + // Join data types for all non-recursive parts of a recursive UNION + if (join_union_item_types(thd, types, union_part_count + 1)) + goto err; if (union_result->create_result_table(thd, &types, MY_TEST(union_distinct), create_options, derived->alias, @@ -898,6 +1042,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } } + // In case of a non-recursive UNION, join data types for all UNION parts. + if (!is_recursive && join_union_item_types(thd, types, union_part_count)) + goto err; cont: /* diff --git a/storage/tokudb/mysql-test/tokudb/r/type_float.result b/storage/tokudb/mysql-test/tokudb/r/type_float.result index 6387cea5384..f8ce24f08c4 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_float.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_float.result @@ -233,12 +233,12 @@ insert into t2 values ("1.23456780"); create table t3 select * from t2 union select * from t1; select * from t3; d -1.2345678 -100000000 +1.234567800 +100000000.000000000 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( - `d` double DEFAULT NULL + `d` double(18,9) DEFAULT NULL ) ENGINE=ENGINE DEFAULT CHARSET=latin1 drop table t1, t2, t3; create table t1 select 105213674794682365.00 + 0.0 x; -- cgit v1.2.1 From f1b729d35270383048842f2023a5c42769d6637f Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 16 May 2017 14:29:51 +0400 Subject: MDEV-9188 Split Column_definition::check() into virtual methods in Type_handler --- sql/field.cc | 301 ++++++++++++++++++-------------------------------------- sql/field.h | 8 ++ sql/sp_head.h | 3 +- sql/sql_type.cc | 159 ++++++++++++++++++++++++++++++ sql/sql_type.h | 53 +++++++++- 5 files changed, 311 insertions(+), 213 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 3bff4213f7c..b17198b3a1e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9893,11 +9893,98 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, } +bool Column_definition::check_length(uint mysql_errno, uint limit) const +{ + if (length <= limit) + return false; + my_error(mysql_errno, MYF(0), field_name.str, static_cast(limit)); + return true; +} + + +bool Column_definition::fix_attributes_int(uint default_length) +{ + if (length) + return check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_CHARLENGTH); + length= default_length; + return false; +} + + +bool Column_definition::fix_attributes_real(uint default_length) +{ + /* change FLOAT(precision) to FLOAT or DOUBLE */ + if (!length && !decimals) + { + length= default_length; + decimals= NOT_FIXED_DEC; + } + if (length < decimals && decimals != NOT_FIXED_DEC) + { + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name.str); + return true; + } + if (decimals != NOT_FIXED_DEC && decimals >= FLOATING_POINT_DECIMALS) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast(decimals), + field_name.str, static_cast(FLOATING_POINT_DECIMALS-1)); + return true; + } + return check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_CHARLENGTH); +} + + +bool Column_definition::fix_attributes_decimal() +{ + if (decimals >= NOT_FIXED_DEC) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast(decimals), + field_name.str, static_cast(NOT_FIXED_DEC - 1)); + return true; + } + my_decimal_trim(&length, &decimals); + if (length > DECIMAL_MAX_PRECISION) + { + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name.str, + DECIMAL_MAX_PRECISION); + return true; + } + if (length < decimals) + { + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name.str); + return true; + } + length= my_decimal_precision_to_length(length, decimals, + flags & UNSIGNED_FLAG); + pack_length= my_decimal_get_binary_size(length, decimals); + return false; +} + + +bool Column_definition::fix_attributes_bit() +{ + if (!length) + length= 1; + pack_length= (length + 7) / 8; + return check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_BIT_FIELD_LENGTH); +} + + +bool Column_definition::fix_attributes_temporal_with_time(uint int_part_length) +{ + if (length > MAX_DATETIME_PRECISION) + { + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name.str, + MAX_DATETIME_PRECISION); + return true; + } + length+= int_part_length + (length ? 1 : 0); + return false; +} + + bool Column_definition::check(THD *thd) { - const uint conditional_type_modifiers= AUTO_INCREMENT_FLAG; - uint sign_len, allowed_type_modifier= 0; - ulong max_field_charlength= MAX_FIELD_CHARLENGTH; DBUG_ENTER("Column_definition::check"); /* Initialize data for a computed field */ @@ -9972,186 +10059,9 @@ bool Column_definition::check(THD *thd) else if (flags & AUTO_INCREMENT_FLAG) unireg_check= Field::NEXT_NUMBER; - sign_len= flags & UNSIGNED_FLAG ? 0 : 1; + if (type_handler()->Column_definition_fix_attributes(this)) + DBUG_RETURN(true); - switch (real_field_type()) { - case MYSQL_TYPE_TINY: - if (!length) - length= MAX_TINYINT_WIDTH+sign_len; - allowed_type_modifier= AUTO_INCREMENT_FLAG; - break; - case MYSQL_TYPE_SHORT: - if (!length) - length= MAX_SMALLINT_WIDTH+sign_len; - allowed_type_modifier= AUTO_INCREMENT_FLAG; - break; - case MYSQL_TYPE_INT24: - if (!length) - length= MAX_MEDIUMINT_WIDTH+sign_len; - allowed_type_modifier= AUTO_INCREMENT_FLAG; - break; - case MYSQL_TYPE_LONG: - if (!length) - length= MAX_INT_WIDTH+sign_len; - allowed_type_modifier= AUTO_INCREMENT_FLAG; - break; - case MYSQL_TYPE_LONGLONG: - if (!length) - length= MAX_BIGINT_WIDTH; - allowed_type_modifier= AUTO_INCREMENT_FLAG; - break; - case MYSQL_TYPE_NULL: - break; - case MYSQL_TYPE_NEWDECIMAL: - if (decimals >= NOT_FIXED_DEC) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast(decimals), - field_name.str, static_cast(NOT_FIXED_DEC - 1)); - DBUG_RETURN(TRUE); - } - my_decimal_trim(&length, &decimals); - if (length > DECIMAL_MAX_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name.str, - DECIMAL_MAX_PRECISION); - DBUG_RETURN(TRUE); - } - if (length < decimals) - { - my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name.str); - DBUG_RETURN(TRUE); - } - length= - my_decimal_precision_to_length(length, decimals, flags & UNSIGNED_FLAG); - pack_length= - my_decimal_get_binary_size(length, decimals); - break; - case MYSQL_TYPE_VARCHAR: - /* - Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table - if they don't have a default value - */ - max_field_charlength= MAX_FIELD_VARCHARLENGTH; - break; - case MYSQL_TYPE_STRING: - break; - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_GEOMETRY: - flags|= BLOB_FLAG; - break; - case MYSQL_TYPE_YEAR: - if (!length || length != 2) - length= 4; /* Default length */ - flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; - break; - case MYSQL_TYPE_FLOAT: - /* change FLOAT(precision) to FLOAT or DOUBLE */ - allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (!length && !decimals) - { - length= MAX_FLOAT_STR_LENGTH; - decimals= NOT_FIXED_DEC; - } - if (length < decimals && - decimals != NOT_FIXED_DEC) - { - my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name.str); - DBUG_RETURN(TRUE); - } - if (decimals != NOT_FIXED_DEC && decimals >= FLOATING_POINT_DECIMALS) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast(decimals), - field_name.str, static_cast(FLOATING_POINT_DECIMALS-1)); - DBUG_RETURN(TRUE); - } - break; - case MYSQL_TYPE_DOUBLE: - allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (!length && !decimals) - { - length= DBL_DIG+7; - decimals= NOT_FIXED_DEC; - } - if (length < decimals && - decimals != NOT_FIXED_DEC) - { - my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name.str); - DBUG_RETURN(TRUE); - } - if (decimals != NOT_FIXED_DEC && decimals >= FLOATING_POINT_DECIMALS) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast(decimals), - field_name.str, static_cast(FLOATING_POINT_DECIMALS-1)); - DBUG_RETURN(TRUE); - } - break; - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_TIMESTAMP2: - if (length > MAX_DATETIME_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name.str, - MAX_DATETIME_PRECISION); - DBUG_RETURN(TRUE); - } - length+= MAX_DATETIME_WIDTH + (length ? 1 : 0); - flags|= UNSIGNED_FLAG; - break; - case MYSQL_TYPE_DATE: - /* We don't support creation of MYSQL_TYPE_DATE anymore */ - set_handler(&type_handler_newdate); - /* fall trough */ - case MYSQL_TYPE_NEWDATE: - length= MAX_DATE_WIDTH; - break; - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_TIME2: - if (length > MAX_DATETIME_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name.str, - MAX_DATETIME_PRECISION); - DBUG_RETURN(TRUE); - } - length+= MIN_TIME_WIDTH + (length ? 1 : 0); - break; - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_DATETIME2: - if (length > MAX_DATETIME_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name.str, - MAX_DATETIME_PRECISION); - DBUG_RETURN(TRUE); - } - length+= MAX_DATETIME_WIDTH + (length ? 1 : 0); - break; - case MYSQL_TYPE_SET: - pack_length= get_set_pack_length(interval_list.elements); - break; - case MYSQL_TYPE_ENUM: - /* Should be safe. */ - pack_length= get_enum_pack_length(interval_list.elements); - break; - case MYSQL_TYPE_VAR_STRING: - DBUG_ASSERT(0); /* Impossible. */ - break; - case MYSQL_TYPE_BIT: - { - if (!length) - length= 1; - if (length > MAX_BIT_FIELD_LENGTH) - { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name.str, - static_cast(MAX_BIT_FIELD_LENGTH)); - DBUG_RETURN(TRUE); - } - pack_length= (length + 7) / 8; - break; - } - case MYSQL_TYPE_DECIMAL: - DBUG_ASSERT(0); /* Was obsolete */ - } /* Remember the value of length */ char_length= length; @@ -10174,32 +10084,9 @@ bool Column_definition::check(THD *thd) } } - enum_field_types sql_type= real_field_type(); - if (!(flags & BLOB_FLAG) && - ((length > max_field_charlength && - sql_type != MYSQL_TYPE_VARCHAR) || - (length == 0 && - sql_type != MYSQL_TYPE_NULL /* e.g. a ROW variable */ && - sql_type != MYSQL_TYPE_ENUM && sql_type != MYSQL_TYPE_SET && - sql_type != MYSQL_TYPE_STRING && sql_type != MYSQL_TYPE_VARCHAR && - sql_type != MYSQL_TYPE_GEOMETRY))) - { - my_error((sql_type == MYSQL_TYPE_VAR_STRING || - sql_type == MYSQL_TYPE_VARCHAR || - sql_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : - ER_TOO_BIG_DISPLAYWIDTH, - MYF(0), - field_name.str, max_field_charlength); /* purecov: inspected */ - DBUG_RETURN(TRUE); - } - else if (length > MAX_FIELD_BLOBLENGTH) - { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name.str, - MAX_FIELD_BLOBLENGTH); - DBUG_RETURN(1); - } - if ((~allowed_type_modifier) & flags & conditional_type_modifiers) + if ((flags & AUTO_INCREMENT_FLAG) && + !type_handler()->type_can_have_auto_increment_attribute()) { my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name.str); DBUG_RETURN(TRUE); diff --git a/sql/field.h b/sql/field.h index 1d6039d3cdf..093fcce6fac 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3919,6 +3919,14 @@ public: bool prepare_create_field(uint *blob_columns, ulonglong table_flags); + uint sign_length() const { return flags & UNSIGNED_FLAG ? 0 : 1; } + bool check_length(uint mysql_errno, uint max_allowed_length) const; + bool fix_attributes_real(uint default_length); + bool fix_attributes_int(uint default_length); + bool fix_attributes_decimal(); + bool fix_attributes_temporal_with_time(uint int_part_length); + bool fix_attributes_bit(); + bool check(THD *thd); bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } diff --git a/sql/sp_head.h b/sql/sp_head.h index e3c9022609b..cfc2e6861d7 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -626,7 +626,8 @@ public: */ bool fill_field_definition(THD *thd, Column_definition *field_def) { - return field_def->check(thd) || + const Type_handler *h= field_def->type_handler(); + return h->Column_definition_fix_attributes(field_def) || field_def->sp_prepare_create_field(thd, mem_root); } bool row_fill_field_definitions(THD *thd, Row_definition_list *row) diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 1b2798f9467..5e08a616d9f 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -1380,6 +1380,165 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table, ((const Field_enum*) target)->typelib, target->charset()); } +/*************************************************************************/ +bool Type_handler_null:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return false; +} + +bool Type_handler_tiny:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_int(MAX_TINYINT_WIDTH + def->sign_length()); +} + +bool Type_handler_short:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_int(MAX_SMALLINT_WIDTH + def->sign_length()); +} + +bool Type_handler_int24:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_int(MAX_MEDIUMINT_WIDTH + def->sign_length()); +} + +bool Type_handler_long:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_int(MAX_INT_WIDTH + def->sign_length()); +} + +bool Type_handler_longlong:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_int(MAX_BIGINT_WIDTH/*no sign_length() added*/); +} + +bool Type_handler_newdecimal:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_decimal(); +} + +bool Type_handler_olddecimal:: + Column_definition_fix_attributes(Column_definition *def) const +{ + DBUG_ASSERT(0); // Obsolete + return true; +} + +bool Type_handler_var_string:: + Column_definition_fix_attributes(Column_definition *def) const +{ + DBUG_ASSERT(0); // Obsolete + return true; +} + +bool Type_handler_varchar:: + Column_definition_fix_attributes(Column_definition *def) const +{ + /* + Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table + if they don't have a default value + */ + return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH); +} + +bool Type_handler_string:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->check_length(ER_TOO_BIG_FIELDLENGTH, MAX_FIELD_CHARLENGTH); +} + +bool Type_handler_blob_common:: + Column_definition_fix_attributes(Column_definition *def) const +{ + def->flags|= BLOB_FLAG; + return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH); +} + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Column_definition_fix_attributes(Column_definition *def) const +{ + def->flags|= BLOB_FLAG; + return false; +} +#endif + +bool Type_handler_year:: + Column_definition_fix_attributes(Column_definition *def) const +{ + if (!def->length || def->length != 2) + def->length= 4; // Default length + def->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + return false; +} + +bool Type_handler_float:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_real(MAX_FLOAT_STR_LENGTH); +} + + +bool Type_handler_double:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_real(DBL_DIG + 7); +} + +bool Type_handler_timestamp_common:: + Column_definition_fix_attributes(Column_definition *def) const +{ + def->flags|= UNSIGNED_FLAG; + return def->fix_attributes_temporal_with_time(MAX_DATETIME_WIDTH); +} + +bool Type_handler_date_common:: + Column_definition_fix_attributes(Column_definition *def) const +{ + // We don't support creation of MYSQL_TYPE_DATE anymore + def->set_handler(&type_handler_newdate); + def->length= MAX_DATE_WIDTH; + return false; +} + +bool Type_handler_time_common:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_temporal_with_time(MIN_TIME_WIDTH); +} + +bool Type_handler_datetime_common:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_temporal_with_time(MAX_DATETIME_WIDTH); +} + +bool Type_handler_set:: + Column_definition_fix_attributes(Column_definition *def) const +{ + def->pack_length= get_set_pack_length(def->interval_list.elements); + return false; +} + +bool Type_handler_enum:: + Column_definition_fix_attributes(Column_definition *def) const +{ + def->pack_length= get_enum_pack_length(def->interval_list.elements); + return false; +} + +bool Type_handler_bit:: + Column_definition_fix_attributes(Column_definition *def) const +{ + return def->fix_attributes_bit(); +} + /*************************************************************************/ Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name, const Record_addr &addr, diff --git a/sql/sql_type.h b/sql/sql_type.h index f41437ffe52..7acab7078e1 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -27,6 +27,7 @@ #include "my_time.h" class Field; +class Column_definition; class Item; class Item_param; class Item_cache; @@ -603,6 +604,10 @@ public: { return false; } + virtual bool type_can_have_auto_increment_attribute() const + { + return false; + } /** Prepared statement long data: Check whether this parameter data type is compatible with long data. @@ -686,6 +691,7 @@ public: virtual Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const= 0; + virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0; virtual Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -924,6 +930,11 @@ public: DBUG_ASSERT(0); return NULL; } + bool Column_definition_fix_attributes(Column_definition *c) const + { + DBUG_ASSERT(0); + return true; + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1369,6 +1380,13 @@ public: }; +class Type_handler_general_purpose_int: public Type_handler_int_result +{ +public: + bool type_can_have_auto_increment_attribute() const { return true; } +}; + + class Type_handler_temporal_result: public Type_handler { protected: @@ -1552,7 +1570,7 @@ public: */ -class Type_handler_tiny: public Type_handler_int_result +class Type_handler_tiny: public Type_handler_general_purpose_int { static const Name m_name_tiny; public: @@ -1566,6 +1584,7 @@ public: } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1573,7 +1592,7 @@ public: }; -class Type_handler_short: public Type_handler_int_result +class Type_handler_short: public Type_handler_general_purpose_int { static const Name m_name_short; public: @@ -1587,6 +1606,7 @@ public: uint32 max_display_length(const Item *item) const { return 6; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1594,7 +1614,7 @@ public: }; -class Type_handler_long: public Type_handler_int_result +class Type_handler_long: public Type_handler_general_purpose_int { static const Name m_name_int; public: @@ -1611,6 +1631,7 @@ public: } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1618,7 +1639,7 @@ public: }; -class Type_handler_longlong: public Type_handler_int_result +class Type_handler_longlong: public Type_handler_general_purpose_int { static const Name m_name_longlong; public: @@ -1632,6 +1653,7 @@ public: } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1639,7 +1661,7 @@ public: }; -class Type_handler_int24: public Type_handler_int_result +class Type_handler_int24: public Type_handler_general_purpose_int { static const Name m_name_mediumint; public: @@ -1653,6 +1675,7 @@ public: uint32 max_display_length(const Item *item) const { return 8; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1674,6 +1697,7 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1699,6 +1723,7 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1713,6 +1738,7 @@ public: virtual ~Type_handler_float() {} const Name name() const { return m_name_float; } enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; } + bool type_can_have_auto_increment_attribute() const { return true; } uint32 max_display_length(const Item *item) const { return 25; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -1721,6 +1747,7 @@ public: Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1735,6 +1762,7 @@ public: virtual ~Type_handler_double() {} const Name name() const { return m_name_double; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + bool type_can_have_auto_increment_attribute() const { return true; } uint32 max_display_length(const Item *item) const { return 53; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -1742,6 +1770,7 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1770,6 +1799,7 @@ public: return Item_divisor_precision_increment_with_seconds(item); } const Type_handler *type_handler_for_comparison() const; + bool Column_definition_fix_attributes(Column_definition *c) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -1845,6 +1875,7 @@ public: { return MYSQL_TIMESTAMP_DATE; } + bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_precision(const Item *item) const; String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, @@ -1893,6 +1924,7 @@ public: { return MYSQL_TIMESTAMP_DATETIME; } + bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_scale(const Item *item) const { return Item_decimal_scale_with_seconds(item); @@ -1958,6 +1990,7 @@ public: { return true; } + bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_scale(const Item *item) const { return Item_decimal_scale_with_seconds(item); @@ -2018,6 +2051,7 @@ public: const Type_handler *type_handler_for_union(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2034,6 +2068,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2056,6 +2091,7 @@ public: bool Item_send(Item *item, Protocol *protocol, st_value *buf) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2087,6 +2123,7 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2107,6 +2144,7 @@ public: { return varstring_type_handler(item); } + bool Column_definition_fix_attributes(Column_definition *c) const; const Type_handler *type_handler_for_union(const Item *item) const { return varstring_type_handler(item); @@ -2132,6 +2170,7 @@ public: bool is_param_long_data_type() const { return true; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2157,6 +2196,7 @@ public: return false; // Materialization does not work with BLOB columns } bool is_param_long_data_type() const { return true; } + bool Column_definition_fix_attributes(Column_definition *c) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -2254,6 +2294,7 @@ public: const st_value *value) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2314,6 +2355,7 @@ public: virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2330,6 +2372,7 @@ public: virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_fix_attributes(Column_definition *c) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, -- cgit v1.2.1 From fba7fbbc5c7bb1d05488108a29b854ee8ef0066a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 17 May 2017 12:21:39 +0400 Subject: MDEV-9397 Split field.cc:calc_pack_length() into virtual methods in Type_handler - Adding new virtual methods in Type_handler: * Column_definition_prepare_stage1() * Column_definition_prepare_stage2() * calc_pack_length() - Using new methods to remove type specific code in: * Global function calc_pack_length() * Column_definition::prepare_create_field() * The loop body mysql_prepare_create_table() * Column_definition::sp_prepare_create_field() --- sql/field.cc | 176 ++++++++------------- sql/field.h | 54 ++++++- sql/sql_lex.cc | 9 +- sql/sql_table.cc | 474 ++++++++++++++++++++++++++----------------------------- sql/sql_table.h | 2 +- sql/sql_type.cc | 301 +++++++++++++++++++++++++++++++++++ sql/sql_type.h | 215 +++++++++++++++++++++++++ 7 files changed, 850 insertions(+), 381 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index b17198b3a1e..577b09e948d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -53,15 +53,6 @@ static const char *zero_timestamp="0000-00-00 00:00:00.000000"; LEX_CSTRING temp_lex_str= {"temp", 4}; -/* number of bytes to store second_part part of the TIMESTAMP(N) */ -static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; - -/* number of bytes to store DATETIME(N) */ -static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= { 5, 6, 6, 7, 7, 7, 8 }; - -/* number of bytes to store TIME(N) */ -static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= { 3, 4, 4, 5, 5, 5, 6 }; - uchar Field_null::null[1]={1}; const char field_separator=','; @@ -5226,14 +5217,14 @@ static longlong read_bigendian(const uchar *from, uint bytes) void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { mi_int4store(ptr, timestamp); - store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes[dec]); + store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes(dec)); } my_time_t Field_timestamp_hires::get_timestamp(const uchar *pos, ulong *sec_part) const { ASSERT_COLUMN_MARKED_FOR_READ; - *sec_part= (long)sec_part_unshift(read_bigendian(pos+4, sec_part_bytes[dec]), dec); + *sec_part= (long)sec_part_unshift(read_bigendian(pos+4, sec_part_bytes(dec)), dec); return mi_uint4korr(pos); } @@ -5300,19 +5291,14 @@ int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) int32 a,b; ulong a_sec_part, b_sec_part; a= mi_uint4korr(a_ptr); - a_sec_part= (ulong)read_bigendian(a_ptr+4, sec_part_bytes[dec]); + a_sec_part= (ulong)read_bigendian(a_ptr+4, sec_part_bytes(dec)); b= mi_uint4korr(b_ptr); - b_sec_part= (ulong)read_bigendian(b_ptr+4, sec_part_bytes[dec]); + b_sec_part= (ulong)read_bigendian(b_ptr+4, sec_part_bytes(dec)); return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : a_sec_part < b_sec_part ? -1 : a_sec_part > b_sec_part ? 1 : 0; } -uint32 Field_timestamp_hires::pack_length() const -{ - return 4 + sec_part_bytes[dec]; -} - void Field_timestamp_with_dec::make_field(Send_field *field) { Field::make_field(field); @@ -5951,11 +5937,6 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, } -uint32 Field_time_hires::pack_length() const -{ - return time_hires_bytes[dec]; -} - longlong Field_time_with_dec::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -6658,11 +6639,6 @@ bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos, } -uint32 Field_datetime_hires::pack_length() const -{ - return datetime_hires_bytes[dec]; -} - int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) { ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length()); @@ -9803,6 +9779,32 @@ void Column_definition::set_attributes(const Lex_field_type_st &type, } +void Column_definition::create_length_to_internal_length_bit() +{ + if (f_bit_as_char(pack_flag)) + { + key_length= pack_length= ((length + 7) & ~7) / 8; + } + else + { + pack_length= length / 8; + /* We need one extra byte to store the bits we save among the null bits */ + key_length= pack_length + MY_TEST(length & 7); + } +} + + +void Column_definition::create_length_to_internal_length_newdecimal() +{ + key_length= pack_length= + my_decimal_get_binary_size(my_decimal_length_to_precision(length, + decimals, + flags & + UNSIGNED_FLAG), + decimals); +} + + /** Convert create_field::length from number of characters to number of bytes. */ @@ -9818,38 +9820,41 @@ void Column_definition::create_length_to_internal_length(void) case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VARCHAR: - length*= charset->mbmaxlen; - key_length= length; - pack_length= calc_pack_length(real_field_type(), length); + create_length_to_internal_length_string(); break; case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: - /* Pack_length already calculated in sql_parse.cc */ - length*= charset->mbmaxlen; - key_length= pack_length; + create_length_to_internal_length_typelib(); break; case MYSQL_TYPE_BIT: - if (f_bit_as_char(pack_flag)) - { - key_length= pack_length= ((length + 7) & ~7) / 8; - } - else - { - pack_length= length / 8; - /* We need one extra byte to store the bits we save among the null bits */ - key_length= pack_length + MY_TEST(length & 7); - } + create_length_to_internal_length_bit(); break; case MYSQL_TYPE_NEWDECIMAL: - key_length= pack_length= - my_decimal_get_binary_size(my_decimal_length_to_precision(length, - decimals, - flags & - UNSIGNED_FLAG), - decimals); + create_length_to_internal_length_newdecimal(); break; - default: - key_length= pack_length= calc_pack_length(real_field_type(), length); + + case MYSQL_TYPE_NULL: + create_length_to_internal_length_null(); + break; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_TIMESTAMP2: + create_length_to_internal_length_simple(); break; } } @@ -10110,64 +10115,6 @@ enum_field_types get_blob_type_from_length(ulong length) } -/* - Make a field from the .frm file info -*/ - -uint32 calc_pack_length(enum_field_types type,uint32 length) -{ - switch (type) { - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_DECIMAL: return (length); - case MYSQL_TYPE_VARCHAR: return (length + (length < 256 ? 1: 2)); - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_TINY : return 1; - case MYSQL_TYPE_SHORT : return 2; - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_NEWDATE: return 3; - case MYSQL_TYPE_TIME: return length > MIN_TIME_WIDTH - ? time_hires_bytes[length - 1 - MIN_TIME_WIDTH] - : 3; - case MYSQL_TYPE_TIME2: - return length > MIN_TIME_WIDTH ? - my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3; - case MYSQL_TYPE_TIMESTAMP: - return length > MAX_DATETIME_WIDTH - ? 4 + sec_part_bytes[length - 1 - MAX_DATETIME_WIDTH] - : 4; - case MYSQL_TYPE_TIMESTAMP2: - return length > MAX_DATETIME_WIDTH ? - my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4; - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_LONG : return 4; - case MYSQL_TYPE_FLOAT : return sizeof(float); - case MYSQL_TYPE_DOUBLE: return sizeof(double); - case MYSQL_TYPE_DATETIME: - return length > MAX_DATETIME_WIDTH - ? datetime_hires_bytes[length - 1 - MAX_DATETIME_WIDTH] - : 8; - case MYSQL_TYPE_DATETIME2: - return length > MAX_DATETIME_WIDTH ? - my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5; - case MYSQL_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */ - case MYSQL_TYPE_NULL : return 0; - case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr; - case MYSQL_TYPE_BLOB: return 2+portable_sizeof_char_ptr; - case MYSQL_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr; - case MYSQL_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr; - case MYSQL_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr; - case MYSQL_TYPE_SET: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_NEWDECIMAL: - abort(); return 0; // This shouldn't happen - case MYSQL_TYPE_BIT: return length / 8; - default: - return 0; - } -} - - uint pack_length_to_packflag(uint type) { switch (type) { @@ -10248,9 +10195,12 @@ Field *make_field(TABLE_SHARE *share, return 0; // Error } - uint pack_length=calc_pack_length((enum_field_types) - f_packtype(pack_flag), - field_length); + // MYSQL_TYPE_VAR_STRING is handled above + DBUG_ASSERT(f_packtype(pack_flag) != MYSQL_TYPE_VAR_STRING); + const Type_handler *tmp; + tmp= Type_handler::get_handler_by_real_type((enum_field_types) + f_packtype(pack_flag)); + uint pack_length= tmp->calc_pack_length(field_length); #ifdef HAVE_SPATIAL if (f_is_geom(pack_flag)) diff --git a/sql/field.h b/sql/field.h index 093fcce6fac..10363fd855b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2454,6 +2454,10 @@ public: class Field_timestamp_hires :public Field_timestamp_with_dec { + uint sec_part_bytes(uint dec) const + { + return Type_handler_timestamp::sec_part_bytes(dec); + } public: Field_timestamp_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, @@ -2468,7 +2472,7 @@ public: my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; void store_TIME(my_time_t timestamp, ulong sec_part); int cmp(const uchar *,const uchar *); - uint32 pack_length() const; + uint32 pack_length() const { return 4 + sec_part_bytes(dec); } uint size_of() const { return sizeof(*this); } }; @@ -2735,7 +2739,7 @@ public: bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); int cmp(const uchar *,const uchar *); void sort_string(uchar *buff,uint length); - uint32 pack_length() const; + uint32 pack_length() const { return Type_handler_time::hires_bytes(dec); } uint size_of() const { return sizeof(*this); } }; @@ -2894,7 +2898,7 @@ public: DBUG_ASSERT(dec); } int cmp(const uchar *,const uchar *); - uint32 pack_length() const; + uint32 pack_length() const { return Type_handler_datetime::hires_bytes(dec); } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); } uint size_of() const { return sizeof(*this); } @@ -3831,6 +3835,8 @@ class Column_definition: public Sql_alloc, set_if_bigger(*max_length, (uint32)length); } } + bool prepare_stage1_check_typelib_default(); + bool prepare_stage1_convert_default(THD *, MEM_ROOT *, CHARSET_INFO *to); const Type_handler *field_type() const; // Prevent using this public: LEX_CSTRING field_name; @@ -3882,6 +3888,29 @@ public: Column_definition(THD *thd, Field *field, Field *orig_field); void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs); void create_length_to_internal_length(void); + void create_length_to_internal_length_null() + { + DBUG_ASSERT(length == 0); + key_length= pack_length= 0; + } + void create_length_to_internal_length_simple() + { + key_length= pack_length= type_handler()->calc_pack_length(length); + } + void create_length_to_internal_length_string() + { + length*= charset->mbmaxlen; + key_length= length; + pack_length= type_handler()->calc_pack_length(length); + } + void create_length_to_internal_length_typelib() + { + /* Pack_length already calculated in sql_parse.cc */ + length*= charset->mbmaxlen; + key_length= pack_length; + } + void create_length_to_internal_length_bit(); + void create_length_to_internal_length_newdecimal(); /** Prepare a SET/ENUM field. @@ -3917,8 +3946,22 @@ public: bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); - bool prepare_create_field(uint *blob_columns, ulonglong table_flags); - + bool prepare_stage1(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage1_typelib(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage1_string(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage1_bit(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + + bool prepare_stage2(handler *handler, ulonglong table_flags); + bool prepare_stage2_blob(handler *handler, + ulonglong table_flags, uint field_flags); + bool prepare_stage2_varchar(ulonglong table_flags); + bool prepare_stage2_typelib(const char *type_name, uint field_flags, + uint *dup_val_count); + uint pack_flag_numeric(uint dec) const; uint sign_length() const { return flags & UNSIGNED_FLAG ? 0 : 1; } bool check_length(uint mysql_errno, uint max_allowed_length) const; bool fix_attributes_real(uint default_length); @@ -4212,7 +4255,6 @@ public: uint pack_length_to_packflag(uint type); enum_field_types get_blob_type_from_length(ulong length); -uint32 calc_pack_length(enum_field_types type,uint32 length); int set_field_to_null(Field *field); int set_field_to_null_with_conversions(Field *field, bool no_conversions); int convert_null_to_field_value_or_error(Field *field); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8cabe795d21..febd0931e48 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5407,13 +5407,8 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, spcont->declare_var_boundary(1); spvar->field_def.field_name= spvar->name; spvar->field_def.set_handler(&type_handler_longlong); - /* - The below is a simplified version of what - Column_definition::prepare_create_field() does for a LONGLONG field. - */ - spvar->field_def.pack_flag= (FIELDFLAG_NUMBER | - f_settype((uint) MYSQL_TYPE_LONGLONG)); - + type_handler_longlong.Column_definition_prepare_stage2(&spvar->field_def, + NULL, HA_CAN_GEOMETRY); if (!value && !(value= new (thd->mem_root) Item_null(thd))) return NULL; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f985f6e73fc..e202552ac8a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2845,23 +2845,82 @@ bool check_duplicates_in_interval(const char *set_or_name, } +bool Column_definition::prepare_stage2_blob(handler *file, + ulonglong table_flags, + uint field_flags) +{ + if (table_flags & HA_NO_BLOBS) + { + my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0), file->table_type()); + return true; + } + pack_flag= field_flags | + pack_length_to_packflag(pack_length - portable_sizeof_char_ptr); + if (charset->state & MY_CS_BINSORT) + pack_flag|= FIELDFLAG_BINARY; + length= 8; // Unireg field length + return false; +} + + +bool Column_definition::prepare_stage2_typelib(const char *type_name, + uint field_flags, + uint *dup_val_count) +{ + pack_flag= pack_length_to_packflag(pack_length) | field_flags; + if (charset->state & MY_CS_BINSORT) + pack_flag|= FIELDFLAG_BINARY; + return check_duplicates_in_interval(type_name, field_name.str, interval, + charset, dup_val_count); +} + + +uint Column_definition::pack_flag_numeric(uint dec) const +{ + return (FIELDFLAG_NUMBER | + (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | + (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) | + (dec << FIELDFLAG_DEC_SHIFT)); +} + + +bool Column_definition::prepare_stage2_varchar(ulonglong table_flags) +{ +#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR + if (table_flags & HA_NO_VARCHAR) + { + /* convert VARCHAR to CHAR because handler is not yet up to date */ + set_handler(&type_handler_var_string); + pack_length= type_handler()->calc_pack_length((uint) length); + if ((length / charset->mbmaxlen) > MAX_FIELD_CHARLENGTH) + { + my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name.str, + static_cast(MAX_FIELD_CHARLENGTH)); + return true; + } + } +#endif + pack_flag= (charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0; + return false; +} + + /* Prepare a Column_definition instance for packing Members such as pack_flag are valid after this call. - @param IN/OUT blob_columns - count for BLOBs + @param IN handler - storage engine handler, + or NULL if preparing for an SP variable @param IN table_flags - table flags @retval false - ok @retval true - error (not supported type, bad definition, etc) */ -bool Column_definition::prepare_create_field(uint *blob_columns, - ulonglong table_flags) +bool Column_definition::prepare_stage2(handler *file, + ulonglong table_flags) { - uint dup_val_count; - uint decimals_orig= decimals; - DBUG_ENTER("Column_definition::prepare_create_field"); + DBUG_ENTER("Column_definition::prepare_stage2"); /* This code came from mysql_prepare_create_table. @@ -2869,122 +2928,9 @@ bool Column_definition::prepare_create_field(uint *blob_columns, */ DBUG_ASSERT(charset); - switch (real_field_type()) { - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_LONG_BLOB: - pack_flag= FIELDFLAG_BLOB | - pack_length_to_packflag(pack_length - portable_sizeof_char_ptr); - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - length= 8; // Unireg field length - (*blob_columns)++; - break; - case MYSQL_TYPE_GEOMETRY: -#ifdef HAVE_SPATIAL - if (!(table_flags & HA_CAN_GEOMETRY)) - { - my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY"); - DBUG_RETURN(1); - } - pack_flag= FIELDFLAG_GEOM | - pack_length_to_packflag(pack_length - portable_sizeof_char_ptr); - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - length= 8; // Unireg field length - (*blob_columns)++; - break; -#else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); + if (type_handler()->Column_definition_prepare_stage2(this, file, table_flags)) DBUG_RETURN(true); -#endif /*HAVE_SPATIAL*/ - case MYSQL_TYPE_VARCHAR: -#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR - if (table_flags & HA_NO_VARCHAR) - { - /* convert VARCHAR to CHAR because handler is not yet up to date */ - set_handler(&type_handler_var_string); - pack_length= calc_pack_length(real_field_type(), (uint) length); - if ((length / charset->mbmaxlen) > MAX_FIELD_CHARLENGTH) - { - my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name.str, - static_cast(MAX_FIELD_CHARLENGTH)); - DBUG_RETURN(true); - } - } -#endif - /* fall through */ - case MYSQL_TYPE_STRING: - pack_flag= 0; - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - break; - case MYSQL_TYPE_ENUM: - pack_flag= pack_length_to_packflag(pack_length) | FIELDFLAG_INTERVAL; - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - if (check_duplicates_in_interval("ENUM", field_name.str, interval, - charset, &dup_val_count)) - DBUG_RETURN(true); - break; - case MYSQL_TYPE_SET: - pack_flag= pack_length_to_packflag(pack_length) | FIELDFLAG_BITFIELD; - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - if (check_duplicates_in_interval("SET", field_name.str, interval, - charset, &dup_val_count)) - DBUG_RETURN(true); - /* Check that count of unique members is not more then 64 */ - if (interval->count - dup_val_count > sizeof(longlong)*8) - { - my_error(ER_TOO_BIG_SET, MYF(0), field_name.str); - DBUG_RETURN(true); - } - break; - case MYSQL_TYPE_DATE: // Rest of string types - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIME2: - case MYSQL_TYPE_DATETIME2: - case MYSQL_TYPE_NULL: - pack_flag= f_settype((uint) real_field_type()); - break; - case MYSQL_TYPE_BIT: - /* - We have sql_field->pack_flag already set here, see - mysql_prepare_create_table(). - */ - break; - case MYSQL_TYPE_NEWDECIMAL: - pack_flag= (FIELDFLAG_NUMBER | - (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | - (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) | - (decimals_orig << FIELDFLAG_DEC_SHIFT)); - break; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - /* - User specified FLOAT() or DOUBLE() without precision. Change to - FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB - versions. - */ - if (decimals_orig >= FLOATING_POINT_DECIMALS) - decimals_orig= FLOATING_POINT_DECIMALS; - /* fall-trough */ - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_TIMESTAMP2: - /* fall-through */ - default: - pack_flag= (FIELDFLAG_NUMBER | - (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | - (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) | - f_settype((uint) real_field_type()) | - (decimals_orig << FIELDFLAG_DEC_SHIFT)); - break; - } + if (!(flags & NOT_NULL_FLAG) || (vcol_info)) /* Make virtual columns allow NULL values */ pack_flag|= FIELDFLAG_MAYBE_NULL; @@ -3007,7 +2953,7 @@ bool Column_definition::prepare_create_field(uint *blob_columns, cs Character set */ -CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, +CHARSET_INFO* get_sql_field_charset(Column_definition *sql_field, HA_CREATE_INFO *create_info) { CHARSET_INFO *cs= sql_field->charset; @@ -3146,6 +3092,143 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info, } +bool Column_definition::prepare_stage1_typelib(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + /* + Pass the last parameter to prepare_interval_field() as follows: + - If we are preparing for an SP variable (file is NULL), we pass "false", + to force allocation and full copying of TYPELIB values on the given + mem_root, even if no character set conversion is needed. This is needed + because a life cycle of an SP variable is longer than the current query. + + - If we are preparing for a CREATE TABLE, (file != NULL), we pass "true". + This will create the typelib in runtime memory - we will free the + occupied memory at the same time when we free this + sql_field -- at the end of execution. + Pass "true" as the last argument to reuse "interval_list" + values in "interval" in cases when no character conversion is needed, + to avoid extra copying. + */ + if (prepare_interval_field(mem_root, file != NULL)) + return true; // E.g. wrong values with commas: SET('a,b') + create_length_to_internal_length_typelib(); + + DBUG_ASSERT(file || !default_value); // SP variables have no default_value + if (default_value && default_value->expr->basic_const_item()) + { + if ((charset != default_value->expr->collation.collation && + prepare_stage1_convert_default(thd, mem_root, charset)) || + prepare_stage1_check_typelib_default()) + return true; + } + return false; +} + + +bool Column_definition::prepare_stage1_string(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + create_length_to_internal_length_string(); + if (prepare_blob_field(thd)) + return true; + DBUG_ASSERT(file || !default_value); // SP variables have no default_value + /* + Convert the default value from client character + set into the column character set if necessary. + We can only do this for constants as we have not yet run fix_fields. + */ + if (default_value && + default_value->expr->basic_const_item() && + charset != default_value->expr->collation.collation) + { + if (prepare_stage1_convert_default(thd, mem_root, charset)) + return true; + } + return false; +} + + +bool Column_definition::prepare_stage1_bit(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + pack_flag= FIELDFLAG_NUMBER; + if (!(table_flags & HA_CAN_BIT_FIELD)) + pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; + create_length_to_internal_length_bit(); + return false; +} + + +bool Column_definition::prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + return type_handler()->Column_definition_prepare_stage1(thd, mem_root, + this, file, + table_flags); +} + + +bool Column_definition::prepare_stage1_convert_default(THD *thd, + MEM_ROOT *mem_root, + CHARSET_INFO *cs) +{ + DBUG_ASSERT(thd->mem_root == mem_root); + Item *item; + if (!(item= default_value->expr->safe_charset_converter(thd, cs))) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name.str); + return true; // Could not convert + } + /* Fix for prepare statement */ + thd->change_item_tree(&default_value->expr, item); + return false; +} + + +bool Column_definition::prepare_stage1_check_typelib_default() +{ + StringBuffer str; + String *def= default_value->expr->val_str(&str); + bool not_found; + if (def == NULL) /* SQL "NULL" maps to NULL */ + { + not_found= flags & NOT_NULL_FLAG; + } + else + { + not_found= false; + if (real_field_type() == MYSQL_TYPE_SET) + { + char *not_used; + uint not_used2; + find_set(interval, def->ptr(), def->length(), + charset, ¬_used, ¬_used2, ¬_found); + } + else /* MYSQL_TYPE_ENUM */ + { + def->length(charset->cset->lengthsp(charset, + def->ptr(), def->length())); + not_found= !find_type2(interval, def->ptr(), def->length(), charset); + } + } + if (not_found) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name.str); + return true; + } + return false; +} + + /* Preparation for table creation @@ -3180,7 +3263,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { const char *key_name; Create_field *sql_field,*dup_field; - uint field,null_fields,blob_columns,max_key_length; + uint field,null_fields,max_key_length; ulong record_offset= 0; KEY *key_info; KEY_PART_INFO *key_part_info; @@ -3193,7 +3276,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, bool tmp_table= create_table_mode == C_ALTER_TABLE; DBUG_ENTER("mysql_prepare_create_table"); - null_fields=blob_columns=0; + null_fields= 0; create_info->varchar= 0; max_key_length= file->max_key_length(); @@ -3215,8 +3298,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, select_field_pos= alter_info->create_list.elements - select_field_count; for (field_no=0; (sql_field=it++) ; field_no++) { - CHARSET_INFO *save_cs; - /* Initialize length from its original value (number of characters), which was set in the parser. This is necessary if we're @@ -3224,105 +3305,18 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, */ sql_field->length= sql_field->char_length; /* Set field charset. */ - save_cs= sql_field->charset= get_sql_field_charset(sql_field, create_info); + sql_field->charset= get_sql_field_charset(sql_field, create_info); if ((sql_field->flags & BINCMP_FLAG) && - !(sql_field->charset= find_bin_collation(sql_field->charset))) - DBUG_RETURN(TRUE); - - if (sql_field->real_field_type() == MYSQL_TYPE_SET || - sql_field->real_field_type() == MYSQL_TYPE_ENUM) - { - /* - Create the typelib in runtime memory - we will free the - occupied memory at the same time when we free this - sql_field -- at the end of execution. - Pass "true" as the last argument to reuse "interval_list" - values in "interval" in cases when no character conversion is needed, - to avoid extra copying. - */ - if (sql_field->prepare_interval_field(thd->mem_root, true)) - DBUG_RETURN(true); // E.g. wrong values with commas: SET('a,b') - } - - if (sql_field->real_field_type() == MYSQL_TYPE_BIT) - { - sql_field->pack_flag= FIELDFLAG_NUMBER; - if (file->ha_table_flags() & HA_CAN_BIT_FIELD) - total_uneven_bit_length+= sql_field->length & 7; - else - sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; - } - - sql_field->create_length_to_internal_length(); - if (sql_field->prepare_blob_field(thd)) - DBUG_RETURN(TRUE); - - /* - Convert the default value from client character - set into the column character set if necessary. - We can only do this for constants as we have not yet run fix_fields. - */ - if (sql_field->default_value && - sql_field->default_value->expr->basic_const_item() && - save_cs != sql_field->default_value->expr->collation.collation && - (sql_field->real_field_type() == MYSQL_TYPE_VAR_STRING || - sql_field->real_field_type() == MYSQL_TYPE_STRING || - sql_field->real_field_type() == MYSQL_TYPE_SET || - sql_field->real_field_type() == MYSQL_TYPE_TINY_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_MEDIUM_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_LONG_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_ENUM)) - { - Item *item; - if (!(item= sql_field->default_value->expr-> - safe_charset_converter(thd, save_cs))) - { - /* Could not convert */ - my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name.str); - DBUG_RETURN(TRUE); - } - /* Fix for prepare statement */ - thd->change_item_tree(&sql_field->default_value->expr, item); - } + !(sql_field->charset= find_bin_collation(sql_field->charset))) + DBUG_RETURN(true); - if (sql_field->default_value && - sql_field->default_value->expr->basic_const_item() && - (sql_field->real_field_type() == MYSQL_TYPE_SET || - sql_field->real_field_type() == MYSQL_TYPE_ENUM)) - { - StringBuffer str; - String *def= sql_field->default_value->expr->val_str(&str); - bool not_found; - if (def == NULL) /* SQL "NULL" maps to NULL */ - { - not_found= sql_field->flags & NOT_NULL_FLAG; - } - else - { - not_found= false; - if (sql_field->real_field_type() == MYSQL_TYPE_SET) - { - char *not_used; - uint not_used2; - find_set(sql_field->interval, def->ptr(), def->length(), - sql_field->charset, ¬_used, ¬_used2, ¬_found); - } - else /* MYSQL_TYPE_ENUM */ - { - def->length(sql_field->charset->cset->lengthsp(sql_field->charset, - def->ptr(), def->length())); - not_found= !find_type2(sql_field->interval, def->ptr(), - def->length(), sql_field->charset); - } - } + if (sql_field->prepare_stage1(thd, thd->mem_root, + file, file->ha_table_flags())) + DBUG_RETURN(true); - if (not_found) - { - my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name.str); - DBUG_RETURN(TRUE); - } - } + if (sql_field->real_field_type() == MYSQL_TYPE_BIT && + file->ha_table_flags() & HA_CAN_BIT_FIELD) + total_uneven_bit_length+= sql_field->length & 7; if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields++; @@ -3419,7 +3413,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { DBUG_ASSERT(sql_field->charset != 0); - if (sql_field->prepare_create_field(&blob_columns, file->ha_table_flags())) + if (sql_field->prepare_stage2(file, file->ha_table_flags())) DBUG_RETURN(TRUE); if (sql_field->real_field_type() == MYSQL_TYPE_VARCHAR) create_info->varchar= TRUE; @@ -3461,12 +3455,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(TRUE); } - if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS)) - { - my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0), file->table_type()); - DBUG_RETURN(TRUE); - } - /* CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows inserted in the created table depends on the order of the rows fetched @@ -4237,7 +4225,7 @@ bool Column_definition::prepare_blob_field(THD *thd) { /* The user has given a length to the blob column */ set_handler(Type_handler::blob_type_handler(length)); - pack_length= calc_pack_length(real_field_type(), 0); + pack_length= type_handler()->calc_pack_length(0); } length= 0; } @@ -4262,30 +4250,8 @@ bool Column_definition::prepare_blob_field(THD *thd) bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) { - if (real_field_type() == MYSQL_TYPE_SET || - real_field_type() == MYSQL_TYPE_ENUM) - { - /* - Pass "false" as the last argument to allocate TYPELIB values on mem_root, - even if no character set conversion is needed. - */ - if (prepare_interval_field(mem_root, false)) - return true; // E.g. wrong values with commas: SET('a,b') - } - - if (real_field_type() == MYSQL_TYPE_BIT) - pack_flag= FIELDFLAG_NUMBER | FIELDFLAG_TREAT_BIT_AS_CHAR; - create_length_to_internal_length(); - DBUG_ASSERT(default_value == 0); - /* - prepare_blob_field() can return an error on attempt to create a too long - VARCHAR/VARBINARY field when the current sql_mode does not allow automatic - conversion to TEXT/BLOB. - */ - if (prepare_blob_field(thd)) - return true; - uint unused1; - return prepare_create_field(&unused1, HA_CAN_GEOMETRY); + return prepare_stage1(thd, mem_root, NULL, HA_CAN_GEOMETRY) || + prepare_stage2(NULL, HA_CAN_GEOMETRY); } diff --git a/sql/sql_table.h b/sql/sql_table.h index 4fb6135e9cc..2e080462deb 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -253,7 +253,7 @@ bool quick_rm_table(THD *thd, handlerton *base, const char *db, const char *table_path=0); void close_cached_table(THD *thd, TABLE *table); void sp_prepare_create_field(THD *thd, Column_definition *sql_field); -CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, +CHARSET_INFO* get_sql_field_charset(Column_definition *sql_field, HA_CREATE_INFO *create_info); bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); int write_bin_log(THD *thd, bool clear_error, diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 5e08a616d9f..90f8d674e67 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -379,6 +379,20 @@ Type_handler_hybrid_field_type::Type_handler_hybrid_field_type() } +/***************************************************************************/ + +/* number of bytes to store second_part part of the TIMESTAMP(N) */ +uint Type_handler_timestamp::m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]= + { 0, 1, 1, 2, 2, 3, 3 }; + +/* number of bytes to store DATETIME(N) */ +uint Type_handler_datetime::m_hires_bytes[MAX_DATETIME_PRECISION + 1]= + { 5, 6, 6, 7, 7, 7, 8 }; + +/* number of bytes to store TIME(N) */ +uint Type_handler_time::m_hires_bytes[MAX_DATETIME_PRECISION + 1]= + { 3, 4, 4, 5, 5, 5, 6 }; + /***************************************************************************/ const Name Type_handler_row::m_name_row(C_STRING_WITH_LEN("row")); @@ -1539,6 +1553,293 @@ bool Type_handler_bit:: return def->fix_attributes_bit(); } +/*************************************************************************/ + +bool Type_handler:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_simple(); + return false; +} + +bool Type_handler_null:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_null(); + return false; +} + +bool Type_handler_newdecimal:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_newdecimal(); + return false; +} + +bool Type_handler_bit:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage1_bit(thd, mem_root, file, table_flags); +} + +bool Type_handler_typelib:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage1_typelib(thd, mem_root, file, table_flags); +} + + +bool Type_handler_string_result:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage1_string(thd, mem_root, file, table_flags); +} + + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_string(); + return def->prepare_blob_field(thd); +} +#endif + + +/*************************************************************************/ + +bool Type_handler:: + Column_definition_prepare_stage2_legacy(Column_definition *def, + enum_field_types type) const +{ + def->pack_flag= f_settype((uint) type); + return false; +} + +bool Type_handler:: + Column_definition_prepare_stage2_legacy_num(Column_definition *def, + enum_field_types type) const +{ + def->pack_flag= def->pack_flag_numeric(def->decimals) | + f_settype((uint) type); + return false; +} + +bool Type_handler:: + Column_definition_prepare_stage2_legacy_real(Column_definition *def, + enum_field_types type) const +{ + uint dec= def->decimals; + /* + User specified FLOAT() or DOUBLE() without precision. Change to + FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB + versions. + */ + if (dec >= FLOATING_POINT_DECIMALS) + dec= FLOATING_POINT_DECIMALS; + def->pack_flag= def->pack_flag_numeric(dec) | f_settype((uint) type); + return false; +} + +bool Type_handler_newdecimal:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->pack_flag= def->pack_flag_numeric(def->decimals); + return false; +} + +bool Type_handler_blob_common:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_BLOB); +} + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + if (!(table_flags & HA_CAN_GEOMETRY)) + { + my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY"); + return true; + } + return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_GEOM); +} +#endif + +bool Type_handler_varchar:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage2_varchar(table_flags); +} + +bool Type_handler_string:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->pack_flag= (def->charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0; + return false; +} + +bool Type_handler_enum:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + uint dummy; + return def->prepare_stage2_typelib("ENUM", FIELDFLAG_INTERVAL, &dummy); +} + +bool Type_handler_set:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + uint dup_count; + if (def->prepare_stage2_typelib("SET", FIELDFLAG_BITFIELD, &dup_count)) + return true; + /* Check that count of unique members is not more then 64 */ + if (def->interval->count - dup_count > sizeof(longlong)*8) + { + my_error(ER_TOO_BIG_SET, MYF(0), def->field_name.str); + return true; + } + return false; +} + +bool Type_handler_bit:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + /* + We have sql_field->pack_flag already set here, see + mysql_prepare_create_table(). + */ + return false; +} + +/*************************************************************************/ + +uint32 Type_handler_time::calc_pack_length(uint32 length) const +{ + return length > MIN_TIME_WIDTH ? + hires_bytes(length - 1 - MIN_TIME_WIDTH) : 3; +} + +uint32 Type_handler_time2::calc_pack_length(uint32 length) const +{ + return length > MIN_TIME_WIDTH ? + my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3; +} + +uint32 Type_handler_timestamp::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + 4 + sec_part_bytes(length - 1 - MAX_DATETIME_WIDTH) : 4; +} + +uint32 Type_handler_timestamp2::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4; +} + +uint32 Type_handler_datetime::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + hires_bytes(length - 1 - MAX_DATETIME_WIDTH) : 8; +} + +uint32 Type_handler_datetime2::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5; +} + +uint32 Type_handler_tiny_blob::calc_pack_length(uint32 length) const +{ + return 1 + portable_sizeof_char_ptr; +} + +uint32 Type_handler_blob::calc_pack_length(uint32 length) const +{ + return 2 + portable_sizeof_char_ptr; +} + +uint32 Type_handler_medium_blob::calc_pack_length(uint32 length) const +{ + return 3 + portable_sizeof_char_ptr; +} + +uint32 Type_handler_long_blob::calc_pack_length(uint32 length) const +{ + return 4 + portable_sizeof_char_ptr; +} + +#ifdef HAVE_SPATIAL +uint32 Type_handler_geometry::calc_pack_length(uint32 length) const +{ + return 4 + portable_sizeof_char_ptr; +} +#endif + +uint32 Type_handler_newdecimal::calc_pack_length(uint32 length) const +{ + abort(); // This shouldn't happen + return 0; +} + +uint32 Type_handler_set::calc_pack_length(uint32 length) const +{ + abort(); // This shouldn't happen + return 0; +} + +uint32 Type_handler_enum::calc_pack_length(uint32 length) const +{ + abort(); // This shouldn't happen + return 0; +} + + /*************************************************************************/ Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name, const Record_addr &addr, diff --git a/sql/sql_type.h b/sql/sql_type.h index 7acab7078e1..28bb2a2edc9 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -67,6 +67,7 @@ class Sort_param; class Arg_comparator; struct st_value; class Protocol; +class handler; struct TABLE; struct SORT_FIELD_ATTR; @@ -549,6 +550,15 @@ protected: bool Item_send_time(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_date(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const; + bool Column_definition_prepare_stage2_legacy(Column_definition *c, + enum_field_types type) + const; + bool Column_definition_prepare_stage2_legacy_num(Column_definition *c, + enum_field_types type) + const; + bool Column_definition_prepare_stage2_legacy_real(Column_definition *c, + enum_field_types type) + const; public: static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); @@ -692,6 +702,14 @@ public: uint metadata, const Field *target) const= 0; virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0; + virtual bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + virtual bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const= 0; virtual Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -708,6 +726,7 @@ public: SORT_FIELD_ATTR *attr) const= 0; virtual uint32 max_display_length(const Item *item) const= 0; + virtual uint32 calc_pack_length(uint32 length) const= 0; virtual bool Item_save_in_value(Item *item, st_value *value) const= 0; virtual bool Item_param_set_from_value(THD *thd, Item_param *param, @@ -935,6 +954,22 @@ public: DBUG_ASSERT(0); return true; } + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const + { + DBUG_ASSERT(0); + return true; + } + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { + DBUG_ASSERT(0); + return true; + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -959,6 +994,11 @@ public: DBUG_ASSERT(0); return 0; } + uint32 calc_pack_length(uint32 length) const + { + DBUG_ASSERT(0); + return 0; + } uint Item_decimal_precision(const Item *item) const { DBUG_ASSERT(0); @@ -1470,6 +1510,11 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; uint32 max_display_length(const Item *item) const; uint Item_time_precision(Item *item) const { @@ -1578,6 +1623,7 @@ public: const Name name() const { return m_name_tiny; } enum_field_types field_type() const { return MYSQL_TYPE_TINY; } uint32 max_display_length(const Item *item) const { return 4; } + uint32 calc_pack_length(uint32 length) const { return 1; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_tiny(item, protocol, buf); @@ -1585,6 +1631,10 @@ public: Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TINY); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1604,9 +1654,14 @@ public: return Item_send_short(item, protocol, buf); } uint32 max_display_length(const Item *item) const { return 6; } + uint32 calc_pack_length(uint32 length) const { return 2; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_SHORT); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1625,6 +1680,7 @@ public: { return MY_INT32_NUM_DECIMAL_DIGITS; } + uint32 calc_pack_length(uint32 length) const { return 4; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_long(item, protocol, buf); @@ -1632,6 +1688,10 @@ public: Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONG); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1647,6 +1707,7 @@ public: const Name name() const { return m_name_longlong; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } uint32 max_display_length(const Item *item) const { return 20; } + uint32 calc_pack_length(uint32 length) const { return 8; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_longlong(item, protocol, buf); @@ -1654,6 +1715,12 @@ public: Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { + return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONGLONG); + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1673,9 +1740,14 @@ public: return Item_send_long(item, protocol, buf); } uint32 max_display_length(const Item *item) const { return 8; } + uint32 calc_pack_length(uint32 length) const { return 3; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_INT24); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1691,6 +1763,7 @@ public: const Name name() const { return m_name_year; } enum_field_types field_type() const { return MYSQL_TYPE_YEAR; } uint32 max_display_length(const Item *item) const; + uint32 calc_pack_length(uint32 length) const { return 1; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_short(item, protocol, buf); @@ -1698,6 +1771,10 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_YEAR); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1713,6 +1790,7 @@ public: const Name name() const { return m_name_bit; } enum_field_types field_type() const { return MYSQL_TYPE_BIT; } uint32 max_display_length(const Item *item) const; + uint32 calc_pack_length(uint32 length) const { return length / 8; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_str(item, protocol, buf); @@ -1724,6 +1802,14 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1740,6 +1826,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; } bool type_can_have_auto_increment_attribute() const { return true; } uint32 max_display_length(const Item *item) const { return 25; } + uint32 calc_pack_length(uint32 length) const { return sizeof(float); } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_float(item, protocol, buf); @@ -1748,6 +1835,10 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_FLOAT); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1764,6 +1855,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } bool type_can_have_auto_increment_attribute() const { return true; } uint32 max_display_length(const Item *item) const { return 53; } + uint32 calc_pack_length(uint32 length) const { return sizeof(double); } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_double(item, protocol, buf); @@ -1771,6 +1863,10 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_DOUBLE); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1821,10 +1917,18 @@ public: class Type_handler_time: public Type_handler_time_common { + /* number of bytes to store TIME(N) */ + static uint m_hires_bytes[MAX_DATETIME_PRECISION+1]; public: + static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_time() {} + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1837,8 +1941,13 @@ class Type_handler_time2: public Type_handler_time_common public: virtual ~Type_handler_time2() {} enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME2); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1889,8 +1998,13 @@ class Type_handler_date: public Type_handler_date_common { public: virtual ~Type_handler_date() {} + uint32 calc_pack_length(uint32 length) const { return 4; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATE); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1903,8 +2017,13 @@ class Type_handler_newdate: public Type_handler_date_common public: virtual ~Type_handler_newdate() {} enum_field_types real_field_type() const { return MYSQL_TYPE_NEWDATE; } + uint32 calc_pack_length(uint32 length) const { return 3; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NEWDATE); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1949,10 +2068,18 @@ public: class Type_handler_datetime: public Type_handler_datetime_common { + /* number of bytes to store DATETIME(N) */ + static uint m_hires_bytes[MAX_DATETIME_PRECISION + 1]; public: + static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_datetime() {} + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1965,8 +2092,13 @@ class Type_handler_datetime2: public Type_handler_datetime_common public: virtual ~Type_handler_datetime2() {} enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME2); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2015,10 +2147,18 @@ public: class Type_handler_timestamp: public Type_handler_timestamp_common { + /* number of bytes to store second_part part of the TIMESTAMP(N) */ + static uint m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]; public: + static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; } virtual ~Type_handler_timestamp() {} + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2031,8 +2171,15 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common public: virtual ~Type_handler_timestamp2() {} enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { + return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP2); + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2047,11 +2194,16 @@ public: virtual ~Type_handler_olddecimal() {} const Name name() const { return m_name_decimal; } enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } + uint32 calc_pack_length(uint32 length) const { return length; } const Type_handler *type_handler_for_tmp_table(const Item *item) const; const Type_handler *type_handler_for_union(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_DECIMAL); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2066,9 +2218,18 @@ public: virtual ~Type_handler_newdecimal() {} const Name name() const { return m_name_decimal; } enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2087,11 +2248,21 @@ public: const Type_handler *type_handler_for_tmp_table(const Item *item) const; const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } + uint32 calc_pack_length(uint32 length) const { return 0; } bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NULL); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2117,6 +2288,7 @@ public: const Name name() const { return m_name_char; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } bool is_param_long_data_type() const { return true; } + uint32 calc_pack_length(uint32 length) const { return length; } const Type_handler *type_handler_for_tmp_table(const Item *item) const { return varstring_type_handler(item); @@ -2124,6 +2296,9 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2145,6 +2320,10 @@ public: return varstring_type_handler(item); } bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_STRING); } const Type_handler *type_handler_for_union(const Item *item) const { return varstring_type_handler(item); @@ -2159,6 +2338,10 @@ public: virtual ~Type_handler_varchar() {} const Name name() const { return m_name_varchar; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + uint32 calc_pack_length(uint32 length) const + { + return (length + (length < 256 ? 1: 2)); + } const Type_handler *type_handler_for_tmp_table(const Item *item) const { return varstring_type_handler(item); @@ -2171,6 +2354,9 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2197,6 +2383,9 @@ public: } bool is_param_long_data_type() const { return true; } bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -2212,6 +2401,7 @@ public: virtual ~Type_handler_tiny_blob() {} const Name name() const { return m_name_tinyblob; } enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2228,6 +2418,7 @@ public: virtual ~Type_handler_medium_blob() {} const Name name() const { return m_name_mediumblob; } enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2244,6 +2435,7 @@ public: virtual ~Type_handler_long_blob() {} const Name name() const { return m_name_longblob; } enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2260,6 +2452,7 @@ public: virtual ~Type_handler_blob() {} const Name name() const { return m_name_blob; } enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2278,6 +2471,7 @@ public: const Name name() const { return m_name_geometry; } enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } bool is_param_long_data_type() const { return true; } + uint32 calc_pack_length(uint32 length) const; const Type_handler *type_handler_for_comparison() const; bool type_can_have_key_part() const { @@ -2295,6 +2489,14 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2343,6 +2545,11 @@ public: Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; }; @@ -2353,9 +2560,13 @@ public: virtual ~Type_handler_enum() {} const Name name() const { return m_name_enum; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2370,9 +2581,13 @@ public: virtual ~Type_handler_set() {} const Name name() const { return m_name_set; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, -- cgit v1.2.1