diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2017-06-01 11:02:32 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2017-06-02 09:36:04 +0300 |
commit | 3d615e4b1aa4f945f69d310f9a19de80fbaccdca (patch) | |
tree | 1d23c043ef41badf359760b70db84bc825a8b4a5 /sql | |
parent | 896c2c73a02c7e82299b00e66ee3ff5f85aa3adc (diff) | |
parent | 959891662dfbb0b860f0bc70e09bc2c92dab831b (diff) | |
download | mariadb-git-3d615e4b1aa4f945f69d310f9a19de80fbaccdca.tar.gz |
Merge branch 'bb-10.2-ext' into 10.3
This excludes MDEV-12472 (InnoDB should accept XtraDB parameters,
warning that they are ignored). In other words, MariaDB 10.3 will not
recognize any XtraDB-specific parameters.
Diffstat (limited to 'sql')
57 files changed, 2225 insertions, 1177 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index c84867e1c4f..87e41817857 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -70,6 +70,7 @@ ENDIF() ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h COMMAND gen_lex_token > lex_token.h + DEPENDS gen_lex_token ) ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER) @@ -84,39 +85,39 @@ SET (SQL_SOURCE filesort_utils.cc filesort.cc gstream.cc signal_handler.cc - handler.cc hash_filo.h + handler.cc hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc item_create.cc item_func.cc item_geofunc.cc item_row.cc item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc key.cc log.cc lock.cc log_event.cc rpl_record.cc rpl_reporting.cc log_event_old.cc rpl_record_old.cc - message.h mf_iocache.cc my_decimal.cc + mf_iocache.cc my_decimal.cc mysqld.cc net_serv.cc keycaches.cc ../sql-common/client_plugin.c - opt_range.cc opt_range.h opt_sum.cc + opt_range.cc opt_sum.cc ../sql-common/pack.c parse_file.cc password.c procedure.cc protocol.cc records.cc repl_failsafe.cc rpl_filter.cc session_tracker.cc set_var.cc slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc - sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h + sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_digest.cc sql_do.cc sql_error.cc sql_handler.cc sql_get_diagnostics.cc sql_help.cc sql_insert.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc - sql_parse.cc sql_bootstrap.cc sql_bootstrap.h + sql_parse.cc sql_bootstrap.cc sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc - debug_sync.cc debug_sync.h + debug_sync.cc sql_repl.cc sql_select.cc sql_show.cc sql_state.c group_by_handler.cc sql_statistics.cc sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc sql_time.cc tztime.cc unireg.cc item_xmlfunc.cc - uniques.cc uniques.h + uniques.cc rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc event_queue.cc event_db_repository.cc sql_tablespace.cc events.cc ../sql-common/my_user.c @@ -126,23 +127,23 @@ SET (SQL_SOURCE sql_profile.cc event_parse_data.cc sql_alter.cc sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc transaction.cc sys_vars.cc sql_truncate.cc datadict.cc - sql_reload.cc sql_cmd.h item_inetfunc.cc + sql_reload.cc item_inetfunc.cc # added in MariaDB: - sql_explain.h sql_explain.cc - sql_analyze_stmt.h sql_analyze_stmt.cc - sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc + sql_explain.cc + sql_analyze_stmt.cc + sql_join_cache.cc create_options.cc multi_range_read.cc opt_index_cond_pushdown.cc opt_subselect.cc opt_table_elimination.cc sql_expression_cache.cc gcalc_slicescan.cc gcalc_tools.cc threadpool_common.cc ../sql-common/mysql_async.c - my_apc.cc my_apc.h mf_iocache_encr.cc item_jsonfunc.cc - my_json_writer.cc my_json_writer.h + my_apc.cc mf_iocache_encr.cc item_jsonfunc.cc + my_json_writer.cc rpl_gtid.cc rpl_parallel.cc - sql_type.cc sql_type.h + sql_type.cc item_windowfunc.cc sql_window.cc - sql_cte.cc sql_cte.h + sql_cte.cc sql_sequence.cc sql_sequence.h ha_sequence.h ${WSREP_SOURCES} table_cache.cc encryption.cc temporary_tables.cc @@ -181,7 +182,7 @@ TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} ${LIBSYSTEMD}) IF(WIN32) - SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h message.rc) + SET(MYSQLD_SOURCE main.cc nt_servc.cc message.rc) TARGET_LINK_LIBRARIES(sql psapi) ELSE() SET(MYSQLD_SOURCE main.cc ${DTRACE_PROBES_ALL}) @@ -340,6 +341,7 @@ ENDIF() ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h COMMAND gen_lex_hash > lex_hash.h + DEPENDS gen_lex_hash ) MYSQL_ADD_EXECUTABLE(mysql_tzinfo_to_sql tztime.cc COMPONENT Server) @@ -458,7 +460,7 @@ IF(WIN32) ${CMAKE_CURRENT_BINARY_DIR}/my_bootstrap.sql mysql_bootstrap_sql.c WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${my_bootstrap_sql} + DEPENDS comp_sql ${my_bootstrap_sql} ) MYSQL_ADD_EXECUTABLE(mysql_install_db diff --git a/sql/datadict.cc b/sql/datadict.cc index b5a6a6794ce..edc9fe5681b 100644 --- a/sql/datadict.cc +++ b/sql/datadict.cc @@ -88,6 +88,12 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name, engine_name->length= 0; dbt= header[3]; + if (((header[39] >> 4) & 3) == HA_CHOICE_YES) + { + DBUG_PRINT("info", ("Sequence found")); + *is_sequence= 1; + } + /* cannot use ha_resolve_by_legacy_type without a THD */ if (thd && dbt < DB_TYPE_FIRST_DYNAMIC) { @@ -99,9 +105,6 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name, } } - if (((header[39] >> 4) & 3) == HA_CHOICE_YES) - *is_sequence= 1; - /* read the true engine name */ { MY_STAT state; diff --git a/sql/field.cc b/sql/field.cc index 577b09e948d..6320121d1c3 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9805,61 +9805,6 @@ void Column_definition::create_length_to_internal_length_newdecimal() } -/** - Convert create_field::length from number of characters to number of bytes. -*/ - -void Column_definition::create_length_to_internal_length(void) -{ - switch (real_field_type()) { - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_GEOMETRY: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_VARCHAR: - create_length_to_internal_length_string(); - break; - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - create_length_to_internal_length_typelib(); - break; - case MYSQL_TYPE_BIT: - create_length_to_internal_length_bit(); - break; - case MYSQL_TYPE_NEWDECIMAL: - create_length_to_internal_length_newdecimal(); - break; - - 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; - } -} - - bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, enum_vcol_info_type type) @@ -10497,6 +10442,33 @@ Column_definition::Column_definition(THD *thd, Field *old_field, /** + The common part for data type redefinition: + CREATE TABLE t1 (a INT) AS SELECT a FROM t2; + See Type_handler::Column_definition_redefine_stage1() + for data type specific code. +*/ +void +Column_definition::redefine_stage1_common(const Column_definition *dup_field, + const handler *file, + const Schema_specification_st *schema) +{ + set_handler(dup_field->type_handler()); + default_value= dup_field->default_value; + charset= dup_field->charset ? dup_field->charset : + schema->default_table_charset; + length= dup_field->char_length; + pack_length= dup_field->pack_length; + key_length= dup_field->key_length; + decimals= dup_field->decimals; + unireg_check= dup_field->unireg_check; + flags= dup_field->flags; + interval= dup_field->interval; + vcol_info= dup_field->vcol_info; +} + + + +/** maximum possible character length for blob. This method is used in Item_field::set_field to calculate diff --git a/sql/field.h b/sql/field.h index 10363fd855b..bfdb06984af 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3887,7 +3887,6 @@ 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); @@ -3955,6 +3954,16 @@ public: bool prepare_stage1_bit(THD *thd, MEM_ROOT *mem_root, handler *file, ulonglong table_flags); + void redefine_stage1_common(const Column_definition *dup_field, + const handler *file, + const Schema_specification_st *schema); + bool redefine_stage1(const Column_definition *dup_field, const handler *file, + const Schema_specification_st *schema) + { + const Type_handler *handler= dup_field->type_handler(); + return handler->Column_definition_redefine_stage1(this, dup_field, + file, schema); + } bool prepare_stage2(handler *handler, ulonglong table_flags); bool prepare_stage2_blob(handler *handler, ulonglong table_flags, uint field_flags); diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index a918da92be2..e0e9e2a42e7 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -48,7 +48,7 @@ handlerton *sql_sequence_hton; */ ha_sequence::ha_sequence(handlerton *hton, TABLE_SHARE *share) - :handler(hton, share), sequence_locked(0) + :handler(hton, share), write_locked(0) { sequence= share->sequence; DBUG_ASSERT(share->sequence); @@ -179,7 +179,7 @@ int ha_sequence::create(const char *name, TABLE *form, @retval != 0 Failure NOTES: - sequence_locked is set if we are called from SEQUENCE::next_value + write_locked is set if we are called from SEQUENCE::next_value In this case the mutex is already locked and we should not update the sequence with 'buf' as the sequence object is already up to date. */ @@ -187,6 +187,8 @@ int ha_sequence::create(const char *name, TABLE *form, int ha_sequence::write_row(uchar *buf) { int error; + sequence_definition tmp_seq; + bool sequence_locked; DBUG_ENTER("ha_sequence::write_row"); DBUG_ASSERT(table->record[0] == buf); @@ -199,23 +201,38 @@ int ha_sequence::write_row(uchar *buf) if (unlikely(sequence->initialized != SEQUENCE::SEQ_READY_TO_USE)) DBUG_RETURN(HA_ERR_WRONG_COMMAND); - /* - User tries to write a row - - Check that the new row is an accurate object - - Update the first row in the table - */ + sequence_locked= write_locked; + if (!write_locked) // If not from next_value() + { + /* + User tries to write a full row directly to the sequence table with + INSERT or LOAD DATA. + + - Get an exclusive lock for the table. This is needed to ensure that + we excute all full inserts (same as ALTER SEQUENCE) in same order + on master and slaves + - Check that we are only using one table. + This is to avoid deadlock problems when upgrading lock to exlusive. + - Check that the new row is an accurate SEQUENCE object + */ - sequence_definition tmp_seq; - tmp_seq.read_fields(table); - if (tmp_seq.check_and_adjust()) - DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA); + THD *thd= table->in_use; + if (thd->lock->table_count != 1) + DBUG_RETURN(ER_WRONG_INSERT_INTO_SEQUENCE); + if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, + thd->variables.lock_wait_timeout)) + DBUG_RETURN(ER_LOCK_WAIT_TIMEOUT); - /* - Lock sequence to ensure that no one can come in between - while sequence, table and binary log are updated. - */ - if (!sequence_locked) // If not from next_value() - sequence->lock(); + tmp_seq.read_fields(table); + if (tmp_seq.check_and_adjust(0)) + DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA); + + /* + Lock sequence to ensure that no one can come in between + while sequence, table and binary log are updated. + */ + sequence->write_lock(table); + } if (!(error= file->update_first_row(buf))) { @@ -230,40 +247,7 @@ int ha_sequence::write_row(uchar *buf) sequence->all_values_used= 0; if (!sequence_locked) - sequence->unlock(); - DBUG_RETURN(error); -} - - -int ha_sequence::update_row(const uchar *old_data, const uchar *new_data) -{ - int error; - sequence_definition tmp_seq; - DBUG_ENTER("ha_sequence::update_row"); - DBUG_ASSERT(new_data == table->record[0]); - - row_already_logged= 0; - - tmp_seq.read_fields(table); - if (tmp_seq.check_and_adjust()) - DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA); - - /* - Lock sequence to ensure that no one can come in between - while sequence, table and binary log is updated. - */ - sequence->lock(); - if (!(error= file->update_row(old_data, new_data))) - { - sequence->copy(&tmp_seq); - rows_changed++; - /* We have to do the logging while we hold the sequence mutex */ - error= binlog_log_row(table, old_data, new_data, - Update_rows_log_event::binlog_row_logging_function); - row_already_logged= 1; - } - sequence->all_values_used= 0; - sequence->unlock(); + sequence->write_unlock(table); DBUG_RETURN(error); } @@ -346,6 +330,9 @@ void ha_sequence::print_error(int error, myf errflag) case HA_ERR_WRONG_COMMAND: my_error(ER_ILLEGAL_HA, MYF(0), "SEQUENCE", sequence_db, sequence_name); DBUG_VOID_RETURN; + case ER_WRONG_INSERT_INTO_SEQUENCE: + my_error(error, MYF(0)); + DBUG_VOID_RETURN; } file->print_error(error, errflag); DBUG_VOID_RETURN; diff --git a/sql/ha_sequence.h b/sql/ha_sequence.h index f753d038114..fd9da05b591 100644 --- a/sql/ha_sequence.h +++ b/sql/ha_sequence.h @@ -60,6 +60,9 @@ private: SEQUENCE *sequence; /* From table_share->sequence */ public: + /* Set when handler is write locked */ + bool write_locked; + ha_sequence(handlerton *hton, TABLE_SHARE *share); ~ha_sequence(); @@ -69,9 +72,10 @@ public: HA_CREATE_INFO *create_info); handler *clone(const char *name, MEM_ROOT *mem_root); int write_row(uchar *buf); - int update_row(const uchar *old_data, const uchar *new_data); Table_flags table_flags() const; - /* One can't delete from sequence engine */ + /* One can't update or delete from sequence engine */ + int update_row(const uchar *old_data, const uchar *new_data) + { return HA_ERR_WRONG_COMMAND; } int delete_row(const uchar *buf) { return HA_ERR_WRONG_COMMAND; } /* One can't delete from sequence engine */ @@ -88,16 +92,36 @@ public: /* For ALTER ONLINE TABLE */ bool check_if_incompatible_data(HA_CREATE_INFO *create_info, uint table_changes); + void write_lock() { write_locked= 1;} + void unlock() { write_locked= 0; } + bool is_locked() { return write_locked; } /* Functions that are directly mapped to the underlying handler */ int rnd_init(bool scan) { return file->rnd_init(scan); } + /* + We need to have a lock here to protect engines like MyISAM from + simultaneous read and write. For sequence's this is not critical + as this function is used extremely seldom. + */ int rnd_next(uchar *buf) - { return file->rnd_next(buf); } + { + int error; + table->s->sequence->read_lock(table); + error= file->rnd_next(buf); + table->s->sequence->read_unlock(table); + return error; + } int rnd_end() { return file->rnd_end(); } int rnd_pos(uchar *buf, uchar *pos) - { return file->rnd_pos(buf, pos); } + { + int error; + table->s->sequence->read_lock(table); + error= file->rnd_pos(buf, pos); + table->s->sequence->read_unlock(table); + return error; + } void position(const uchar *record) { return file->position(record); } const char *table_type() const @@ -128,6 +152,8 @@ public: { return file->check_and_repair(thd); } bool is_crashed() const { return file->is_crashed(); } + void column_bitmaps_signal() + { return file->column_bitmaps_signal(); } /* New methods */ void register_original_handler(handler *file_arg) @@ -135,8 +161,5 @@ public: file= file_arg; init(); /* Update cached_table_flags */ } - - /* To inform handler that sequence is already locked by called */ - bool sequence_locked; }; #endif diff --git a/sql/handler.cc b/sql/handler.cc index a5832be30e1..9b66801b109 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6041,7 +6041,13 @@ int handler::update_first_row(uchar *new_data) { int end_error; if (!(error= ha_rnd_next(table->record[1]))) - error= update_row(table->record[1], new_data); + { + /* + We have to do the memcmp as otherwise we may get error 169 from InnoDB + */ + if (memcmp(table->record[0], table->record[1], table->s->reclength)) + error= update_row(table->record[1], new_data); + } end_error= ha_rnd_end(); if (!error) error= end_error; diff --git a/sql/innodb_priv.h b/sql/innodb_priv.h index ec85aa352f8..27aa9ac8645 100644 --- a/sql/innodb_priv.h +++ b/sql/innodb_priv.h @@ -28,6 +28,7 @@ void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); uint strconvert(CHARSET_INFO *from_cs, const char *from, uint from_length, CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors); + void sql_print_error(const char *format, ...); #define thd_binlog_pos(X, Y, Z) mysql_bin_log_commit_pos(X, Z, Y) diff --git a/sql/item.cc b/sql/item.cc index a9c7604d154..f4236eee013 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -311,6 +311,56 @@ bool Item::is_null_from_temporal() } +longlong Item::val_int_from_str(int *error) +{ + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff), &my_charset_bin), *res; + + /* + For a string result, we must first get the string and then convert it + to a longlong + */ + if (!(res= val_str(&tmp))) + { + *error= 0; + return 0; + } + Converter_strtoll10_with_warn cnv(NULL, Warn_filter_all(), + res->charset(), res->ptr(), res->length()); + *error= cnv.error(); + return cnv.result(); +} + + +longlong Item::val_int_signed_typecast_from_str() +{ + int error; + longlong value= val_int_from_str(&error); + if (!null_value && value < 0 && error == 0) + push_note_converted_to_negative_complement(current_thd); + return value; +} + + +longlong Item::val_int_unsigned_typecast_from_str() +{ + int error; + longlong value= val_int_from_str(&error); + if (!null_value && error < 0) + push_note_converted_to_positive_complement(current_thd); + return value; +} + + +longlong Item::val_int_unsigned_typecast_from_int() +{ + longlong value= val_int(); + if (!null_value && unsigned_flag == 0 && value < 0) + push_note_converted_to_positive_complement(current_thd); + return value; +} + + String *Item::val_string_from_date(String *str) { MYSQL_TIME ltime; @@ -428,6 +478,18 @@ longlong Item::val_int_from_decimal() return result; } + +longlong Item::val_int_unsigned_typecast_from_decimal() +{ + longlong result; + my_decimal tmp, *dec= val_decimal(&tmp); + if (null_value) + return 0; + my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &result); + return result; +} + + int Item::save_time_in_field(Field *field, bool no_conversions) { MYSQL_TIME ltime; @@ -997,6 +1059,75 @@ bool Item::check_cols(uint c) return 0; } + +bool Item::check_type_or_binary(const char *opname, + const Type_handler *expect) const +{ + const Type_handler *handler= type_handler(); + if (handler == expect || + (handler->is_general_purpose_string_type() && + collation.collation == &my_charset_bin)) + return false; + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + handler->name().ptr(), opname); + return true; +} + + +bool Item::check_type_general_purpose_string(const char *opname) const +{ + const Type_handler *handler= type_handler(); + if (handler->is_general_purpose_string_type()) + return false; + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + handler->name().ptr(), opname); + return true; +} + + +bool Item::check_type_traditional_scalar(const char *opname) const +{ + const Type_handler *handler= type_handler(); + if (handler->is_traditional_type() && handler->is_scalar_type()) + return false; + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + handler->name().ptr(), opname); + return true; +} + + +bool Item::check_type_can_return_int(const char *opname) const +{ + const Type_handler *handler= type_handler(); + if (handler->can_return_int()) + return false; + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + handler->name().ptr(), opname); + return true; +} + + +bool Item::check_type_can_return_real(const char *opname) const +{ + const Type_handler *handler= type_handler(); + if (handler->can_return_real()) + return false; + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + handler->name().ptr(), opname); + return true; +} + + +bool Item::check_type_scalar(const char *opname) const +{ + const Type_handler *handler= type_handler(); + if (handler->is_scalar_type()) + return false; + my_error(ER_OPERAND_COLUMNS, MYF(0), 1); + return true; +} + + void Item::set_name(THD *thd, const char *str, uint length, CHARSET_INFO *cs) { if (!length) @@ -1563,7 +1694,9 @@ Item_splocal::Item_splocal(THD *thd, const LEX_CSTRING *sp_var_name, bool Item_splocal::fix_fields(THD *thd, Item **ref) { - return fix_fields_from_item(thd, ref, thd->spcont->get_item(m_var_idx)); + Item *item= thd->spcont->get_item(m_var_idx); + set_handler(item->type_handler()); + return fix_fields_from_item(thd, ref, item); } @@ -3489,7 +3622,16 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg, uint pos_in_query_arg, uint len_in_query_arg): Item_basic_value(thd), Rewritable_query_parameter(pos_in_query_arg, len_in_query_arg), - Type_handler_hybrid_field_type(&type_handler_varchar), + /* + Set handler to type_handler_null. Its data type test methods such as: + - is_scalar_type() + - can_return_int() + - can_return_real(), + - is_general_purpose_string_type() + all return "true". This is needed to avoid any "illegal parameter type" + errors in Item::check_type_xxx() at PS prepare time. + */ + Type_handler_hybrid_field_type(&type_handler_null), state(NO_VALUE), /* Don't pretend to be a literal unless value for this item is set. */ item_type(PARAM_ITEM), @@ -6656,6 +6798,22 @@ void Item_hex_hybrid::print(String *str, enum_query_type query_type) } +uint Item_hex_hybrid::decimal_precision() const +{ + switch (max_length) {// HEX DEC + case 0: // ---- --- + case 1: return 3; // 0xFF 255 + case 2: return 5; // 0xFFFF 65535 + case 3: return 8; // 0xFFFFFF 16777215 + case 4: return 10; // 0xFFFFFFFF 4294967295 + case 5: return 13; // 0xFFFFFFFFFF 1099511627775 + case 6: return 15; // 0xFFFFFFFFFFFF 281474976710655 + case 7: return 17; // 0xFFFFFFFFFFFFFF 72057594037927935 + } + return 20; // 0xFFFFFFFFFFFFFFFF 18446744073709551615 +} + + void Item_hex_string::print(String *str, enum_query_type query_type) { str->append("X'"); diff --git a/sql/item.h b/sql/item.h index 2de5214c99e..76ce4aa935f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -337,19 +337,6 @@ typedef struct replace_equal_field_arg struct st_join_table *context_tab; } REPLACE_EQUAL_FIELD_ARG; - -class Load_data_out_param -{ -public: - Load_data_out_param() { } - virtual ~Load_data_out_param() { } - virtual void load_data_set_null_value(CHARSET_INFO *cs) = 0; - virtual void load_data_set_value(const char *str, uint length, - CHARSET_INFO *cs) = 0; - virtual void load_data_print(THD *thd, String *str) = 0; -}; - - class Settable_routine_parameter { public: @@ -567,6 +554,15 @@ protected: SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); /** + Create a field based on the exact data type handler. + */ + Field *create_table_field_from_handler(TABLE *table) + { + const Type_handler *h= type_handler(); + return h->make_and_init_table_field(&name, Record_addr(maybe_null), + *this, table); + } + /** Create a field based on field_type of argument. This is used to create a field for - IFNULL(x,something) @@ -582,7 +578,7 @@ protected: return h->make_and_init_table_field(&name, Record_addr(maybe_null), *this, table); } - Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length); + Field *create_tmp_field_int(TABLE *table, uint convert_int_length); void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd); @@ -880,14 +876,24 @@ public: to negative complements. Values of non-integer data types are adjusted to the SIGNED range. */ - virtual longlong val_int_signed_typecast(); + virtual longlong val_int_signed_typecast() + { + return cast_to_int_type_handler()->Item_val_int_signed_typecast(this); + } + longlong val_int_signed_typecast_from_str(); /** Get a value for CAST(x AS UNSIGNED). Negative signed integer values are converted to positive complements. Values of non-integer data types are adjusted to the UNSIGNED range. */ - virtual longlong val_int_unsigned_typecast(); + virtual longlong val_int_unsigned_typecast() + { + return cast_to_int_type_handler()->Item_val_int_unsigned_typecast(this); + } + longlong val_int_unsigned_typecast_from_decimal(); + longlong val_int_unsigned_typecast_from_int(); + longlong val_int_unsigned_typecast_from_str(); /* This is just a shortcut to avoid the cast. You should still use unsigned_flag to check the sign of the item. @@ -1200,6 +1206,10 @@ public: return const_item() ? type_handler()->Item_datetime_precision(this) : MY_MIN(decimals, TIME_SECOND_PART_DIGITS); } + virtual longlong val_int_min() const + { + return LONGLONG_MIN; + } /* Returns true if this is constant (during query execution, i.e. its value will not change until next fix_fields) and its value is known. @@ -1622,18 +1632,25 @@ public: } virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); + bool check_type_traditional_scalar(const char *opname) const; + bool check_type_scalar(const char *opname) const; + bool check_type_or_binary(const char *opname, const Type_handler *handler) const; + bool check_type_general_purpose_string(const char *opname) const; + bool check_type_can_return_int(const char *opname) const; + bool check_type_can_return_real(const char *opname) const; // It is not row => null inside is impossible virtual bool null_inside() { return 0; } // used in row subselects to get value of elements virtual void bring_value() {} + const Type_handler *type_handler_long_or_longlong() const + { + return Type_handler::type_handler_long_or_longlong(max_char_length()); + } + virtual Field *create_tmp_field(bool group, TABLE *table) { - /* - Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into - Field_long : make them Field_longlong. - */ - return create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS - 2); + return tmp_table_field_from_field_type(table); } virtual Item_field *field_for_view_update() { return 0; } @@ -1700,14 +1717,6 @@ public: delete this; } - virtual Load_data_out_param *get_load_data_out_param() { return 0; } - Load_data_out_param *get_load_data_out_param_or_error() - { - Load_data_out_param *res= get_load_data_out_param(); - if (!res) - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), full_name()); - return res; - } virtual Item_splocal *get_item_splocal() { return 0; } virtual Rewritable_query_parameter *get_rewritable_query_parameter() { return 0; } @@ -2269,6 +2278,18 @@ public: bool append_for_log(THD *thd, String *str); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } + + /* + Override the inherited create_field_for_create_select(), + because we want to preserve the exact data type for: + DECLARE a1 INT; + DECLARE a2 TYPE OF t1.a2; + CREATE TABLE t1 AS SELECT a1, a2; + The inherited implementation would create a column + based on result_type(), which is less exact. + */ + Field *create_field_for_create_select(TABLE *table) + { return tmp_table_field_from_field_type(table); } }; @@ -2300,23 +2321,6 @@ public: :Item_splocal(thd, sp_var_name, sp_var_idx, MYSQL_TYPE_NULL, pos_in_q, len_in_q) { } - bool fix_fields(THD *thd, Item **it) - { - if (Item_splocal::fix_fields(thd, it)) - return true; - set_handler(this_item()->type_handler()); - return false; - } - /* - Override the inherited create_field_for_create_select(), - because we want to preserve the exact data type for: - DECLARE a t1.a%TYPE; - CREATE TABLE t1 AS SELECT a; - The inherited implementation would create a column - based on result_type(), which is less exact. - */ - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } }; @@ -3231,17 +3235,13 @@ public: Item_int(THD *thd, const char *str_arg, uint length=64); enum Type type() const { return INT_ITEM; } const Type_handler *type_handler() const - { - // The same condition is repeated in Item::create_tmp_field() - if (max_length > MY_INT32_NUM_DECIMAL_DIGITS - 2) - return &type_handler_longlong; - return &type_handler_long; - } + { return type_handler_long_or_longlong(); } Field *create_tmp_field(bool group, TABLE *table) { return tmp_table_field_from_field_type(table); } Field *create_field_for_create_select(TABLE *table) { return tmp_table_field_from_field_type(table); } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } + longlong val_int_min() const { DBUG_ASSERT(fixed == 1); return value; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } my_decimal *val_decimal(my_decimal *); String *val_str(String*); @@ -3800,6 +3800,7 @@ public: Item_hex_hybrid(THD *thd): Item_hex_constant(thd) {} Item_hex_hybrid(THD *thd, const char *str, uint str_length): Item_hex_constant(thd, str, str_length) {} + uint decimal_precision() const; double val_real() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 717a65489f6..07b5f90bf69 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3738,30 +3738,6 @@ bool Predicant_to_list_comparator::make_unique_cmp_items(THD *thd, } -cmp_item* cmp_item::get_comparator(Item_result type, Item *warn_item, - CHARSET_INFO *cs) -{ - switch (type) { - case STRING_RESULT: - return new cmp_item_sort_string(cs); - case INT_RESULT: - return new cmp_item_int; - case REAL_RESULT: - return new cmp_item_real; - case ROW_RESULT: - return new cmp_item_row; - case DECIMAL_RESULT: - return new cmp_item_decimal; - case TIME_RESULT: - DBUG_ASSERT(warn_item); - return warn_item->field_type() == MYSQL_TYPE_TIME ? - (cmp_item *) new cmp_item_time() : - (cmp_item *) new cmp_item_datetime(); - } - return 0; // to satisfy compiler :) -} - - cmp_item* cmp_item_sort_string::make_same() { return new cmp_item_sort_string_in_static(cmp_charset); @@ -3814,7 +3790,8 @@ bool cmp_item_row::alloc_comparators(THD *thd, uint cols) void cmp_item_row::store_value(Item *item) { DBUG_ENTER("cmp_item_row::store_value"); - if (!alloc_comparators(current_thd, item->cols())) + THD *thd= current_thd; + if (!alloc_comparators(thd, item->cols())) { item->bring_value(); item->null_value= 0; @@ -3836,10 +3813,11 @@ void cmp_item_row::store_value(Item *item) - predicate0, value00, value01 - predicate1, value10, value11 */ - DBUG_ASSERT(item->element_index(i)->cmp_type() != TIME_RESULT); + Item *elem= item->element_index(i); + const Type_handler *handler= elem->type_handler(); + DBUG_ASSERT(elem->cmp_type() != TIME_RESULT); if (!(comparators[i]= - cmp_item::get_comparator(item->element_index(i)->result_type(), 0, - item->element_index(i)->collation.collation))) + handler->make_cmp_item(thd, elem->collation.collation))) break; // new failed } comparators[i]->store_value(item->element_index(i)); @@ -5519,6 +5497,7 @@ Item_func_regexp_instr::fix_length_and_dec() re.init(cmp_collation.collation, 0, 1); re.fix_owner(this, args[0], args[1]); + max_length= MY_INT32_NUM_DECIMAL_DIGITS; // See also Item_func_locate } @@ -6550,8 +6529,8 @@ longlong Item_equal::val_int() void Item_equal::fix_length_and_dec() { Item *item= get_first(NO_PARTICULAR_TAB, NULL); - eval_item= cmp_item::get_comparator(item->cmp_type(), item, - item->collation.collation); + const Type_handler *handler= item->type_handler(); + eval_item= handler->make_cmp_item(current_thd, item->collation.collation); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6d604b3a2fc..e21e074a7a3 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -204,6 +204,7 @@ public: Item_bool_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_bool_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { } Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const { return &type_handler_long; } bool is_bool_type() { return true; } virtual CHARSET_INFO *compare_collation() const { return NULL; } void fix_length_and_dec() { decimals=0; max_length=1; } @@ -480,12 +481,14 @@ class Item_bool_rowready_func2 :public Item_bool_func2_with_rev { protected: Arg_comparator cmp; + bool check_arguments() const + { + return check_argument_types_like_args0(); + } public: Item_bool_rowready_func2(THD *thd, Item *a, Item *b): Item_bool_func2_with_rev(thd, a, b), cmp(tmp_arg, tmp_arg + 1) - { - allowed_arg_cols= 0; // Fetch this value from first argument - } + { } void print(String *str, enum_query_type query_type) { Item_func::print_op(str, query_type); @@ -919,13 +922,13 @@ public: }; -class Item_func_strcmp :public Item_int_func +class Item_func_strcmp :public Item_long_func { String value1, value2; DTCollation cmp_collation; public: Item_func_strcmp(THD *thd, Item *a, Item *b): - Item_int_func(thd, a, b) {} + Item_long_func(thd, a, b) {} longlong val_int(); uint decimal_precision() const { return 1; } const char *func_name() const { return "strcmp"; } @@ -946,17 +949,19 @@ struct interval_range my_decimal dec; }; -class Item_func_interval :public Item_int_func +class Item_func_interval :public Item_long_func { Item_row *row; bool use_decimal_comparison; interval_range *intervals; -public: - Item_func_interval(THD *thd, Item_row *a): - Item_int_func(thd, a), row(a), intervals(0) + bool check_arguments() const { - allowed_arg_cols= 0; // Fetch this value from first argument + return check_argument_types_like_args0(); } +public: + Item_func_interval(THD *thd, Item_row *a): + Item_long_func(thd, a), row(a), intervals(0) + { } longlong val_int(); void fix_length_and_dec(); const char *func_name() const { return "interval"; } @@ -1466,8 +1471,6 @@ public: virtual int cmp(Item *item)= 0; // for optimized IN with row virtual int compare(cmp_item *item)= 0; - static cmp_item* get_comparator(Item_result type, Item * warn_item, - CHARSET_INFO *cs); virtual cmp_item *make_same()= 0; virtual void store_value_by_template(THD *thd, cmp_item *tmpl, Item *item) { @@ -2118,6 +2121,10 @@ class Item_func_in :public Item_func_opt_neg, return true; } bool prepare_predicant_and_values(THD *thd, uint *found_types); + bool check_arguments() const + { + return check_argument_types_like_args0(); + } protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value); @@ -2142,9 +2149,7 @@ public: Predicant_to_list_comparator(thd, arg_count - 1), array(0), have_null(0), arg_types_compatible(FALSE) - { - allowed_arg_cols= 0; // Fetch this value from first argument - } + { } longlong val_int(); bool fix_fields(THD *, Item **); void fix_length_and_dec(); @@ -2661,12 +2666,19 @@ public: }; -class Item_func_regexp_instr :public Item_int_func +/* + In the corner case REGEXP_INSTR could return (2^32 + 1), + which would not fit into Item_long_func range. + But string lengths are limited with max_allowed_packet, + which cannot be bigger than 1024*1024*1024. +*/ +class Item_func_regexp_instr :public Item_long_func { Regexp_processor_pcre re; DTCollation cmp_collation; public: - Item_func_regexp_instr(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) + Item_func_regexp_instr(THD *thd, Item *a, Item *b) + :Item_long_func(thd, a, b) {} void cleanup() { @@ -3130,6 +3142,61 @@ public: { return get_item_copy<Item_func_dyncol_exists>(thd, mem_root, this); } }; + +class Item_func_cursor_bool_attr: public Item_bool_func, public Cursor_ref +{ +public: + Item_func_cursor_bool_attr(THD *thd, const LEX_CSTRING *name, uint offset) + :Item_bool_func(thd), Cursor_ref(name, offset) + { } + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC); + } + void print(String *str, enum_query_type query_type) + { + Cursor_ref::print_func(str, func_name()); + } +}; + + +class Item_func_cursor_isopen: public Item_func_cursor_bool_attr +{ +public: + Item_func_cursor_isopen(THD *thd, const LEX_CSTRING *name, uint offset) + :Item_func_cursor_bool_attr(thd, name, offset) { } + const char *func_name() const { return "%ISOPEN"; } + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_func_cursor_isopen>(thd, mem_root, this); } +}; + + +class Item_func_cursor_found: public Item_func_cursor_bool_attr +{ +public: + Item_func_cursor_found(THD *thd, const LEX_CSTRING *name, uint offset) + :Item_func_cursor_bool_attr(thd, name, offset) { maybe_null= true; } + const char *func_name() const { return "%FOUND"; } + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_func_cursor_found>(thd, mem_root, this); } +}; + + +class Item_func_cursor_notfound: public Item_func_cursor_bool_attr +{ +public: + Item_func_cursor_notfound(THD *thd, const LEX_CSTRING *name, uint offset) + :Item_func_cursor_bool_attr(thd, name, offset) { maybe_null= true; } + const char *func_name() const { return "%NOTFOUND"; } + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_func_cursor_notfound>(thd, mem_root, this); } +}; + + + inline bool is_cond_or(Item *item) { if (item->type() != Item::COND_ITEM) diff --git a/sql/item_create.cc b/sql/item_create.cc index 60b39035d1b..8ab45e5dbe1 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -38,68 +38,6 @@ /* ============================================================================= - HELPER FUNCTIONS -============================================================================= -*/ - -static const char* item_name(Item *a, String *str) -{ - if (a->name.str) - return a->name.str; - str->length(0); - a->print(str, QT_ORDINARY); - return str->c_ptr_safe(); -} - - -static void wrong_precision_error(uint errcode, Item *a, - ulonglong number, uint maximum) -{ - char buff[1024]; - String buf(buff, sizeof(buff), system_charset_info); - - my_error(errcode, MYF(0), number, item_name(a, &buf), maximum); -} - - -/** - Get precision and scale for a declaration - - return - 0 ok - 1 error -*/ - -bool get_length_and_scale(ulonglong length, ulonglong decimals, - ulong *out_length, uint *out_decimals, - uint max_precision, uint max_scale, - Item *a) -{ - if (length > (ulonglong) max_precision) - { - wrong_precision_error(ER_TOO_BIG_PRECISION, a, length, max_precision); - return 1; - } - if (decimals > (ulonglong) max_scale) - { - wrong_precision_error(ER_TOO_BIG_SCALE, a, decimals, max_scale); - return 1; - } - - *out_decimals= (uint) decimals; - my_decimal_trim(&length, out_decimals); - *out_length= (ulong) length; - - if (*out_length < *out_decimals) - { - my_error(ER_M_BIGGER_THAN_D, MYF(0), ""); - return 1; - } - return 0; -} - -/* -============================================================================= LOCAL DECLARATIONS ============================================================================= */ @@ -5684,11 +5622,9 @@ Create_func_length Create_func_length::s_singleton; Item* Create_func_length::create_1_arg(THD *thd, Item *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); } @@ -6978,6 +6914,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("LCASE") }, BUILDER(Create_func_lcase)}, { { C_STRING_WITH_LEN("LEAST") }, BUILDER(Create_func_least)}, { { C_STRING_WITH_LEN("LENGTH") }, BUILDER(Create_func_length)}, + { { C_STRING_WITH_LEN("LENGTHB") }, BUILDER(Create_func_octet_length)}, #ifndef DBUG_OFF { { C_STRING_WITH_LEN("LIKE_RANGE_MIN") }, BUILDER(Create_func_like_range_min)}, { { C_STRING_WITH_LEN("LIKE_RANGE_MAX") }, BUILDER(Create_func_like_range_max)}, @@ -7271,114 +7208,6 @@ find_qualified_function_builder(THD *thd) } -Item * -create_func_cast(THD *thd, Item *a, Cast_target cast_type, - const char *c_len, const char *c_dec, - CHARSET_INFO *cs) -{ - Item *UNINIT_VAR(res); - ulonglong length= 0, decimals= 0; - int error; - - /* - We don't have to check for error here as sql_yacc.yy has guaranteed - that the values are in range of ulonglong - */ - if (c_len) - length= (ulonglong) my_strtoll10(c_len, NULL, &error); - if (c_dec) - decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error); - - switch (cast_type) { - case ITEM_CAST_BINARY: - res= new (thd->mem_root) Item_func_binary(thd, a); - break; - case ITEM_CAST_SIGNED_INT: - res= new (thd->mem_root) Item_func_signed(thd, a); - break; - case ITEM_CAST_UNSIGNED_INT: - res= new (thd->mem_root) Item_func_unsigned(thd, a); - break; - case ITEM_CAST_DATE: - res= new (thd->mem_root) Item_date_typecast(thd, a); - break; - case ITEM_CAST_TIME: - if (decimals > MAX_DATETIME_PRECISION) - { - wrong_precision_error(ER_TOO_BIG_PRECISION, a, decimals, - MAX_DATETIME_PRECISION); - return 0; - } - res= new (thd->mem_root) Item_time_typecast(thd, a, (uint) decimals); - break; - case ITEM_CAST_DATETIME: - if (decimals > MAX_DATETIME_PRECISION) - { - wrong_precision_error(ER_TOO_BIG_PRECISION, a, decimals, - MAX_DATETIME_PRECISION); - return 0; - } - res= new (thd->mem_root) Item_datetime_typecast(thd, a, (uint) decimals); - break; - case ITEM_CAST_DECIMAL: - { - ulong len; - uint dec; - if (get_length_and_scale(length, decimals, &len, &dec, - DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE, - a)) - return NULL; - res= new (thd->mem_root) Item_decimal_typecast(thd, a, len, dec); - break; - } - case ITEM_CAST_DOUBLE: - { - ulong len; - uint dec; - - if (!c_len) - { - length= DBL_DIG+7; - decimals= NOT_FIXED_DEC; - } - else if (get_length_and_scale(length, decimals, &len, &dec, - DECIMAL_MAX_PRECISION, NOT_FIXED_DEC-1, - a)) - return NULL; - res= new (thd->mem_root) Item_double_typecast(thd, a, (uint) length, - (uint) decimals); - break; - } - case ITEM_CAST_CHAR: - { - int len= -1; - CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection); - if (c_len) - { - if (length > MAX_FIELD_BLOBLENGTH) - { - char buff[1024]; - String buf(buff, sizeof(buff), system_charset_info); - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), item_name(a, &buf), - MAX_FIELD_BLOBLENGTH); - return NULL; - } - len= (int) length; - } - res= new (thd->mem_root) Item_char_typecast(thd, a, len, real_cs); - break; - } - default: - { - DBUG_ASSERT(0); - res= 0; - break; - } - } - return res; -} - - static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status) { @@ -7536,7 +7365,7 @@ Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums) Item *create_func_dyncol_get(THD *thd, Item *str, Item *num, - Cast_target cast_type, + const Type_handler *handler, const char *c_len, const char *c_dec, CHARSET_INFO *cs) { @@ -7544,5 +7373,6 @@ Item *create_func_dyncol_get(THD *thd, Item *str, Item *num, if (!(res= new (thd->mem_root) Item_dyncol_get(thd, str, num))) return res; // Return NULL - return create_func_cast(thd, res, cast_type, c_len, c_dec, cs); + return handler->create_typecast_item(thd, res, + Type_cast_attributes(c_len, c_dec, cs)); } diff --git a/sql/item_create.h b/sql/item_create.h index a2d985dd3e8..128a19a1c15 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -157,20 +157,6 @@ protected: #endif -/** - Builder for cast expressions. - @param thd The current thread - @param a The item to cast - @param cast_type the type casted into - @param len TODO - @param dec TODO - @param cs The character set -*/ -Item * -create_func_cast(THD *thd, Item *a, Cast_target cast_type, - const char *len, const char *dec, - CHARSET_INFO *cs); - Item *create_temporal_literal(THD *thd, const char *str, uint length, CHARSET_INFO *cs, @@ -194,7 +180,7 @@ Item *create_func_dyncol_add(THD *thd, Item *str, List<DYNCALL_CREATE_DEF> &list); Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums); Item *create_func_dyncol_get(THD *thd, Item *num, Item *str, - Cast_target cast_type, + const Type_handler *handler, const char *c_len, const char *c_dec, CHARSET_INFO *cs); Item *create_func_dyncol_json(THD *thd, Item *str); diff --git a/sql/item_func.cc b/sql/item_func.cc index 1f1523e738a..63a3937a12e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -151,15 +151,81 @@ void Item_func::sync_with_sum_func_and_with_field(List<Item> &list) } -bool Item_func::check_allowed_arg_cols(uint n) +bool Item_func::check_argument_types_like_args0() const { - if (allowed_arg_cols) - return args[n]->check_cols(allowed_arg_cols); + uint cols; + if (arg_count == 0) + return false; + cols= args[0]->cols(); + for (uint i= 1; i < arg_count; i++) + { + if (args[i]->check_cols(cols)) + return true; + } + return false; +} + + +bool Item_func::check_argument_types_or_binary(const Type_handler *handler, + uint start, uint end) const +{ + for (uint i= start; i < end ; i++) + { + DBUG_ASSERT(i < arg_count); + if (args[i]->check_type_or_binary(func_name(), handler)) + return true; + } + return false; +} - /* we have to fetch allowed_arg_cols from first argument */ - DBUG_ASSERT(n == 0); // it is first argument - allowed_arg_cols= args[n]->cols(); - DBUG_ASSERT(allowed_arg_cols); // Can't be 0 any more + +bool Item_func::check_argument_types_traditional_scalar(uint start, + uint end) const +{ + for (uint i= start; i < end ; i++) + { + DBUG_ASSERT(i < arg_count); + if (args[i]->check_type_traditional_scalar(func_name())) + return true; + } + return false; +} + + +bool Item_func::check_argument_types_can_return_int(uint start, + uint end) const +{ + for (uint i= start; i < end ; i++) + { + DBUG_ASSERT(i < arg_count); + if (args[i]->check_type_can_return_int(func_name())) + return true; + } + return false; +} + + +bool Item_func::check_argument_types_can_return_real(uint start, + uint end) const +{ + for (uint i= start; i < end ; i++) + { + DBUG_ASSERT(i < arg_count); + if (args[i]->check_type_can_return_real(func_name())) + return true; + } + return false; +} + + +bool Item_func::check_argument_types_scalar(uint start, uint end) const +{ + for (uint i= start; i < end; i++) + { + DBUG_ASSERT(i < arg_count); + if (args[i]->check_type_scalar(func_name())) + return true; + } return false; } @@ -236,9 +302,6 @@ Item_func::fix_fields(THD *thd, Item **ref) return TRUE; /* purecov: inspected */ item= *arg; - if (check_allowed_arg_cols(arg - args)) - return true; - if (item->maybe_null) maybe_null=1; @@ -249,6 +312,8 @@ Item_func::fix_fields(THD *thd, Item **ref) with_subselect|= item->has_subquery(); } } + if (check_arguments()) + return true; fix_length_and_dec(); if (thd->is_error()) // An error inside fix_length_and_dec occurred return TRUE; @@ -632,7 +697,7 @@ String *Item_int_func::val_str(String *str) void Item_func_connection_id::fix_length_and_dec() { - Item_int_func::fix_length_and_dec(); + Item_long_func::fix_length_and_dec(); max_length= 10; } @@ -879,41 +944,6 @@ void Item_func_signed::print(String *str, enum_query_type query_type) } -longlong Item::val_int_from_str(int *error) -{ - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff), &my_charset_bin), *res; - - /* - For a string result, we must first get the string and then convert it - to a longlong - */ - - if (!(res= val_str(&tmp))) - { - *error= 0; - return 0; - } - Converter_strtoll10_with_warn cnv(NULL, Warn_filter_all(), - res->charset(), res->ptr(), res->length()); - *error= cnv.error(); - return cnv.result(); -} - - -longlong Item::val_int_signed_typecast() -{ - if (cast_to_int_type_handler()->cmp_type() != STRING_RESULT) - return val_int(); - - int error; - longlong value= val_int_from_str(&error); - if (!null_value && value < 0 && error == 0) - push_note_converted_to_negative_complement(current_thd); - return value; -} - - void Item_func_unsigned::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); @@ -923,34 +953,6 @@ void Item_func_unsigned::print(String *str, enum_query_type query_type) } -longlong Item::val_int_unsigned_typecast() -{ - if (cast_to_int_type_handler()->cmp_type() == DECIMAL_RESULT) - { - longlong value; - my_decimal tmp, *dec= val_decimal(&tmp); - if (!null_value) - my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &value); - else - value= 0; - return value; - } - else if (cast_to_int_type_handler()->cmp_type() != STRING_RESULT) - { - longlong value= val_int(); - if (!null_value && unsigned_flag == 0 && value < 0) - push_note_converted_to_positive_complement(current_thd); - return value; - } - - int error; - longlong value= val_int_from_str(&error); - if (!null_value && error < 0) - push_note_converted_to_positive_complement(current_thd); - return value; -} - - String *Item_decimal_typecast::val_str(String *str) { my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); @@ -1804,8 +1806,8 @@ my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value) void Item_func_neg::fix_length_and_dec_int() { - set_handler(&type_handler_longlong); max_length= args[0]->max_length + 1; + set_handler(type_handler_long_or_longlong()); /* If this is in integer context keep the context as integer if possible @@ -1898,9 +1900,9 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) void Item_func_abs::fix_length_and_dec_int() { - set_handler(&type_handler_longlong); max_length= args[0]->max_length; unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); } @@ -2181,7 +2183,7 @@ void Item_func_int_val::fix_length_and_dec_int_or_decimal() else { unsigned_flag= args[0]->unsigned_flag; - set_handler(&type_handler_longlong); + set_handler(type_handler_long_or_longlong()); } } @@ -2372,9 +2374,9 @@ void Item_func_round::fix_arg_int() int length_can_increase= MY_TEST(!truncate && val1_is_negative); max_length= args[0]->max_length + length_can_increase; // Here we can keep INT_RESULT - set_handler(&type_handler_longlong); unsigned_flag= args[0]->unsigned_flag; decimals= 0; + set_handler(type_handler_long_or_longlong()); } else fix_length_and_dec_decimal(decimals_to_set); @@ -2773,6 +2775,14 @@ my_decimal *Item_func_min_max::val_decimal_native(my_decimal *dec) } +longlong Item_func_bit_length::val_int() +{ + DBUG_ASSERT(fixed == 1); + String *res= args[0]->val_str(&value); + return (null_value= !res) ? 0 : (longlong) res->length() * 8; +} + + longlong Item_func_octet_length::val_int() { DBUG_ASSERT(fixed == 1); @@ -2809,13 +2819,6 @@ longlong Item_func_coercibility::val_int() } -void Item_func_locate::fix_length_and_dec() -{ - max_length= MY_INT32_NUM_DECIMAL_DIGITS; - agg_arg_charsets_for_comparison(cmp_collation, args, 2); -} - - longlong Item_func_locate::val_int() { DBUG_ASSERT(fixed == 1); @@ -4414,8 +4417,27 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref) m_var_entry->set_charset(args[0]->collation.derivation == DERIVATION_NUMERIC ? default_charset() : args[0]->collation.collation); collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT); - set_handler_by_result_type(args[0]->result_type(), - max_length, collation.collation); + switch (args[0]->result_type()) { + case STRING_RESULT: + case TIME_RESULT: + set_handler(type_handler_long_blob. + type_handler_adjusted_to_max_octet_length(max_length, + collation.collation)); + break; + case REAL_RESULT: + set_handler(&type_handler_double); + break; + case INT_RESULT: + set_handler(Type_handler::type_handler_long_or_longlong(max_char_length())); + break; + case DECIMAL_RESULT: + set_handler(&type_handler_newdecimal); + break; + case ROW_RESULT: + DBUG_ASSERT(0); + set_handler(&type_handler_row); + break; + } if (thd->lex->current_select) { /* @@ -5321,7 +5343,6 @@ void Item_func_get_user_var::fix_length_and_dec() break; case STRING_RESULT: max_length= MAX_BLOB_WIDTH - 1; - set_handler(&type_handler_medium_blob); break; case DECIMAL_RESULT: fix_char_length(DECIMAL_MAX_STR_LENGTH); @@ -5406,15 +5427,14 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) } -void Item_user_var_as_out_param::load_data_set_null_value(CHARSET_INFO* cs) +void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs) { ::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, 0 /* unsigned_arg */); } -void Item_user_var_as_out_param::load_data_set_value(const char *str, - uint length, - CHARSET_INFO* cs) +void Item_user_var_as_out_param::set_value(const char *str, uint length, + CHARSET_INFO* cs) { ::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, 0 /* unsigned_arg */); @@ -5449,7 +5469,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) } -void Item_user_var_as_out_param::load_data_print(THD *thd, String *str) +void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) { str->append('@'); append_identifier(thd, str, name.str, name.length); @@ -6688,14 +6708,14 @@ void Item_func_last_value::fix_length_and_dec() } -void Item_func_cursor_int_attr::print(String *str, enum_query_type query_type) +void Cursor_ref::print_func(String *str, const char *func_name) { append_identifier(current_thd, str, m_cursor_name.str, m_cursor_name.length); - str->append(func_name()); + str->append(func_name); } -sp_cursor *Item_func_cursor_int_attr::get_open_cursor_or_error() +sp_cursor *Cursor_ref::get_open_cursor_or_error() { THD *thd= current_thd; sp_cursor *c= thd->spcont->get_cursor(m_cursor_offset); diff --git a/sql/item_func.h b/sql/item_func.h index 860a4fdcc7d..077f69fe0f5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -35,14 +35,19 @@ class Item_func :public Item_func_or_sum { void sync_with_sum_func_and_with_field(List<Item> &list); protected: - /* - Allowed numbers of columns in result (usually 1, which means scalar value) - 0 means get this number from first argument - */ - uint allowed_arg_cols; String *val_str_from_val_str_ascii(String *str, String *str2); - virtual bool check_allowed_arg_cols(uint argno); + virtual bool check_arguments() const + { + return check_argument_types_scalar(0, arg_count); + } + bool check_argument_types_like_args0() const; + bool check_argument_types_scalar(uint start, uint end) const; + bool check_argument_types_traditional_scalar(uint start, uint end) const; + bool check_argument_types_or_binary(const Type_handler *handler, + uint start, uint end) const; + bool check_argument_types_can_return_int(uint start, uint end) const; + bool check_argument_types_can_return_real(uint start, uint end) const; public: table_map not_null_tables_cache; @@ -65,30 +70,30 @@ public: NEG_FUNC, GSYSVAR_FUNC, DYNCOL_FUNC }; enum Type type() const { return FUNC_ITEM; } virtual enum Functype functype() const { return UNKNOWN_FUNC; } - Item_func(THD *thd): Item_func_or_sum(thd), allowed_arg_cols(1) + Item_func(THD *thd): Item_func_or_sum(thd) { with_sum_func= 0; with_field= 0; } - Item_func(THD *thd, Item *a): Item_func_or_sum(thd, a), allowed_arg_cols(1) + Item_func(THD *thd, Item *a): Item_func_or_sum(thd, a) { with_sum_func= a->with_sum_func; with_field= a->with_field; } Item_func(THD *thd, Item *a, Item *b): - Item_func_or_sum(thd, a, b), allowed_arg_cols(1) + Item_func_or_sum(thd, a, b) { with_sum_func= a->with_sum_func || b->with_sum_func; with_field= a->with_field || b->with_field; } Item_func(THD *thd, Item *a, Item *b, Item *c): - Item_func_or_sum(thd, a, b, c), allowed_arg_cols(1) + Item_func_or_sum(thd, a, b, c) { with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func; with_field= a->with_field || b->with_field || c->with_field; } Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d): - Item_func_or_sum(thd, a, b, c, d), allowed_arg_cols(1) + Item_func_or_sum(thd, a, b, c, d) { with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func || d->with_sum_func; @@ -96,7 +101,7 @@ public: c->with_field || d->with_field; } Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e): - Item_func_or_sum(thd, a, b, c, d, e), allowed_arg_cols(1) + Item_func_or_sum(thd, a, b, c, d, e) { with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func || d->with_sum_func || e->with_sum_func; @@ -104,14 +109,13 @@ public: c->with_field || d->with_field || e->with_field; } Item_func(THD *thd, List<Item> &list): - Item_func_or_sum(thd, list), allowed_arg_cols(1) + Item_func_or_sum(thd, list) { set_arguments(thd, list); } // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item): Item_func_or_sum(thd, item), - allowed_arg_cols(item->allowed_arg_cols), not_null_tables_cache(item->not_null_tables_cache) { } @@ -141,7 +145,6 @@ public: virtual Item *key_item() const { return args[0]; } void set_arguments(THD *thd, List<Item> &list) { - allowed_arg_cols= 1; Item_args::set_arguments(thd, list); sync_with_sum_func_and_with_field(list); list.empty(); // Fields are used @@ -169,11 +172,7 @@ public: void signal_divide_by_null(); friend class udf_handler; Field *create_field_for_create_select(TABLE *table) - { - return result_type() != STRING_RESULT ? - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : - tmp_table_field_from_field_type(table); - } + { return tmp_table_field_from_field_type(table); } Item *get_tmp_table_item(THD *thd); my_decimal *val_decimal(my_decimal *); @@ -624,10 +623,6 @@ public: Item_func_case_expression(THD *thd, List<Item> &list): Item_func_hybrid_field_type(thd, list) { } - Field *create_tmp_field(bool group, TABLE *table) - { return tmp_table_field_from_field_type(table); } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } }; @@ -700,13 +695,14 @@ class Item_num_op :public Item_func_numhybrid unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; result_precision(); decimals= 0; + set_handler(type_handler_long_or_longlong()); } void fix_length_and_dec_temporal() { set_handler(&type_handler_newdecimal); fix_length_and_dec_decimal(); if (decimals == 0) - set_handler(&type_handler_longlong); + set_handler(type_handler_long_or_longlong()); } bool need_parentheses_in_default() { return true; } }; @@ -715,6 +711,12 @@ class Item_num_op :public Item_func_numhybrid class Item_int_func :public Item_func { public: + /* + QQ: shouldn't 20 characters be enough: + Max unsigned = 18,446,744,073,709,551,615 = 20 digits, 20 characters + Max signed = 9,223,372,036,854,775,807 = 19 digits, 19 characters + Min signed = -9,223,372,036,854,775,808 = 19 digits, 20 characters + */ Item_int_func(THD *thd): Item_func(thd) { collation.set_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item *a): Item_func(thd, a) @@ -732,87 +734,82 @@ public: { collation.set_numeric(); } double val_real(); String *val_str(String*str); - const Type_handler *type_handler() const { return &type_handler_longlong; } + const Type_handler *type_handler() const= 0; void fix_length_and_dec() {} }; -class Item_func_cursor_int_attr: public Item_int_func +class Item_long_func: public Item_int_func { -protected: - LEX_CSTRING m_cursor_name; - uint m_cursor_offset; - class sp_cursor *get_open_cursor_or_error(); public: - Item_func_cursor_int_attr(THD *thd, const LEX_CSTRING *name, uint offset) - :Item_int_func(thd), m_cursor_name(*name), m_cursor_offset(offset) - { } - bool check_vcol_func_processor(void *arg) - { - return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC); - } - void print(String *str, enum_query_type query_type); + Item_long_func(THD *thd): Item_int_func(thd) { } + Item_long_func(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_long_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_long_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_long_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { } + Item_long_func(THD *thd, Item_long_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const { return &type_handler_long; } + void fix_length_and_dec() { max_length= 11; } }; -class Item_func_cursor_isopen: public Item_func_cursor_int_attr +class Item_longlong_func: public Item_int_func { public: - Item_func_cursor_isopen(THD *thd, const LEX_CSTRING *name, uint offset) - :Item_func_cursor_int_attr(thd, name, offset) { } - const char *func_name() const { return "%ISOPEN"; } - void fix_length_and_dec() { max_length= 1; } - longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_cursor_isopen>(thd, mem_root, this); } + Item_longlong_func(THD *thd): Item_int_func(thd) { } + Item_longlong_func(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_longlong_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_longlong_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_longlong_func(THD *thd, Item *a, Item *b, Item *c, Item *d): + Item_int_func(thd, a, b, c, d) {} + Item_longlong_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { } + Item_longlong_func(THD *thd, Item_longlong_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const { return &type_handler_longlong; } }; -class Item_func_cursor_found: public Item_func_cursor_int_attr +class Cursor_ref { -public: - Item_func_cursor_found(THD *thd, const LEX_CSTRING *name, uint offset) - :Item_func_cursor_int_attr(thd, name, offset) { } - const char *func_name() const { return "%FOUND"; } - void fix_length_and_dec() { max_length= 1; maybe_null= true; } - longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_cursor_found>(thd, mem_root, this); } +protected: + LEX_CSTRING m_cursor_name; + uint m_cursor_offset; + class sp_cursor *get_open_cursor_or_error(); + Cursor_ref(const LEX_CSTRING *name, uint offset) + :m_cursor_name(*name), m_cursor_offset(offset) + { } + void print_func(String *str, const char *func_name); }; -class Item_func_cursor_notfound: public Item_func_cursor_int_attr -{ -public: - Item_func_cursor_notfound(THD *thd, const LEX_CSTRING *name, uint offset) - :Item_func_cursor_int_attr(thd, name, offset) { } - const char *func_name() const { return "%NOTFOUND"; } - void fix_length_and_dec() { max_length= 1; maybe_null= true; } - longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_cursor_notfound>(thd, mem_root, this); } -}; - -class Item_func_cursor_rowcount: public Item_func_cursor_int_attr +class Item_func_cursor_rowcount: public Item_longlong_func, + public Cursor_ref { public: Item_func_cursor_rowcount(THD *thd, const LEX_CSTRING *name, uint offset) - :Item_func_cursor_int_attr(thd, name, offset) { } + :Item_longlong_func(thd), Cursor_ref(name, offset) { maybe_null= true; } const char *func_name() const { return "%ROWCOUNT"; } longlong val_int(); + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC); + } + void print(String *str, enum_query_type query_type) + { + return Cursor_ref::print_func(str, func_name()); + } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_cursor_rowcount>(thd, mem_root, this); } }; -class Item_func_connection_id :public Item_int_func +class Item_func_connection_id :public Item_long_func { longlong value; public: - Item_func_connection_id(THD *thd): Item_int_func(thd) {} + Item_func_connection_id(THD *thd): Item_long_func(thd) {} const char *func_name() const { return "connection_id"; } void fix_length_and_dec(); bool fix_fields(THD *thd, Item **ref); @@ -834,12 +831,18 @@ public: unsigned_flag= 0; } const char *func_name() const { return "cast_as_signed"; } + const Type_handler *type_handler() const + { return type_handler_long_or_longlong(); } longlong val_int() { longlong value= args[0]->val_int_signed_typecast(); null_value= args[0]->null_value; return value; } + void fix_length_and_dec_double() + { + fix_char_length(MAX_BIGINT_WIDTH); + } void fix_length_and_dec_generic() { uint32 char_length= MY_MIN(args[0]->max_char_length(), @@ -852,6 +855,19 @@ public: set_if_bigger(char_length, 1U + (unsigned_flag ? 0 : 1)); fix_char_length(char_length); } + void fix_length_and_dec_string() + { + /* + For strings, use decimal_int_part() instead of max_char_length(). + This is important for Item_hex_hybrid: + SELECT CAST(0x1FFFFFFFF AS SIGNED); + Length is 5, decimal_int_part() is 13. + */ + uint32 char_length= MY_MIN(args[0]->decimal_int_part(), + MY_INT64_NUM_DECIMAL_DIGITS); + set_if_bigger(char_length, 1U + (unsigned_flag ? 0 : 1)); + fix_char_length(char_length); + } void fix_length_and_dec() { args[0]->type_handler()->Item_func_signed_fix_length_and_dec(this); @@ -872,6 +888,12 @@ public: unsigned_flag= 1; } const char *func_name() const { return "cast_as_unsigned"; } + const Type_handler *type_handler() const + { + if (max_char_length() <= MY_INT32_NUM_DECIMAL_DIGITS - 1) + return &type_handler_long; + return &type_handler_longlong; + } longlong val_int() { longlong value= args[0]->val_int_unsigned_typecast(); @@ -882,6 +904,7 @@ public: { args[0]->type_handler()->Item_func_unsigned_fix_length_and_dec(this); } + uint decimal_precision() const { return max_length; } virtual void print(String *str, enum_query_type query_type); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_unsigned>(thd, mem_root, this); } @@ -1044,6 +1067,8 @@ public: longlong val_int(); const char *func_name() const { return "DIV"; } enum precedence precedence() const { return MUL_PRECEDENCE; } + const Type_handler *type_handler() const + { return type_handler_long_or_longlong(); } void fix_length_and_dec(); void print(String *str, enum_query_type query_type) { @@ -1084,6 +1109,7 @@ public: max_length= MY_MAX(args[0]->max_length, args[1]->max_length); decimals= 0; unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); } bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} @@ -1384,11 +1410,13 @@ private: }; -class Item_func_sign :public Item_int_func +class Item_func_sign :public Item_long_func { public: - Item_func_sign(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_sign(THD *thd, Item *a): Item_long_func(thd, a) {} const char *func_name() const { return "sign"; } + uint decimal_precision() const { return 1; } + void fix_length_and_dec() { fix_char_length(2); } longlong val_int(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_sign>(thd, mem_root, this); } @@ -1433,10 +1461,6 @@ public: Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg): Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg) {} - Field *create_tmp_field(bool group, TABLE *table) - { return tmp_table_field_from_field_type(table); } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } String *val_str_native(String *str); double val_real_native(); longlong val_int_native(); @@ -1552,11 +1576,11 @@ public: }; -class Item_func_octet_length :public Item_int_func +class Item_func_octet_length :public Item_long_func { String value; public: - Item_func_octet_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_octet_length(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "octet_length"; } void fix_length_and_dec() { max_length=10; } @@ -1564,22 +1588,26 @@ public: { return get_item_copy<Item_func_octet_length>(thd, mem_root, this); } }; -class Item_func_bit_length :public Item_func_octet_length +class Item_func_bit_length :public Item_longlong_func { + String value; public: - Item_func_bit_length(THD *thd, Item *a): Item_func_octet_length(thd, a) {} - longlong val_int() - { DBUG_ASSERT(fixed == 1); return Item_func_octet_length::val_int()*8; } + Item_func_bit_length(THD *thd, Item *a): Item_longlong_func(thd, a) {} + void fix_length_and_dec() + { + max_length= 11; // 0x100000000*8 = 34,359,738,368 + } + longlong val_int(); const char *func_name() const { return "bit_length"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_bit_length>(thd, mem_root, this); } }; -class Item_func_char_length :public Item_int_func +class Item_func_char_length :public Item_long_func { String value; public: - Item_func_char_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_char_length(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "char_length"; } void fix_length_and_dec() { max_length=10; } @@ -1587,10 +1615,10 @@ public: { return get_item_copy<Item_func_char_length>(thd, mem_root, this); } }; -class Item_func_coercibility :public Item_int_func +class Item_func_coercibility :public Item_long_func { public: - Item_func_coercibility(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_coercibility(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "coercibility"; } void fix_length_and_dec() { max_length=10; maybe_null= 0; } @@ -1602,29 +1630,42 @@ public: { return get_item_copy<Item_func_coercibility>(thd, mem_root, this); } }; -class Item_func_locate :public Item_int_func + +/* + In the corner case LOCATE could return (4,294,967,296 + 1), + which would not fit into Item_long_func range. + But string lengths are limited with max_allowed_packet, + which cannot be bigger than 1024*1024*1024. +*/ +class Item_func_locate :public Item_long_func { String value1,value2; DTCollation cmp_collation; public: - Item_func_locate(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} - Item_func_locate(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_func_locate(THD *thd, Item *a, Item *b) + :Item_long_func(thd, a, b) {} + Item_func_locate(THD *thd, Item *a, Item *b, Item *c) + :Item_long_func(thd, a, b, c) {} const char *func_name() const { return "locate"; } longlong val_int(); - void fix_length_and_dec(); + void fix_length_and_dec() + { + max_length= MY_INT32_NUM_DECIMAL_DIGITS; + agg_arg_charsets_for_comparison(cmp_collation, args, 2); + } virtual void print(String *str, enum_query_type query_type); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_locate>(thd, mem_root, this); } }; -class Item_func_field :public Item_int_func +class Item_func_field :public Item_long_func { String value,tmp; Item_result cmp_type; DTCollation cmp_collation; public: - Item_func_field(THD *thd, List<Item> &list): Item_int_func(thd, list) {} + Item_func_field(THD *thd, List<Item> &list): Item_long_func(thd, list) {} longlong val_int(); const char *func_name() const { return "field"; } void fix_length_and_dec(); @@ -1633,11 +1674,11 @@ public: }; -class Item_func_ascii :public Item_int_func +class Item_func_ascii :public Item_long_func { String value; public: - Item_func_ascii(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_ascii(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "ascii"; } void fix_length_and_dec() { max_length=3; } @@ -1645,18 +1686,19 @@ public: { return get_item_copy<Item_func_ascii>(thd, mem_root, this); } }; -class Item_func_ord :public Item_int_func +class Item_func_ord :public Item_long_func { String value; public: - Item_func_ord(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_ord(THD *thd, Item *a): Item_long_func(thd, a) {} + void fix_length_and_dec() { fix_char_length(7); } longlong val_int(); const char *func_name() const { return "ord"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_ord>(thd, mem_root, this); } }; -class Item_func_find_in_set :public Item_int_func +class Item_func_find_in_set :public Item_long_func { String value,value2; uint enum_value; @@ -1664,7 +1706,7 @@ class Item_func_find_in_set :public Item_int_func DTCollation cmp_collation; public: Item_func_find_in_set(THD *thd, Item *a, Item *b): - Item_int_func(thd, a, b), enum_value(0) {} + Item_long_func(thd, a, b), enum_value(0) {} longlong val_int(); const char *func_name() const { return "find_in_set"; } void fix_length_and_dec(); @@ -1674,11 +1716,11 @@ public: /* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */ -class Item_func_bit: public Item_int_func +class Item_func_bit: public Item_longlong_func { public: - Item_func_bit(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} - Item_func_bit(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_bit(THD *thd, Item *a, Item *b): Item_longlong_func(thd, a, b) {} + Item_func_bit(THD *thd, Item *a): Item_longlong_func(thd, a) {} void fix_length_and_dec() { unsigned_flag= 1; } virtual inline void print(String *str, enum_query_type query_type) @@ -1710,10 +1752,10 @@ public: { return get_item_copy<Item_func_bit_and>(thd, mem_root, this); } }; -class Item_func_bit_count :public Item_int_func +class Item_func_bit_count :public Item_long_func { public: - Item_func_bit_count(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_bit_count(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "bit_count"; } void fix_length_and_dec() { max_length=2; } @@ -1760,19 +1802,18 @@ public: }; -class Item_func_last_insert_id :public Item_int_func +class Item_func_last_insert_id :public Item_longlong_func { public: - Item_func_last_insert_id(THD *thd): Item_int_func(thd) {} - Item_func_last_insert_id(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_last_insert_id(THD *thd): Item_longlong_func(thd) {} + Item_func_last_insert_id(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int(); const char *func_name() const { return "last_insert_id"; } void fix_length_and_dec() { - unsigned_flag= TRUE; + unsigned_flag= true; if (arg_count) max_length= args[0]->max_length; - unsigned_flag=1; } bool fix_fields(THD *thd, Item **ref); bool check_vcol_func_processor(void *arg) @@ -1784,11 +1825,11 @@ public: }; -class Item_func_benchmark :public Item_int_func +class Item_func_benchmark :public Item_long_func { public: Item_func_benchmark(THD *thd, Item *count_expr, Item *expr): - Item_int_func(thd, count_expr, expr) + Item_long_func(thd, count_expr, expr) {} longlong val_int(); const char *func_name() const { return "benchmark"; } @@ -1806,10 +1847,11 @@ public: void item_func_sleep_init(void); void item_func_sleep_free(void); -class Item_func_sleep :public Item_int_func +class Item_func_sleep :public Item_long_func { public: - Item_func_sleep(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_sleep(THD *thd, Item *a): Item_long_func(thd, a) {} + void fix_length_and_dec() { fix_char_length(1); } bool const_item() const { return 0; } const char *func_name() const { return "sleep"; } table_map used_tables() const @@ -2045,6 +2087,7 @@ public: Item_int_func(thd) {} Item_func_udf_int(THD *thd, udf_func *udf_arg, List<Item> &list): Item_int_func(thd, list) {} + const Type_handler *type_handler() const { return &type_handler_longlong; } longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -2056,6 +2099,7 @@ public: Item_int_func(thd) {} Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list): Item_int_func(thd, list) {} + const Type_handler *type_handler() const { return &type_handler_longlong; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -2079,11 +2123,11 @@ public: void mysql_ull_cleanup(THD *thd); void mysql_ull_set_explicit_lock_duration(THD *thd); -class Item_func_get_lock :public Item_int_func +class Item_func_get_lock :public Item_long_func { String value; public: - Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_int_func(thd, a, b) {} + Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "get_lock"; } void fix_length_and_dec() { max_length=1; maybe_null=1;} @@ -2101,11 +2145,11 @@ class Item_func_get_lock :public Item_int_func { return get_item_copy<Item_func_get_lock>(thd, mem_root, this); } }; -class Item_func_release_lock :public Item_int_func +class Item_func_release_lock :public Item_long_func { String value; public: - Item_func_release_lock(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_release_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "release_lock"; } void fix_length_and_dec() { max_length= 1; maybe_null= 1;} @@ -2125,15 +2169,16 @@ public: /* replication functions */ -class Item_master_pos_wait :public Item_int_func +class Item_master_pos_wait :public Item_longlong_func { String value; public: - Item_master_pos_wait(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_master_pos_wait(THD *thd, Item *a, Item *b) + :Item_longlong_func(thd, a, b) {} Item_master_pos_wait(THD *thd, Item *a, Item *b, Item *c): - Item_int_func(thd, a, b, c) {} + Item_longlong_func(thd, a, b, c) {} Item_master_pos_wait(THD *thd, Item *a, Item *b, Item *c, Item *d): - Item_int_func(thd, a, b, c, d) {} + Item_longlong_func(thd, a, b, c, d) {} longlong val_int(); const char *func_name() const { return "master_pos_wait"; } void fix_length_and_dec() { max_length=21; maybe_null=1;} @@ -2146,15 +2191,17 @@ public: }; -class Item_master_gtid_wait :public Item_int_func +class Item_master_gtid_wait :public Item_long_func { String value; public: - Item_master_gtid_wait(THD *thd, Item *a): Item_int_func(thd, a) {} - Item_master_gtid_wait(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_master_gtid_wait(THD *thd, Item *a) + :Item_long_func(thd, a) {} + Item_master_gtid_wait(THD *thd, Item *a, Item *b) + :Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "master_gtid_wait"; } - void fix_length_and_dec() { max_length=10+1+10+1+20+1; maybe_null=0;} + void fix_length_and_dec() { max_length= 2; maybe_null=0;} bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); @@ -2185,6 +2232,10 @@ public: Item_func_user_var(THD *thd, Item_func_user_var *item) :Item_hybrid_func(thd, item), m_var_entry(item->m_var_entry), name(item->name) { } + Field *create_tmp_field(bool group, TABLE *table) + { return create_table_field_from_handler(table); } + Field *create_field_for_create_select(TABLE *table) + { return create_table_field_from_handler(table); } bool check_vcol_func_processor(void *arg); }; @@ -2287,14 +2338,6 @@ public: my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); - Field *create_field_for_create_select(TABLE *table) - { - return Type_handler_hybrid_field_type::cmp_type() == STRING_RESULT ? - type_handler_long_blob.make_and_init_table_field(&(Item::name), - Record_addr(maybe_null), - *this, table) : - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS); - } virtual void print(String *str, enum_query_type query_type); /* We must always return variables as strings to guard against selects of type @@ -2327,8 +2370,7 @@ public: in List<Item> and desire to place this code somewhere near other functions working with user variables. */ -class Item_user_var_as_out_param :public Item, - public Load_data_out_param +class Item_user_var_as_out_param :public Item { LEX_CSTRING name; user_var_entry *entry; @@ -2344,10 +2386,9 @@ public: my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); - Load_data_out_param *get_load_data_out_param() { return this; } - void load_data_print(THD *thd, String *str); - void load_data_set_null_value(CHARSET_INFO* cs); - void load_data_set_value(const char *str, uint length, CHARSET_INFO* cs); + void print_for_load(THD *thd, String *str); + void set_null_value(CHARSET_INFO* cs); + void set_value(const char *str, uint length, CHARSET_INFO* cs); const Type_handler *type_handler() const { return &type_handler_double; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_user_var_as_out_param>(thd, mem_root, this); } @@ -2506,11 +2547,11 @@ public: { return get_item_copy<Item_func_bit_xor>(thd, mem_root, this); } }; -class Item_func_is_free_lock :public Item_int_func +class Item_func_is_free_lock :public Item_long_func { String value; public: - Item_func_is_free_lock(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_is_free_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "is_free_lock"; } void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} @@ -2522,11 +2563,11 @@ public: { return get_item_copy<Item_func_is_free_lock>(thd, mem_root, this); } }; -class Item_func_is_used_lock :public Item_int_func +class Item_func_is_used_lock :public Item_long_func { String value; public: - Item_func_is_used_lock(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_is_used_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "is_used_lock"; } void fix_length_and_dec() { decimals=0; max_length=10; maybe_null=1;} @@ -2538,47 +2579,44 @@ public: { return get_item_copy<Item_func_is_used_lock>(thd, mem_root, this); } }; -/* For type casts */ - -enum Cast_target -{ - ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT, - ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR, - ITEM_CAST_DECIMAL, ITEM_CAST_DOUBLE -}; - struct Lex_cast_type_st: public Lex_length_and_dec_st { private: - Cast_target m_type; + const Type_handler *m_type_handler; public: - void set(Cast_target type, const char *length, const char *dec) + void set(const Type_handler *handler, const char *length, const char *dec) { - m_type= type; + m_type_handler= handler; Lex_length_and_dec_st::set(length, dec); } - void set(Cast_target 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_type_handler= handler; Lex_length_and_dec_st::operator=(length_and_dec); } - void set(Cast_target type, const char *length) + void set(const Type_handler *handler, const char *length) + { + set(handler, length, 0); + } + void set(const Type_handler *handler) { - set(type, length, 0); + set(handler, 0, 0); } - void set(Cast_target type) + const Type_handler *type_handler() const { return m_type_handler; } + Item *create_typecast_item(THD *thd, Item *item, CHARSET_INFO *cs= NULL) { - set(type, 0, 0); + return m_type_handler-> + create_typecast_item(thd, item, + Type_cast_attributes(length(), dec(), cs)); } - Cast_target type() const { return m_type; } }; -class Item_func_row_count :public Item_int_func +class Item_func_row_count :public Item_longlong_func { public: - Item_func_row_count(THD *thd): Item_int_func(thd) {} + Item_func_row_count(THD *thd): Item_longlong_func(thd) {} longlong val_int(); const char *func_name() const { return "row_count"; } void fix_length_and_dec() { decimals= 0; maybe_null=0; } @@ -2622,7 +2660,7 @@ protected: bool is_expensive_processor(void *arg) { return is_expensive(); } - bool check_allowed_arg_cols(uint n) + bool check_arguments() const { // sp_prepare_func_item() checks that the number of columns is correct return false; @@ -2734,10 +2772,10 @@ public: }; -class Item_func_found_rows :public Item_int_func +class Item_func_found_rows :public Item_longlong_func { public: - Item_func_found_rows(THD *thd): Item_int_func(thd) {} + Item_func_found_rows(THD *thd): Item_longlong_func(thd) {} longlong val_int(); const char *func_name() const { return "found_rows"; } void fix_length_and_dec() { decimals= 0; maybe_null=0; } @@ -2750,10 +2788,10 @@ public: }; -class Item_func_oracle_sql_rowcount :public Item_int_func +class Item_func_oracle_sql_rowcount :public Item_longlong_func { public: - Item_func_oracle_sql_rowcount(THD *thd): Item_int_func(thd) {} + Item_func_oracle_sql_rowcount(THD *thd): Item_longlong_func(thd) {} longlong val_int(); const char *func_name() const { return "SQL%ROWCOUNT"; } void print(String *str, enum_query_type query_type) @@ -2769,10 +2807,10 @@ public: }; -class Item_func_sqlcode: public Item_int_func +class Item_func_sqlcode: public Item_long_func { public: - Item_func_sqlcode(THD *thd): Item_int_func(thd) { } + Item_func_sqlcode(THD *thd): Item_long_func(thd) { } longlong val_int(); const char *func_name() const { return "SQLCODE"; } void print(String *str, enum_query_type query_type) @@ -2795,10 +2833,10 @@ public: void uuid_short_init(); -class Item_func_uuid_short :public Item_int_func +class Item_func_uuid_short :public Item_longlong_func { public: - Item_func_uuid_short(THD *thd): Item_int_func(thd) {} + Item_func_uuid_short(THD *thd): Item_longlong_func(thd) {} const char *func_name() const { return "uuid_short"; } longlong val_int(); void fix_length_and_dec() @@ -2841,13 +2879,13 @@ public: /* Implementation for sequences: NEXT VALUE FOR sequence and NEXTVAL() */ -class Item_func_nextval :public Item_int_func +class Item_func_nextval :public Item_longlong_func { protected: TABLE_LIST *table_list; public: Item_func_nextval(THD *thd, TABLE_LIST *table): - Item_int_func(thd), table_list(table) {} + Item_longlong_func(thd), table_list(table) {} longlong val_int(); const char *func_name() const { return "nextval"; } void fix_length_and_dec() diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index cf6d9bb1360..838f0b21d56 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -42,8 +42,160 @@ public: const Type_handler *type_handler() const { return &type_handler_geometry; } }; + +/* + Functions returning REAL measurements of a single GEOMETRY argument +*/ +class Item_real_func_args_geometry: public Item_real_func +{ +protected: + String value; + bool check_arguments() const + { + DBUG_ASSERT(arg_count == 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_real_func_args_geometry(THD *thd, Item *a) + :Item_real_func(thd, a) {} +}; + + +/* + Functions returning INT measurements of a single GEOMETRY argument +*/ +class Item_long_func_args_geometry: public Item_long_func +{ + bool check_arguments() const + { + DBUG_ASSERT(arg_count == 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +protected: + String value; +public: + Item_long_func_args_geometry(THD *thd, Item *a) + :Item_long_func(thd, a) {} +}; + + +/* + Functions returning BOOL measurements of a single GEOMETRY argument +*/ +class Item_bool_func_args_geometry: public Item_bool_func +{ +protected: + String value; + bool check_arguments() const + { + DBUG_ASSERT(arg_count == 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_bool_func_args_geometry(THD *thd, Item *a) + :Item_bool_func(thd, a) {} +}; + + +/* + Functions returning ASCII string measurements of a single GEOMETRY argument +*/ +class Item_str_ascii_func_args_geometry: public Item_str_ascii_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_str_ascii_func_args_geometry(THD *thd, Item *a) + :Item_str_ascii_func(thd, a) {} + Item_str_ascii_func_args_geometry(THD *thd, Item *a, Item *b) + :Item_str_ascii_func(thd, a, b) {} + Item_str_ascii_func_args_geometry(THD *thd, Item *a, Item *b, Item *c) + :Item_str_ascii_func(thd, a, b, c) {} +}; + + +/* + Functions returning binary string measurements of a single GEOMETRY argument +*/ +class Item_binary_func_args_geometry: public Item_str_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_binary_func_args_geometry(THD *thd, Item *a) + :Item_str_func(thd, a) {} +}; + + +/* + Functions returning GEOMETRY measurements of a single GEOEMETRY argument +*/ +class Item_geometry_func_args_geometry: public Item_geometry_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_geometry_func_args_geometry(THD *thd, Item *a) + :Item_geometry_func(thd, a) {} + Item_geometry_func_args_geometry(THD *thd, Item *a, Item *b) + :Item_geometry_func(thd, a, b) {} +}; + + +/* + Functions returning REAL result relationships between two GEOMETRY arguments +*/ +class Item_real_func_args_geometry_geometry: public Item_real_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 2); + return check_argument_types_or_binary(&type_handler_geometry, 0, 2); + } +public: + Item_real_func_args_geometry_geometry(THD *thd, Item *a, Item *b) + :Item_real_func(thd, a, b) {} +}; + + +/* + Functions returning BOOL result relationships between two GEOMETRY arguments +*/ +class Item_bool_func_args_geometry_geometry: public Item_bool_func +{ +protected: + String value; + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 2); + return check_argument_types_or_binary(&type_handler_geometry, 0, 2); + } +public: + Item_bool_func_args_geometry_geometry(THD *thd, Item *a, Item *b, Item *c) + :Item_bool_func(thd, a, b, c) {} +}; + + class Item_func_geometry_from_text: public Item_geometry_func { + bool check_arguments() const + { + return args[0]->check_type_general_purpose_string(func_name()) || + check_argument_types_can_return_int(1, MY_MIN(2, arg_count)); + } public: Item_func_geometry_from_text(THD *thd, Item *a): Item_geometry_func(thd, a) {} Item_func_geometry_from_text(THD *thd, Item *a, Item *srid): @@ -56,6 +208,11 @@ public: class Item_func_geometry_from_wkb: public Item_geometry_func { + bool check_arguments() const + { + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry) || + check_argument_types_can_return_int(1, MY_MIN(2, arg_count)); + } public: Item_func_geometry_from_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {} Item_func_geometry_from_wkb(THD *thd, Item *a, Item *srid): @@ -70,6 +227,12 @@ public: class Item_func_geometry_from_json: public Item_geometry_func { String tmp_js; + bool check_arguments() const + { + // TODO: check with Alexey, for better args[1] and args[2] type control + return args[0]->check_type_general_purpose_string(func_name()) || + check_argument_types_traditional_scalar(1, MY_MIN(3, arg_count)); + } public: Item_func_geometry_from_json(THD *thd, Item *js): Item_geometry_func(thd, js) {} Item_func_geometry_from_json(THD *thd, Item *js, Item *opt): @@ -83,10 +246,11 @@ public: }; -class Item_func_as_wkt: public Item_str_ascii_func +class Item_func_as_wkt: public Item_str_ascii_func_args_geometry { public: - Item_func_as_wkt(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_as_wkt(THD *thd, Item *a) + :Item_str_ascii_func_args_geometry(thd, a) {} const char *func_name() const { return "st_astext"; } String *val_str_ascii(String *); void fix_length_and_dec(); @@ -94,26 +258,41 @@ public: { return get_item_copy<Item_func_as_wkt>(thd, mem_root, this); } }; -class Item_func_as_wkb: public Item_geometry_func +class Item_func_as_wkb: public Item_binary_func_args_geometry { public: - Item_func_as_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {} + Item_func_as_wkb(THD *thd, Item *a) + :Item_binary_func_args_geometry(thd, a) {} const char *func_name() const { return "st_aswkb"; } String *val_str(String *); const Type_handler *type_handler() const { return &type_handler_long_blob; } + void fix_length_and_dec() + { + collation.set(&my_charset_bin); + decimals=0; + max_length= (uint32) UINT_MAX32; + maybe_null= 1; + } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_as_wkb>(thd, mem_root, this); } }; -class Item_func_as_geojson: public Item_str_ascii_func +class Item_func_as_geojson: public Item_str_ascii_func_args_geometry { + bool check_arguments() const + { + // TODO: check with Alexey, for better args[1] and args[2] type control + return Item_str_ascii_func_args_geometry::check_arguments() || + check_argument_types_traditional_scalar(1, MY_MIN(3, arg_count)); + } public: - Item_func_as_geojson(THD *thd, Item *js): Item_str_ascii_func(thd, js) {} - Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits): - Item_str_ascii_func(thd, js, max_dec_digits) {} - Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits, Item *opt): - Item_str_ascii_func(thd, js, max_dec_digits, opt) {} + Item_func_as_geojson(THD *thd, Item *js) + :Item_str_ascii_func_args_geometry(thd, js) {} + Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits) + :Item_str_ascii_func_args_geometry(thd, js, max_dec_digits) {} + Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits, Item *opt) + :Item_str_ascii_func_args_geometry(thd, js, max_dec_digits, opt) {} const char *func_name() const { return "st_asgeojson"; } void fix_length_and_dec(); String *val_str_ascii(String *); @@ -122,10 +301,11 @@ public: }; -class Item_func_geometry_type: public Item_str_ascii_func +class Item_func_geometry_type: public Item_str_ascii_func_args_geometry { public: - Item_func_geometry_type(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_geometry_type(THD *thd, Item *a) + :Item_str_ascii_func_args_geometry(thd, a) {} String *val_str_ascii(String *); const char *func_name() const { return "st_geometrytype"; } void fix_length_and_dec() @@ -140,7 +320,7 @@ public: // #define HEAVY_CONVEX_HULL -class Item_func_convexhull: public Item_geometry_func +class Item_func_convexhull: public Item_geometry_func_args_geometry { class ch_node: public Gcalc_dyn_list::Item { @@ -163,7 +343,8 @@ class Item_func_convexhull: public Item_geometry_func ch_node *new_ch_node() { return (ch_node *) res_heap.new_item(); } int add_node_to_line(ch_node **p_cur, int dir, const Gcalc_heap::Info *pi); public: - Item_func_convexhull(THD *thd, Item *a): Item_geometry_func(thd, a), + Item_func_convexhull(THD *thd, Item *a) + :Item_geometry_func_args_geometry(thd, a), res_heap(8192, sizeof(ch_node)) {} const char *func_name() const { return "st_convexhull"; } @@ -173,10 +354,11 @@ public: }; -class Item_func_centroid: public Item_geometry_func +class Item_func_centroid: public Item_geometry_func_args_geometry { public: - Item_func_centroid(THD *thd, Item *a): Item_geometry_func(thd, a) {} + Item_func_centroid(THD *thd, Item *a) + :Item_geometry_func_args_geometry(thd, a) {} const char *func_name() const { return "st_centroid"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; @@ -184,10 +366,11 @@ public: { return get_item_copy<Item_func_centroid>(thd, mem_root, this); } }; -class Item_func_envelope: public Item_geometry_func +class Item_func_envelope: public Item_geometry_func_args_geometry { public: - Item_func_envelope(THD *thd, Item *a): Item_geometry_func(thd, a) {} + Item_func_envelope(THD *thd, Item *a) + :Item_geometry_func_args_geometry(thd, a) {} const char *func_name() const { return "st_envelope"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; @@ -196,7 +379,7 @@ public: }; -class Item_func_boundary: public Item_geometry_func +class Item_func_boundary: public Item_geometry_func_args_geometry { class Transporter : public Gcalc_shape_transporter { @@ -221,7 +404,8 @@ class Item_func_boundary: public Item_geometry_func }; Gcalc_result_receiver res_receiver; public: - Item_func_boundary(THD *thd, Item *a): Item_geometry_func(thd, a) {} + Item_func_boundary(THD *thd, Item *a) + :Item_geometry_func_args_geometry(thd, a) {} const char *func_name() const { return "st_boundary"; } String *val_str(String *); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -231,6 +415,8 @@ public: class Item_func_point: public Item_geometry_func { + bool check_arguments() const + { return check_argument_types_can_return_real(0, 2); } public: Item_func_point(THD *thd, Item *a, Item *b): Item_geometry_func(thd, a, b) {} Item_func_point(THD *thd, Item *a, Item *b, Item *srid): @@ -242,12 +428,12 @@ public: { return get_item_copy<Item_func_point>(thd, mem_root, this); } }; -class Item_func_spatial_decomp: public Item_geometry_func +class Item_func_spatial_decomp: public Item_geometry_func_args_geometry { enum Functype decomp_func; public: Item_func_spatial_decomp(THD *thd, Item *a, Item_func::Functype ft): - Item_geometry_func(thd, a) { decomp_func = ft; } + Item_geometry_func_args_geometry(thd, a) { decomp_func = ft; } const char *func_name() const { switch (decomp_func) @@ -268,12 +454,19 @@ public: { return get_item_copy<Item_func_spatial_decomp>(thd, mem_root, this); } }; -class Item_func_spatial_decomp_n: public Item_geometry_func +class Item_func_spatial_decomp_n: public Item_geometry_func_args_geometry { enum Functype decomp_func_n; + bool check_arguments() const + { + return Item_geometry_func_args_geometry::check_arguments() || + args[1]->check_type_can_return_int(func_name()); + } public: - Item_func_spatial_decomp_n(THD *thd, Item *a, Item *b, Item_func::Functype ft): - Item_geometry_func(thd, a, b) { decomp_func_n = ft; } + Item_func_spatial_decomp_n(THD *thd, Item *a, Item *b, Item_func::Functype ft) + :Item_geometry_func_args_geometry(thd, a, b), + decomp_func_n(ft) + { } const char *func_name() const { switch (decomp_func_n) @@ -296,6 +489,10 @@ public: class Item_func_spatial_collection: public Item_geometry_func { + bool check_arguments() const + { + return check_argument_types_or_binary(&type_handler_geometry, 0, arg_count); + } String tmp_value; enum Geometry::wkbType coll_type; enum Geometry::wkbType item_type; @@ -342,6 +539,11 @@ protected: SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field, KEY_PART *key_part, Item_func::Functype type, Item *value); + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 2); + return check_argument_types_or_binary(&type_handler_geometry, 0, 2); + } public: Item_func_spatial_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel): Item_bool_func2_with_rev(thd, a, b), spatial_rel(sp_rel) @@ -392,15 +594,20 @@ public: }; -class Item_func_spatial_relate: public Item_bool_func +class Item_func_spatial_relate: public Item_bool_func_args_geometry_geometry { Gcalc_heap collector; Gcalc_scan_iterator scan_it; Gcalc_function func; String tmp_value1, tmp_value2, tmp_matrix; + bool check_arguments() const + { + return Item_bool_func_args_geometry_geometry::check_arguments() || + args[2]->check_type_general_purpose_string(func_name()); + } public: Item_func_spatial_relate(THD *thd, Item *a, Item *b, Item *matrix): - Item_bool_func(thd, a, b, matrix) + Item_bool_func_args_geometry_geometry(thd, a, b, matrix) { } longlong val_int(); const char *func_name() const { return "st_relate"; } @@ -416,6 +623,11 @@ public: class Item_func_spatial_operation: public Item_geometry_func { + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 2); + return check_argument_types_or_binary(&type_handler_geometry, 0, 2); + } public: Gcalc_function::op_type spatial_op; Gcalc_heap collector; @@ -441,8 +653,13 @@ public: }; -class Item_func_buffer: public Item_geometry_func +class Item_func_buffer: public Item_geometry_func_args_geometry { + bool check_arguments() const + { + return Item_geometry_func_args_geometry::check_arguments() || + args[1]->check_type_can_return_real(func_name()); + } protected: class Transporter : public Gcalc_operation_transporter { @@ -485,8 +702,8 @@ protected: String tmp_value; public: - Item_func_buffer(THD *thd, Item *obj, Item *distance): - Item_geometry_func(thd, obj, distance) {} + Item_func_buffer(THD *thd, Item *obj, Item *distance) + :Item_geometry_func_args_geometry(thd, obj, distance) {} const char *func_name() const { return "st_buffer"; } String *val_str(String *); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -494,10 +711,11 @@ public: }; -class Item_func_isempty: public Item_bool_func +class Item_func_isempty: public Item_bool_func_args_geometry { public: - Item_func_isempty(THD *thd, Item *a): Item_bool_func(thd, a) {} + Item_func_isempty(THD *thd, Item *a) + :Item_bool_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_isempty"; } void fix_length_and_dec() { maybe_null= 1; } @@ -506,14 +724,15 @@ public: { return get_item_copy<Item_func_isempty>(thd, mem_root, this); } }; -class Item_func_issimple: public Item_int_func +class Item_func_issimple: public Item_long_func_args_geometry { Gcalc_heap collector; Gcalc_function func; Gcalc_scan_iterator scan_it; String tmp; public: - Item_func_issimple(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_issimple(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_issimple"; } void fix_length_and_dec() { decimals=0; max_length=2; } @@ -522,10 +741,11 @@ public: { return get_item_copy<Item_func_issimple>(thd, mem_root, this); } }; -class Item_func_isclosed: public Item_int_func +class Item_func_isclosed: public Item_long_func_args_geometry { public: - Item_func_isclosed(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_isclosed(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_isclosed"; } void fix_length_and_dec() { decimals=0; max_length=2; } @@ -544,11 +764,11 @@ public: { return get_item_copy<Item_func_isring>(thd, mem_root, this); } }; -class Item_func_dimension: public Item_int_func +class Item_func_dimension: public Item_long_func_args_geometry { - String value; public: - Item_func_dimension(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_dimension(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_dimension"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } @@ -556,11 +776,11 @@ public: { return get_item_copy<Item_func_dimension>(thd, mem_root, this); } }; -class Item_func_x: public Item_real_func + +class Item_func_x: public Item_real_func_args_geometry { - String value; public: - Item_func_x(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_x(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_x"; } void fix_length_and_dec() @@ -573,11 +793,10 @@ public: }; -class Item_func_y: public Item_real_func +class Item_func_y: public Item_real_func_args_geometry { - String value; public: - Item_func_y(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_y(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_y"; } void fix_length_and_dec() @@ -590,11 +809,11 @@ public: }; -class Item_func_numgeometries: public Item_int_func +class Item_func_numgeometries: public Item_long_func_args_geometry { - String value; public: - Item_func_numgeometries(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_numgeometries(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_numgeometries"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } @@ -603,11 +822,11 @@ public: }; -class Item_func_numinteriorring: public Item_int_func +class Item_func_numinteriorring: public Item_long_func_args_geometry { - String value; public: - Item_func_numinteriorring(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_numinteriorring(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_numinteriorrings"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } @@ -616,11 +835,11 @@ public: }; -class Item_func_numpoints: public Item_int_func +class Item_func_numpoints: public Item_long_func_args_geometry { - String value; public: - Item_func_numpoints(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_numpoints(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_numpoints"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } @@ -629,11 +848,10 @@ public: }; -class Item_func_area: public Item_real_func +class Item_func_area: public Item_real_func_args_geometry { - String value; public: - Item_func_area(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_area(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_area"; } void fix_length_and_dec() @@ -646,11 +864,12 @@ public: }; -class Item_func_glength: public Item_real_func +class Item_func_glength: public Item_real_func_args_geometry { String value; public: - Item_func_glength(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_glength(THD *thd, Item *a) + :Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_length"; } void fix_length_and_dec() @@ -663,11 +882,11 @@ public: }; -class Item_func_srid: public Item_int_func +class Item_func_srid: public Item_long_func_args_geometry { - String value; public: - Item_func_srid(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_srid(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "srid"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } @@ -676,7 +895,7 @@ public: }; -class Item_func_distance: public Item_real_func +class Item_func_distance: public Item_real_func_args_geometry_geometry { String tmp_value1; String tmp_value2; @@ -684,7 +903,8 @@ class Item_func_distance: public Item_real_func Gcalc_function func; Gcalc_scan_iterator scan_it; public: - Item_func_distance(THD *thd, Item *a, Item *b): Item_real_func(thd, a, b) {} + Item_func_distance(THD *thd, Item *a, Item *b) + :Item_real_func_args_geometry_geometry(thd, a, b) {} double val_real(); const char *func_name() const { return "st_distance"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -692,14 +912,15 @@ public: }; -class Item_func_pointonsurface: public Item_geometry_func +class Item_func_pointonsurface: public Item_geometry_func_args_geometry { String tmp_value; Gcalc_heap collector; Gcalc_function func; Gcalc_scan_iterator scan_it; public: - Item_func_pointonsurface(THD *thd, Item *a): Item_geometry_func(thd, a) {} + Item_func_pointonsurface(THD *thd, Item *a) + :Item_geometry_func_args_geometry(thd, a) {} const char *func_name() const { return "st_pointonsurface"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; @@ -709,11 +930,12 @@ public: #ifndef DBUG_OFF -class Item_func_gis_debug: public Item_int_func +class Item_func_gis_debug: public Item_long_func { public: - Item_func_gis_debug(THD *thd, Item *a): Item_int_func(thd, a) + Item_func_gis_debug(THD *thd, Item *a): Item_long_func(thd, a) { null_value= false; } + void fix_length_and_dec() { fix_char_length(10); } const char *func_name() const { return "st_gis_debug"; } longlong val_int(); bool check_vcol_func_processor(void *arg) diff --git a/sql/item_inetfunc.h b/sql/item_inetfunc.h index 741b9f7d997..33586c29175 100644 --- a/sql/item_inetfunc.h +++ b/sql/item_inetfunc.h @@ -24,10 +24,10 @@ Item_func_inet_aton implements INET_ATON() SQL-function. *************************************************************************/ -class Item_func_inet_aton : public Item_int_func +class Item_func_inet_aton : public Item_longlong_func { public: - Item_func_inet_aton(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_inet_aton(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int(); const char *func_name() const { return "inet_aton"; } void fix_length_and_dec() diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index fd5b4a98e0e..9e9b26e2119 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -390,7 +390,7 @@ longlong Item_func_json_valid::val_int() void Item_func_json_exists::fix_length_and_dec() { - Item_int_func::fix_length_and_dec(); + Item_bool_func::fix_length_and_dec(); maybe_null= 1; path.set_constant_flag(args[1]->const_item()); } @@ -890,7 +890,7 @@ void Item_func_json_contains::fix_length_and_dec() maybe_null= 1; if (arg_count > 2) path.set_constant_flag(args[2]->const_item()); - Item_int_func::fix_length_and_dec(); + Item_bool_func::fix_length_and_dec(); } @@ -1135,7 +1135,7 @@ void Item_func_json_contains_path::fix_length_and_dec() ooa_parsed= FALSE; maybe_null= 1; mark_constant_paths(paths, args+2, arg_count-2); - Item_int_func::fix_length_and_dec(); + Item_bool_func::fix_length_and_dec(); } @@ -2050,6 +2050,7 @@ void Item_func_json_length::fix_length_and_dec() if (arg_count > 1) path.set_constant_flag(args[1]->const_item()); maybe_null= 1; + max_length= 10; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 394ed5f189a..4235bd3ea9f 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -40,27 +40,26 @@ public: }; -class Item_func_json_valid: public Item_int_func +class Item_func_json_valid: public Item_bool_func { protected: String tmp_value; public: - Item_func_json_valid(THD *thd, Item *json) : Item_int_func(thd, json) {} + Item_func_json_valid(THD *thd, Item *json) : Item_bool_func(thd, json) {} longlong val_int(); const char *func_name() const { return "json_valid"; } void fix_length_and_dec() { - Item_int_func::fix_length_and_dec(); + Item_bool_func::fix_length_and_dec(); maybe_null= 1; } - bool is_bool_type() { return true; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_json_valid>(thd, mem_root, this); } }; -class Item_func_json_exists: public Item_int_func +class Item_func_json_exists: public Item_bool_func { protected: json_path_with_flags path; @@ -68,9 +67,8 @@ protected: public: Item_func_json_exists(THD *thd, Item *js, Item *i_path): - Item_int_func(thd, js, i_path) {} + Item_bool_func(thd, js, i_path) {} const char *func_name() const { return "json_exists"; } - bool is_bool_type() { return true; } void fix_length_and_dec(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_json_exists>(thd, mem_root, this); } @@ -170,7 +168,7 @@ public: }; -class Item_func_json_contains: public Item_int_func +class Item_func_json_contains: public Item_bool_func { protected: String tmp_js; @@ -180,7 +178,7 @@ protected: String tmp_val, *val; public: Item_func_json_contains(THD *thd, List<Item> &list): - Item_int_func(thd, list) {} + Item_bool_func(thd, list) {} const char *func_name() const { return "json_contains"; } void fix_length_and_dec(); longlong val_int(); @@ -189,7 +187,7 @@ public: }; -class Item_func_json_contains_path: public Item_int_func +class Item_func_json_contains_path: public Item_bool_func { protected: String tmp_js; @@ -201,7 +199,7 @@ protected: public: Item_func_json_contains_path(THD *thd, List<Item> &list): - Item_int_func(thd, list), tmp_paths(0) {} + Item_bool_func(thd, list), tmp_paths(0) {} const char *func_name() const { return "json_contains_path"; } bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); @@ -290,7 +288,7 @@ public: }; -class Item_func_json_length: public Item_int_func +class Item_func_json_length: public Item_long_func { protected: json_path_with_flags path; @@ -298,7 +296,7 @@ protected: String tmp_path; public: Item_func_json_length(THD *thd, List<Item> &list): - Item_int_func(thd, list) {} + Item_long_func(thd, list) {} const char *func_name() const { return "json_length"; } void fix_length_and_dec(); longlong val_int(); @@ -307,13 +305,14 @@ public: }; -class Item_func_json_depth: public Item_int_func +class Item_func_json_depth: public Item_long_func { protected: String tmp_js; public: - Item_func_json_depth(THD *thd, Item *js): Item_int_func(thd, js) {} + Item_func_json_depth(THD *thd, Item *js): Item_long_func(thd, js) {} const char *func_name() const { return "json_depth"; } + void fix_length_and_dec() { max_length= 10; } longlong val_int(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_json_depth>(thd, mem_root, this); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ee5646bdfc5..4fcff4c0d2e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. + Copyright (c) 2000, 2017, Oracle and/or its affiliates. + Copyright (c) 2009, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4005,6 +4005,7 @@ String *Item_func_quote::val_str(String *str) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + ulong max_allowed_packet= current_thd->variables.max_allowed_packet; char *from, *to, *end, *start; String *arg= args[0]->val_str(str); uint arg_length, new_length; @@ -4023,11 +4024,14 @@ String *Item_func_quote::val_str(String *str) new_length= arg_length + 2; /* for beginning and ending ' signs */ for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++) new_length+= get_esc_bit(escmask, (uchar) *from); + if (new_length > max_allowed_packet) + goto toolong; } else { new_length= (arg_length * 2) + /* For string characters */ (2 * collation.collation->mbmaxlen); /* For quotes */ + set_if_smaller(new_length, max_allowed_packet); } if (tmp_value.alloc(new_length)) @@ -4043,7 +4047,7 @@ String *Item_func_quote::val_str(String *str) /* Put leading quote */ if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0) - goto null; + goto toolong; to+= mblen; for (start= (char*) arg->ptr(), end= start + arg_length; start < end; ) @@ -4063,17 +4067,17 @@ String *Item_func_quote::val_str(String *str) if (escape) { if ((mblen= cs->cset->wc_mb(cs, '\\', (uchar*) to, to_end)) <= 0) - goto null; + goto toolong; to+= mblen; } if ((mblen= cs->cset->wc_mb(cs, wc, (uchar*) to, to_end)) <= 0) - goto null; + goto toolong; to+= mblen; } /* Put trailing quote */ if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0) - goto null; + goto toolong; to+= mblen; new_length= to - tmp_value.ptr(); goto ret; @@ -4117,6 +4121,11 @@ ret: null_value= 0; return &tmp_value; +toolong: + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_ALLOWED_PACKET_OVERFLOWED, + ER_THD(current_thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED), + func_name(), max_allowed_packet); null: null_value= 1; return 0; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6e31d489574..6310d15b4e7 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1444,11 +1444,11 @@ public: { return get_item_copy<Item_func_weight_string>(thd, mem_root, this); } }; -class Item_func_crc32 :public Item_int_func +class Item_func_crc32 :public Item_long_func { String value; public: - Item_func_crc32(THD *thd, Item *a): Item_int_func(thd, a) + Item_func_crc32(THD *thd, Item *a): Item_long_func(thd, a) { unsigned_flag= 1; } const char *func_name() const { return "crc32"; } void fix_length_and_dec() { max_length=10; } @@ -1457,11 +1457,11 @@ public: { return get_item_copy<Item_func_crc32>(thd, mem_root, this); } }; -class Item_func_uncompressed_length : public Item_int_func +class Item_func_uncompressed_length : public Item_long_func { String value; public: - Item_func_uncompressed_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_uncompressed_length(THD *thd, Item *a): Item_long_func(thd, a) {} const char *func_name() const{return "uncompressed_length";} void fix_length_and_dec() { max_length=10; maybe_null= true; } longlong val_int(); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 5d9e2e7c0cd..cb60b646979 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -721,6 +721,13 @@ public: in_strategy= (SUBS_STRATEGY_CHOSEN | strategy); DBUG_VOID_RETURN; } + + bool walk(Item_processor processor, bool walk_subquery, void *arg) + { + return left_expr->walk(processor, walk_subquery, arg) || + Item_subselect::walk(processor, walk_subquery, arg); + } + bool exists2in_processor(void *opt_arg __attribute__((unused))) { return 0; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 77cd20e7386..9e26bd6f75e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1210,7 +1210,7 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table) field->flags&= ~NOT_NULL_FLAG; return field; } - return Item_sum::create_tmp_field(group, table); + return tmp_table_field_from_field_type(table); } diff --git a/sql/item_sum.h b/sql/item_sum.h index c1485738b11..65306ab6f48 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -508,10 +508,7 @@ public: } virtual void make_unique() { force_copy_fields= TRUE; } Item *get_tmp_table_item(THD *thd); - Field *create_tmp_field(bool group, TABLE *table) - { - return Item::create_tmp_field(group, table, MY_INT32_NUM_DECIMAL_DIGITS); - } + Field *create_tmp_field(bool group, TABLE *table); virtual bool collect_outer_ref_processor(void *param); bool init_sum_func_check(THD *thd); bool check_sum_func(THD *thd, Item **ref); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index ced4bf4b31e..4cdf7b63158 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -33,10 +33,10 @@ enum date_time_format_types bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval); -class Item_func_period_add :public Item_int_func +class Item_func_period_add :public Item_long_func { public: - Item_func_period_add(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_period_add(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "period_add"; } void fix_length_and_dec() @@ -48,10 +48,10 @@ public: }; -class Item_func_period_diff :public Item_int_func +class Item_func_period_diff :public Item_long_func { public: - Item_func_period_diff(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_period_diff(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "period_diff"; } void fix_length_and_dec() @@ -64,10 +64,10 @@ public: }; -class Item_func_to_days :public Item_int_func +class Item_func_to_days :public Item_long_func { public: - Item_func_to_days(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_to_days(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "to_days"; } void fix_length_and_dec() @@ -89,16 +89,16 @@ public: }; -class Item_func_to_seconds :public Item_int_func +class Item_func_to_seconds :public Item_longlong_func { public: - Item_func_to_seconds(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_to_seconds(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int(); const char *func_name() const { return "to_seconds"; } void fix_length_and_dec() { decimals=0; - max_length=6*MY_CHARSET_BIN_MB_MAXLEN; + fix_char_length(12); maybe_null= 1; } enum_monotonicity_info get_monotonicity_info() const; @@ -115,10 +115,10 @@ public: }; -class Item_func_dayofmonth :public Item_int_func +class Item_func_dayofmonth :public Item_long_func { public: - Item_func_dayofmonth(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_dayofmonth(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "dayofmonth"; } void fix_length_and_dec() @@ -155,7 +155,7 @@ public: return str; } const char *func_name() const { return "month"; } - const Type_handler *type_handler() const { return &type_handler_longlong; } + const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() { decimals= 0; @@ -196,10 +196,10 @@ public: }; -class Item_func_dayofyear :public Item_int_func +class Item_func_dayofyear :public Item_long_func { public: - Item_func_dayofyear(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_dayofyear(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "dayofyear"; } void fix_length_and_dec() @@ -219,10 +219,10 @@ public: }; -class Item_func_hour :public Item_int_func +class Item_func_hour :public Item_long_func { public: - Item_func_hour(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_hour(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "hour"; } void fix_length_and_dec() @@ -242,10 +242,10 @@ public: }; -class Item_func_minute :public Item_int_func +class Item_func_minute :public Item_long_func { public: - Item_func_minute(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_minute(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "minute"; } void fix_length_and_dec() @@ -265,10 +265,10 @@ public: }; -class Item_func_quarter :public Item_int_func +class Item_func_quarter :public Item_long_func { public: - Item_func_quarter(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_quarter(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "quarter"; } void fix_length_and_dec() @@ -288,10 +288,10 @@ public: }; -class Item_func_second :public Item_int_func +class Item_func_second :public Item_long_func { public: - Item_func_second(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_second(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "second"; } void fix_length_and_dec() @@ -311,11 +311,11 @@ public: }; -class Item_func_week :public Item_int_func +class Item_func_week :public Item_long_func { public: - Item_func_week(THD *thd, Item *a): Item_int_func(thd, a) {} - Item_func_week(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_week(THD *thd, Item *a): Item_long_func(thd, a) {} + Item_func_week(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "week"; } void fix_length_and_dec() @@ -338,10 +338,10 @@ public: { return get_item_copy<Item_func_week>(thd, mem_root, this); } }; -class Item_func_yearweek :public Item_int_func +class Item_func_yearweek :public Item_long_func { public: - Item_func_yearweek(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_yearweek(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "yearweek"; } void fix_length_and_dec() @@ -361,10 +361,10 @@ public: }; -class Item_func_year :public Item_int_func +class Item_func_year :public Item_long_func { public: - Item_func_year(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_year(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "year"; } enum_monotonicity_info get_monotonicity_info() const; @@ -404,7 +404,7 @@ public: { return (odbc_type ? "dayofweek" : "weekday"); } - const Type_handler *type_handler() const { return &type_handler_longlong; } + const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() { decimals= 0; @@ -449,7 +449,10 @@ public: decimals= dec; max_length=17 + (decimals ? decimals + 1 : 0); maybe_null= true; - set_handler_by_result_type(decimals ? DECIMAL_RESULT : INT_RESULT); + if (decimals) + set_handler(&type_handler_newdecimal); + else + set_handler(type_handler_long_or_longlong()); } double real_op() { DBUG_ASSERT(0); return 0; } String *str_op(String *str) { DBUG_ASSERT(0); return 0; } @@ -530,8 +533,6 @@ public: bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; } my_decimal *val_decimal(my_decimal *decimal_value) { return val_decimal_from_date(decimal_value); } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } }; @@ -1012,9 +1013,6 @@ class Item_extract :public Item_int_func } return true; } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_extract>(thd, mem_root, this); } }; @@ -1177,16 +1175,17 @@ public: }; -class Item_func_microsecond :public Item_int_func +class Item_func_microsecond :public Item_long_func { public: - Item_func_microsecond(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_microsecond(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "microsecond"; } void fix_length_and_dec() { decimals=0; maybe_null=1; + fix_char_length(6); } bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} @@ -1199,12 +1198,12 @@ public: }; -class Item_func_timestamp_diff :public Item_int_func +class Item_func_timestamp_diff :public Item_longlong_func { const interval_type int_type; public: Item_func_timestamp_diff(THD *thd, Item *a, Item *b, interval_type type_arg): - Item_int_func(thd, a, b), int_type(type_arg) {} + Item_longlong_func(thd, a, b), int_type(type_arg) {} const char *func_name() const { return "timestampdiff"; } longlong val_int(); void fix_length_and_dec() diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 90df6e27f6c..ba33d103d0c 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2005, 2013, Oracle and/or its affiliates. +/* Copyright (c) 2005, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -461,13 +462,13 @@ public: }; -class Item_func_xpath_position :public Item_int_func +class Item_func_xpath_position :public Item_long_func { String *pxml; String tmp_value; public: Item_func_xpath_position(THD *thd, Item *a, String *p): - Item_int_func(thd, a), pxml(p) {} + Item_long_func(thd, a), pxml(p) {} const char *func_name() const { return "xpath_position"; } void fix_length_and_dec() { max_length=10; } longlong val_int() @@ -482,13 +483,13 @@ public: }; -class Item_func_xpath_count :public Item_int_func +class Item_func_xpath_count :public Item_long_func { String *pxml; String tmp_value; public: Item_func_xpath_count(THD *thd, Item *a, String *p): - Item_int_func(thd, a), pxml(p) {} + Item_long_func(thd, a), pxml(p) {} const char *func_name() const { return "xpath_count"; } void fix_length_and_dec() { max_length=10; } longlong val_int() @@ -2836,9 +2837,9 @@ int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len) node.parent= data->parent; // Set parent for the new node to old parent data->parent= numnodes; // Remember current node as new parent - DBUG_ASSERT(data->level <= MAX_LEVEL); + DBUG_ASSERT(data->level < MAX_LEVEL); data->pos[data->level]= numnodes; - if (data->level < MAX_LEVEL) + if (data->level < MAX_LEVEL - 1) node.level= data->level++; else return MY_XML_ERROR; diff --git a/sql/log.cc b/sql/log.cc index 83e1724b195..0ffa4a5a82d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -9662,6 +9662,8 @@ binlog_background_thread(void *arg __attribute__((unused))) { THD_STAGE_INFO(thd, stage_binlog_processing_checkpoint_notify); DEBUG_SYNC(thd, "binlog_background_thread_before_mark_xid_done"); + /* Set the thread start time */ + thd->set_time(); /* Grab next pointer first, as mark_xid_done() may free the element. */ next= queue->next_in_queue; mysql_bin_log.mark_xid_done(queue->binlog_id, true); diff --git a/sql/log_event.cc b/sql/log_event.cc index 383972d1a54..3c062975041 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -12525,7 +12525,9 @@ Rows_log_event::write_row(rpl_group_info *rgi, TODO: Add safety measures against infinite looping. */ - while ((error= table->file->ha_write_row(table->record[0]))) + if (table->s->sequence) + error= update_sequence(); + else while ((error= table->file->ha_write_row(table->record[0]))) { if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT || @@ -12692,6 +12694,33 @@ Rows_log_event::write_row(rpl_group_info *rgi, DBUG_RETURN(error); } + +int Rows_log_event::update_sequence() +{ + TABLE *table= m_table; // pointer to event's table + + if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO)) + { + /* This event come from a setval function executed on the master. + Update the sequence next_number and round, like we do with setval() + */ + my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, + table->read_set); + longlong nextval= table->field[NEXT_FIELD_NO]->val_int(); + longlong round= table->field[ROUND_FIELD_NO]->val_int(); + dbug_tmp_restore_column_map(table->read_set, old_map); + + return table->s->sequence->set_value(table, nextval, round, 0); + } + + /* + Update all fields in table and update the active sequence, like with + ALTER SEQUENCE + */ + return table->file->ha_write_row(table->record[0]); +} + + #endif int diff --git a/sql/log_event.h b/sql/log_event.h index e79c88c28f1..3497ffab26d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -4606,6 +4606,7 @@ protected: int find_key(); // Find a best key to use in find_row() int find_row(rpl_group_info *); int write_row(rpl_group_info *, const bool); + int update_sequence(); // Unpack the current row into m_table->record[0], but with // a different columns bitmap. diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 381f4129321..9ba29ddb0f6 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -221,6 +221,8 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, rpl_group_info *rgi) /* A small test to verify that objects have consistent types */ DBUG_ASSERT(sizeof(ev_thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); + table->rpl_write_set= table->write_set; + error= do_before_row_operations(table); while (error == 0 && row_start < ev->m_rows_end) { diff --git a/sql/mdl.cc b/sql/mdl.cc index db7291d9b6a..87a0171a193 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -2328,12 +2328,6 @@ MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket, if (mdl_ticket->has_stronger_or_equal_type(new_type)) DBUG_RETURN(FALSE); - /* Only allow upgrades from SHARED_UPGRADABLE/NO_WRITE/NO_READ_WRITE/READ */ - DBUG_ASSERT(mdl_ticket->m_type == MDL_SHARED_UPGRADABLE || - mdl_ticket->m_type == MDL_SHARED_NO_WRITE || - mdl_ticket->m_type == MDL_SHARED_NO_READ_WRITE || - mdl_ticket->m_type == MDL_SHARED_READ); - mdl_xlock_request.init(&mdl_ticket->m_lock->key, new_type, MDL_TRANSACTION); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index eb39e542c41..d7c46071c38 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -330,9 +330,13 @@ static PSI_thread_key key_thread_handle_con_sockets; static PSI_thread_key key_thread_handle_shutdown; #endif /* __WIN__ */ -#if defined (HAVE_OPENSSL) && !defined(HAVE_YASSL) +#ifdef HAVE_OPENSSL +#include <ssl_compat.h> + +#ifdef HAVE_OPENSSL10 static PSI_rwlock_key key_rwlock_openssl; #endif +#endif #endif /* HAVE_PSI_INTERFACE */ #ifdef HAVE_NPTL @@ -623,6 +627,7 @@ Time_zone *default_tz; const char *mysql_real_data_home_ptr= mysql_real_data_home; char server_version[SERVER_VERSION_LENGTH], *server_version_ptr; +bool using_custom_server_version= false; char *mysqld_unix_port, *opt_mysql_tmpdir; ulong thread_handling; @@ -920,8 +925,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_PARTITION_LOCK_auto_inc; PSI_mutex_key key_RELAYLOG_LOCK_index; PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, - key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry, - key_LOCK_SEQUENCE; + key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; PSI_mutex_key key_LOCK_stats, key_LOCK_global_user_client_stats, key_LOCK_global_table_stats, @@ -1006,7 +1010,6 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_slave_state, "LOCK_slave_state", 0}, { &key_LOCK_start_thread, "LOCK_start_thread", PSI_FLAG_GLOBAL}, { &key_LOCK_binlog_state, "LOCK_binlog_state", 0}, - { &key_LOCK_SEQUENCE, "SQUENCE::LOCK_SEQUENCE", 0}, { &key_LOCK_rpl_thread, "LOCK_rpl_thread", 0}, { &key_LOCK_rpl_thread_pool, "LOCK_rpl_thread_pool", 0}, { &key_LOCK_parallel_entry, "LOCK_parallel_entry", 0} @@ -1014,17 +1017,20 @@ static PSI_mutex_info all_server_mutexes[]= PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, - key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock; + key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock, + key_LOCK_SEQUENCE; + static PSI_rwlock_info all_server_rwlocks[]= { -#if defined (HAVE_OPENSSL) && !defined(HAVE_YASSL) +#ifdef HAVE_OPENSSL10 { &key_rwlock_openssl, "CRYPTO_dynlock_value::lock", 0}, #endif { &key_rwlock_LOCK_grant, "LOCK_grant", PSI_FLAG_GLOBAL}, { &key_rwlock_LOCK_logger, "LOGGER::LOCK_logger", 0}, { &key_rwlock_LOCK_sys_init_connect, "LOCK_sys_init_connect", PSI_FLAG_GLOBAL}, { &key_rwlock_LOCK_sys_init_slave, "LOCK_sys_init_slave", PSI_FLAG_GLOBAL}, + { &key_LOCK_SEQUENCE, "LOCK_SEQUENCE", 0}, { &key_rwlock_LOCK_system_variables_hash, "LOCK_system_variables_hash", PSI_FLAG_GLOBAL}, { &key_rwlock_query_cache_query_lock, "Query_cache_query::lock", 0} }; @@ -1494,7 +1500,7 @@ scheduler_functions *thread_scheduler= &thread_scheduler_struct, #ifdef HAVE_OPENSSL #include <openssl/crypto.h> -#ifndef HAVE_YASSL +#ifdef HAVE_OPENSSL10 typedef struct CRYPTO_dynlock_value { mysql_rwlock_t lock; @@ -1505,7 +1511,7 @@ static openssl_lock_t *openssl_dynlock_create(const char *, int); static void openssl_dynlock_destroy(openssl_lock_t *, const char *, int); static void openssl_lock_function(int, int, const char *, int); static void openssl_lock(int, openssl_lock_t *, const char *, int); -#endif +#endif /* HAVE_OPENSSL10 */ char *des_key_file; #ifndef EMBEDDED_LIBRARY struct st_VioSSLFd *ssl_acceptor_fd; @@ -2325,11 +2331,11 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_global_index_stats); #ifdef HAVE_OPENSSL mysql_mutex_destroy(&LOCK_des_key_file); -#ifndef HAVE_YASSL +#ifdef HAVE_OPENSSL10 for (int i= 0; i < CRYPTO_num_locks(); ++i) mysql_rwlock_destroy(&openssl_stdlocks[i].lock); OPENSSL_free(openssl_stdlocks); -#endif /* HAVE_YASSL */ +#endif /* HAVE_OPENSSL10 */ #endif /* HAVE_OPENSSL */ #ifdef HAVE_REPLICATION mysql_mutex_destroy(&LOCK_rpl_status); @@ -3184,7 +3190,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) } -static void init_signals(void) +void init_signals(void) { if(opt_console) SetConsoleCtrlHandler(console_event_handler,TRUE); @@ -3315,7 +3321,7 @@ static size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize) #ifndef EMBEDDED_LIBRARY -static void init_signals(void) +void init_signals(void) { sigset_t set; struct sigaction sa; @@ -4140,6 +4146,14 @@ static int init_common_variables() return 1; } +#ifdef HAVE_OPENSSL + if (check_openssl_compatibility()) + { + sql_print_error("Incompatible OpenSSL version. Cannot continue..."); + return 1; + } +#endif + if (init_thread_environment() || mysql_init_variables()) return 1; @@ -4699,7 +4713,7 @@ static int init_thread_environment() #ifdef HAVE_OPENSSL mysql_mutex_init(key_LOCK_des_key_file, &LOCK_des_key_file, MY_MUTEX_INIT_FAST); -#ifndef HAVE_YASSL +#ifdef HAVE_OPENSSL10 openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(openssl_lock_t)); for (int i= 0; i < CRYPTO_num_locks(); ++i) @@ -4708,8 +4722,8 @@ static int init_thread_environment() CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy); CRYPTO_set_dynlock_lock_callback(openssl_lock); CRYPTO_set_locking_callback(openssl_lock_function); -#endif -#endif +#endif /* HAVE_OPENSSL10 */ +#endif /* HAVE_OPENSSL */ mysql_rwlock_init(key_rwlock_LOCK_sys_init_connect, &LOCK_sys_init_connect); mysql_rwlock_init(key_rwlock_LOCK_sys_init_slave, &LOCK_sys_init_slave); mysql_rwlock_init(key_rwlock_LOCK_grant, &LOCK_grant); @@ -4743,7 +4757,7 @@ static int init_thread_environment() } -#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) +#ifdef HAVE_OPENSSL10 static openssl_lock_t *openssl_dynlock_create(const char *file, int line) { openssl_lock_t *lock= new openssl_lock_t; @@ -4803,8 +4817,7 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, abort(); } } -#endif /* HAVE_OPENSSL */ - +#endif /* HAVE_OPENSSL10 */ static void init_ssl() { @@ -6302,7 +6315,7 @@ static void bootstrap(MYSQL_FILE *file) thd->variables.wsrep_on= 0; #endif thd->bootstrap=1; - my_net_init(&thd->net,(st_vio*) 0, (void*) 0, MYF(0)); + my_net_init(&thd->net,(st_vio*) 0, thd, MYF(0)); thd->max_client_packet_length= thd->net.max_packet; thd->security_ctx->master_access= ~(ulong)0; in_bootstrap= TRUE; @@ -8967,6 +8980,7 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument) { strmake(server_version, argument, sizeof(server_version) - 1); set_sys_var_value_origin(&server_version_ptr, sys_var::CONFIG); + using_custom_server_version= true; } #ifndef EMBEDDED_LIBRARY else diff --git a/sql/mysqld.h b/sql/mysqld.h index edda7e530fe..b7de4ecc324 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -301,7 +301,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, key_rpl_group_info_sleep_lock, key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, - key_LOCK_start_thread, key_LOCK_SEQUENCE, + key_LOCK_start_thread, key_LOCK_error_messages, key_LOCK_thread_count, key_PARTITION_LOCK_auto_inc; extern PSI_mutex_key key_RELAYLOG_LOCK_index; extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, @@ -314,8 +314,8 @@ extern PSI_mutex_key key_LOCK_gtid_waiting; extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, - key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock; - + key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock, + key_LOCK_SEQUENCE; #ifdef HAVE_MMAP extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool; #endif /* HAVE_MMAP */ @@ -545,6 +545,7 @@ extern const char *mysql_real_data_home_ptr; extern ulong thread_handling; extern "C" MYSQL_PLUGIN_IMPORT char server_version[SERVER_VERSION_LENGTH]; extern char *server_version_ptr; +extern bool using_custom_server_version; extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[]; extern char mysql_unpacked_real_data_home[]; extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables; @@ -781,20 +782,6 @@ inline void dec_thread_running() extern void set_server_version(char *buf, size_t size); -#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32) -extern "C" THD *_current_thd_noinline(); -#define _current_thd() _current_thd_noinline() -#else -/* - THR_THD is a key which will be used to set/get THD* for a thread, - using my_pthread_setspecific_ptr()/my_thread_getspecific_ptr(). -*/ -extern pthread_key(THD*, THR_THD); -inline THD *_current_thd(void) -{ - return my_pthread_getspecific_ptr(THD*,THR_THD); -} -#endif #define current_thd _current_thd() inline int set_current_thd(THD *thd) { diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 97a6421ec5c..1f282e6aee5 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7486,3 +7486,7 @@ ER_UNKNOWN_SEQUENCES 42S02 eng "Unknown SEQUENCE: '%-.300s'" ER_UNKNOWN_VIEW 42S02 eng "Unknown VIEW: '%-.300s'" +ER_WRONG_INSERT_INTO_SEQUENCE + eng "Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a squence object (like with mysqldump). If you want to change the SEQUENCE, use ALTER SEQUENCE instead." +ER_SP_STACK_TRACE + eng "At line %u in %s" diff --git a/sql/slave.cc b/sql/slave.cc index b2cbac44c1b..641bdae9e31 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -40,6 +40,7 @@ #include <my_dir.h> #include <sql_common.h> #include <errmsg.h> +#include <ssl_compat.h> #include <mysqld_error.h> #include <mysys_err.h> #include "rpl_handler.h" @@ -60,7 +61,6 @@ #include "debug_sync.h" #include "rpl_parallel.h" - #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") #define MAX_SLAVE_RETRY_PAUSE 5 @@ -4671,9 +4671,7 @@ err_during_init: DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); -#ifdef HAVE_OPENSSL ERR_remove_state(0); -#endif pthread_exit(0); return 0; // Avoid compiler warnings } @@ -5336,9 +5334,7 @@ err_during_init: DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); -#ifdef HAVE_OPENSSL ERR_remove_state(0); -#endif pthread_exit(0); return 0; // Avoid compiler warnings } diff --git a/sql/sp.cc b/sql/sp.cc index aa353f8d594..9c130eac52d 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2002, 2015, Oracle and/or its affiliates. - Copyright (c) 2009, 2015, MariaDB + Copyright (c) 2002, 2016, Oracle and/or its affiliates. + Copyright (c) 2009, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 80730a9b060..f8ad3c305a7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1178,11 +1178,10 @@ sp_head::execute(THD *thd, bool merge_da_on_success) /* Discard the initial part of executing routines. */ thd->profiling.discard_current_query(); #endif + sp_instr *i; DEBUG_SYNC(thd, "sp_head_execute_before_loop"); do { - sp_instr *i; - #if defined(ENABLED_PROFILING) /* Treat each "instr" of a routine as discrete unit that could be profiled. @@ -1342,6 +1341,13 @@ sp_head::execute(THD *thd, bool merge_da_on_success) da->opt_clear_warning_info(thd->query_id); da->copy_sql_conditions_from_wi(thd, &sp_wi); da->remove_marked_sql_conditions(); + if (i != NULL) + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_SP_STACK_TRACE, + ER_THD(thd, ER_SP_STACK_TRACE), + i->m_lineno, + m_qname.str != NULL ? m_qname.str : + "anonymous block"); } } @@ -2770,6 +2776,7 @@ int sp_head::add_instr(sp_instr *instr) entire stored procedure, as their life span is equal. */ instr->mem_root= &main_mem_root; + instr->m_lineno= m_thd->m_parser_state->m_lip.yylineno; return insert_dynamic(&m_instr, (uchar*)&instr); } diff --git a/sql/sp_head.h b/sql/sp_head.h index cfc2e6861d7..a96ef514429 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -888,6 +888,7 @@ public: uint marked; uint m_ip; ///< My index sp_pcontext *m_ctx; ///< My parse context + uint m_lineno; /// Should give each a name or type code for debugging purposes? sp_instr(uint ip, sp_pcontext *ctx) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d6cdb252a85..d63a2f2bc51 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7524,7 +7524,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); Security_context *sctx= thd->security_ctx; uint i; - ulong orig_want_access= want_access; + ulong original_want_access= want_access; bool locked= 0; GRANT_TABLE *grant_table; GRANT_TABLE *grant_table_role= NULL; @@ -7558,6 +7558,16 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *const t_ref= tl->correspondent_table ? tl->correspondent_table : tl; sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx; + ulong orig_want_access= original_want_access; + + if (t_ref->sequence) + { + /* We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed + */ + orig_want_access= ((t_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? + INSERT_ACL : SELECT_ACL); + } const ACL_internal_table_access *access= get_cached_table_access(&t_ref->grant.m_internal, @@ -12067,7 +12077,13 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio, data_len= SCRAMBLE_LENGTH; } - end= strxnmov(end, SERVER_VERSION_LENGTH, RPL_VERSION_HACK, server_version, NullS) + 1; + /* When server version is specified in config file, don't include + the replication hack prefix. */ + if (using_custom_server_version) + end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1; + else + end= strxnmov(end, SERVER_VERSION_LENGTH, RPL_VERSION_HACK, server_version, NullS) + 1; + int4store((uchar*) end, mpvio->auth_info.thd->thread_id); end+= 4; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5e13d7cd759..9fab6c5e252 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4262,8 +4262,9 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, else lock_type= TL_READ; - if (table_already_fk_prelocked(table_list, fk->foreign_db, - fk->foreign_table, lock_type)) + if (table_already_fk_prelocked(prelocking_ctx->query_tables, + fk->foreign_db, fk->foreign_table, + lock_type)) continue; TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5b8aa9ce2aa..076ae8b9923 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1985,7 +1985,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, if (!thd_table->needs_reopen()) { signalled|= mysql_lock_abort_for_thread(this, thd_table); - if (this && WSREP(this) && wsrep_thd_is_BF(this, FALSE)) + if (WSREP(this) && wsrep_thd_is_BF(this, FALSE)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) this->real_id); @@ -4106,16 +4106,12 @@ my_bool thd_net_is_killed() void thd_increment_bytes_received(void *thd, ulong length) { - if (unlikely(!thd)) // Called from federatedx - thd= current_thd; ((THD*) thd)->status_var.bytes_received+= length; } void thd_increment_net_big_packet_count(void *thd, ulong length) { - if (unlikely(!thd)) // Called from federatedx - thd= current_thd; ((THD*) thd)->status_var.net_big_packet_count+= length; } @@ -5922,8 +5918,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) table->table->file->ht) multi_write_engine= TRUE; if (table->table->s->non_determinstic_insert && - lex->sql_command != SQLCOM_CREATE_SEQUENCE && - lex->sql_command != SQLCOM_CREATE_TABLE) + !(sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE)) has_write_tables_with_unsafe_statements= true; trans= table->table->file->has_transactions(); diff --git a/sql/sql_const.h b/sql/sql_const.h index 2fa4b01b0a5..8d5f56de6b0 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -69,6 +69,7 @@ #define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1)) #define PSEUDO_TABLE_BITS (PARAM_TABLE_BIT | OUTER_REF_TABLE_BIT | \ RAND_TABLE_BIT) +#define CONNECT_STRING_MAXLEN 65535 /* stored in 2 bytes in .frm */ #define MAX_FIELDS 4096 /* Limit in the .frm file */ #define MAX_PARTITIONS 8192 diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1a5fac30536..132da4dff65 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -431,7 +431,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else tot_length+= field->field_length; } - else if (item->get_load_data_out_param()) + else if (item->type() == Item::STRING_ITEM) use_vars= 1; } if (use_blobs && !ex->line_term->length() && !field_term->length()) @@ -814,7 +814,11 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, if (item->real_type() == Item::FIELD_ITEM) append_identifier(thd, &query_str, item->name.str, item->name.length); else - item->get_load_data_out_param()->load_data_print(thd, &query_str); + { + /* Actually Item_user_var_as_out_param despite claiming STRING_ITEM. */ + DBUG_ASSERT(item->type() == Item::STRING_ITEM); + ((Item_user_var_as_out_param *)item)->print_for_load(thd, &query_str); + } } query_str.append(")"); } @@ -1057,8 +1061,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { uint length; uchar *pos; - Item *real_item; - Load_data_out_param *out_param; + Item_field *real_item; if (read_info.read_field()) break; @@ -1070,16 +1073,26 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, pos=read_info.row_start; length=(uint) (read_info.row_end-pos); - real_item= item->real_item(); + real_item= item->field_for_view_update(); if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) || (length == 1 && read_info.found_null)) { - if (real_item->type() == Item::FIELD_ITEM) + if (item->type() == Item::STRING_ITEM) + { + ((Item_user_var_as_out_param *)item)->set_null_value( + read_info.read_charset); + } + else if (!real_item) { - Field *field= ((Item_field *)real_item)->field; + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + DBUG_RETURN(1); + } + else + { + Field *field= real_item->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name.str, @@ -1101,17 +1114,24 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, } /* Do not auto-update this field. */ field->set_has_explicit_value(); - } - else if ((out_param= item->get_load_data_out_param_or_error())) - out_param->load_data_set_null_value(read_info.read_charset); - else - DBUG_RETURN(1); + } + continue; } - if (real_item->type() == Item::FIELD_ITEM) + if (item->type() == Item::STRING_ITEM) { - Field *field= ((Item_field *)real_item)->field; + ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, + read_info.read_charset); + } + else if (!real_item) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + DBUG_RETURN(1); + } + else + { + Field *field= real_item->field; field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker if (field == table->next_number_field) @@ -1119,11 +1139,6 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, field->store((char*) pos, length, read_info.read_charset); field->set_has_explicit_value(); } - else if ((out_param= item->get_load_data_out_param_or_error())) - out_param->load_data_set_value((const char *) pos, length, - read_info.read_charset); - else - DBUG_RETURN(1); } if (thd->is_error()) @@ -1143,11 +1158,20 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { - Load_data_out_param *out_param; - Item *real_item= item->real_item(); - if (real_item->type() == Item::FIELD_ITEM) + Item_field *real_item= item->field_for_view_update(); + if (item->type() == Item::STRING_ITEM) + { + ((Item_user_var_as_out_param *)item)->set_null_value( + read_info.read_charset); + } + else if (!real_item) { - Field *field= ((Item_field *)real_item)->field; + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + DBUG_RETURN(1); + } + else + { + Field *field= real_item->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name.str, @@ -1169,10 +1193,6 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), thd->get_stmt_da()->current_row_for_warning()); } - else if ((out_param= item->get_load_data_out_param_or_error())) - out_param->load_data_set_null_value(read_info.read_charset); - else - DBUG_RETURN(1); } } @@ -1268,7 +1288,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, while ((item= it++)) { - Load_data_out_param *out_param; /* If this line is to be skipped we don't want to fill field or var */ if (skip_lines) continue; @@ -1280,11 +1299,19 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, while(tag && strcmp(tag->field.c_ptr(), item->name.str) != 0) tag= xmlit++; + Item_field *real_item= item->field_for_view_update(); if (!tag) // found null { - if (item->type() == Item::FIELD_ITEM) + if (item->type() == Item::STRING_ITEM) + ((Item_user_var_as_out_param *) item)->set_null_value(cs); + else if (!real_item) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + DBUG_RETURN(1); + } + else { - Field *field= ((Item_field *) item)->field; + Field *field= real_item->field; field->reset(); field->set_null(); if (field == table->next_number_field) @@ -1300,15 +1327,21 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, /* Do not auto-update this field. */ field->set_has_explicit_value(); } - else if ((out_param= item->get_load_data_out_param_or_error())) - out_param->load_data_set_null_value(cs); - else - DBUG_RETURN(1); continue; } - if (item->type() == Item::FIELD_ITEM) + if (item->type() == Item::STRING_ITEM) + ((Item_user_var_as_out_param *) item)->set_value( + (char *) tag->value.ptr(), + tag->value.length(), cs); + else if (!real_item) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + DBUG_RETURN(1); + } + else { + Field *field= ((Item_field *)item)->field; field->set_notnull(); if (field == table->next_number_field) @@ -1316,12 +1349,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, field->store((char *) tag->value.ptr(), tag->value.length(), cs); field->set_has_explicit_value(); } - else if ((out_param= item->get_load_data_out_param_or_error())) - out_param->load_data_set_value((const char *) tag->value.ptr(), - tag->value.length(), cs); - else - DBUG_RETURN(1); - } if (read_info.error) @@ -1341,8 +1368,15 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, for ( ; item; item= it++) { - Load_data_out_param *out_param; - if (item->type() == Item::FIELD_ITEM) + Item_field *real_item= item->field_for_view_update(); + if (item->type() == Item::STRING_ITEM) + ((Item_user_var_as_out_param *)item)->set_null_value(cs); + else if (!real_item) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + DBUG_RETURN(1); + } + else { /* QQ: We probably should not throw warning for each field. @@ -1356,10 +1390,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), thd->get_stmt_da()->current_row_for_warning()); } - else if ((out_param= item->get_load_data_out_param_or_error())) - out_param->load_data_set_null_value(cs); - else - DBUG_RETURN(1); } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ff988659c7..174d57b99af 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2016, MariaDB Corporation +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. + Copyright (c) 2008, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -557,7 +557,7 @@ void init_update_queries(void) 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; + CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; 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; @@ -1456,7 +1456,7 @@ static my_bool deny_updates_if_read_only_option(THD *thd, if (lex->sql_command == SQLCOM_UPDATE_MULTI) DBUG_RETURN(FALSE); - /* Check if we created and dropped temporary tables */ + /* Check if we created or dropped temporary tables */ if ((sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE) && lex->tmp_table()) DBUG_RETURN(FALSE); @@ -5790,9 +5790,15 @@ end_with_restore_list: if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, &thd->sp_proc_cache, TRUE))) { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", - ErrConvDQName(lex->spname).ptr()); - goto error; + /* + sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error. + Send message ER_SP_DOES_NOT_EXIST only if procedure is not found in + cache. + */ + if (!sp_cache_lookup(&thd->sp_proc_cache, lex->spname)) + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", + ErrConvDQName(lex->spname).ptr()); + goto error; } else { @@ -7039,6 +7045,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, thd->security_ctx= sctx; + if (table_ref->sequence) + { + /* We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed + */ + want_access= ((table_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? + INSERT_ACL : SELECT_ACL); + } + if (check_access(thd, want_access, table_ref->get_db_name(), &table_ref->grant.privilege, &table_ref->grant.m_internal, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 6107595e930..e9fc0f62617 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1620,22 +1620,28 @@ int plugin_init(int *argc, char **argv, int flags) } } - /* First, we initialize only MyISAM - that should always succeed */ + /* + First, we initialize only MyISAM - that should almost always succeed + (almost always, because plugins can be loaded outside of the server, too). + */ plugin_ptr= plugin_find_internal(&MyISAM, MYSQL_STORAGE_ENGINE_PLUGIN); - DBUG_ASSERT(plugin_ptr); - DBUG_ASSERT(plugin_ptr->load_option == PLUGIN_FORCE); + DBUG_ASSERT(plugin_ptr || !mysql_mandatory_plugins[0]); + if (plugin_ptr) + { + DBUG_ASSERT(plugin_ptr->load_option == PLUGIN_FORCE); - if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, false)) - goto err_unlock; + if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, false)) + goto err_unlock; - /* - set the global default storage engine variable so that it will - not be null in any child thread. - */ - global_system_variables.table_plugin= - intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); - DBUG_ASSERT(plugin_ptr->ref_count == 1); + /* + set the global default storage engine variable so that it will + not be null in any child thread. + */ + global_system_variables.table_plugin = + intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); + DBUG_ASSERT(plugin_ptr->ref_count == 1); + } mysql_mutex_unlock(&LOCK_plugin); /* Register (not initialize!) all dynamic plugins */ diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 2e71fac50be..ea6aefa5993 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -133,7 +133,7 @@ static struct base64_service_st base64_handler= { my_base64_decode }; -static struct thd_error_context_service_st thd_error_conext_handler= { +static struct thd_error_context_service_st thd_error_context_handler= { thd_get_error_message, thd_get_error_number, thd_get_error_row, @@ -196,6 +196,24 @@ static struct encryption_scheme_service_st encryption_scheme_handler= encryption_scheme_decrypt }; +static struct my_crypt_service_st crypt_handler= +{ + my_aes_crypt_init, + my_aes_crypt_update, + my_aes_crypt_finish, + my_aes_crypt, + my_aes_get_size, + my_aes_ctx_size, + my_random_bytes +}; + +static struct my_print_error_service_st my_print_error_handler= +{ + my_error, + my_printf_error, + my_printv_error +}; + static struct st_service_ref list_of_services[]= { { "base64_service", VERSION_base64, &base64_handler }, @@ -203,19 +221,21 @@ static struct st_service_ref list_of_services[]= { "encryption_scheme_service", VERSION_encryption_scheme, &encryption_scheme_handler }, { "encryption_service", VERSION_encryption, &encryption_handler }, { "logger_service", VERSION_logger, &logger_service_handler }, + { "my_crypt_service", VERSION_my_crypt, &crypt_handler}, { "my_md5_service", VERSION_my_md5, &my_md5_handler}, + { "my_print_error_service", VERSION_my_print_error, &my_print_error_handler}, { "my_sha1_service", VERSION_my_sha1, &my_sha1_handler}, { "my_sha2_service", VERSION_my_sha2, &my_sha2_handler}, { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler }, { "progress_report_service", VERSION_progress_report, &progress_report_handler }, { "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler }, { "thd_autoinc_service", VERSION_thd_autoinc, &thd_autoinc_handler }, - { "thd_error_context_service", VERSION_thd_error_context, &thd_error_conext_handler }, + { "thd_error_context_service", VERSION_thd_error_context, &thd_error_context_handler }, { "thd_kill_statement_service", VERSION_kill_statement, &thd_kill_statement_handler }, { "thd_rnd_service", VERSION_thd_rnd, &thd_rnd_handler }, { "thd_specifics_service", VERSION_thd_specifics, &thd_specifics_handler }, { "thd_timezone_service", VERSION_thd_timezone, &thd_timezone_handler }, { "thd_wait_service", VERSION_thd_wait, &thd_wait_handler }, - { "wsrep_service", VERSION_wsrep, &wsrep_handler }, + { "wsrep_service", VERSION_wsrep, &wsrep_handler } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a71d5240593..c6613facde7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1138,6 +1138,8 @@ int JOIN::init_join_caches() } if (tab->cache && tab->cache->init(select_options & SELECT_DESCRIBE)) revise_cache_usage(tab); + else + tab->remove_redundant_bnl_scan_conds(); } return 0; } @@ -8785,8 +8787,6 @@ bool JOIN::get_best_combination() full_join=0; hash_join= FALSE; - used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read - fix_semijoin_strategies_for_picked_join_order(this); JOIN_TAB_RANGE *root_range; @@ -8850,7 +8850,6 @@ bool JOIN::get_best_combination() j->bush_root_tab= sjm_nest_root; form= table[tablenr]= j->table; - used_tables|= form->map; form->reginfo.join_tab=j; DBUG_PRINT("info",("type: %d", j->type)); if (j->type == JT_CONST) @@ -8877,9 +8876,6 @@ bool JOIN::get_best_combination() best_positions[tablenr].loosescan_picker.loosescan_key); j->index= best_positions[tablenr].loosescan_picker.loosescan_key; }*/ - - if (keyuse && create_ref_for_key(this, j, keyuse, TRUE, used_tables)) - DBUG_RETURN(TRUE); // Something went wrong if ((j->type == JT_REF || j->type == JT_EQ_REF) && is_hash_join_key_no(j->ref.key)) @@ -8905,6 +8901,23 @@ bool JOIN::get_best_combination() } root_range->end= j; + used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read + for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++) + { + if (j->bush_children) + j= j->bush_children->start; + + used_tables|= j->table->map; + if (j->type != JT_CONST && j->type != JT_SYSTEM) + { + if ((keyuse= best_positions[tablenr].key) && + create_ref_for_key(this, j, keyuse, TRUE, used_tables)) + DBUG_RETURN(TRUE); // Something went wrong + } + if (j->last_leaf_in_bush) + j= j->bush_root_tab; + } + top_join_tab_count= join_tab_ranges.head()->end - join_tab_ranges.head()->start; @@ -9757,7 +9770,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5 */ if (tab == join->join_tab + join->top_join_tab_count - 1) - current_map|= OUTER_REF_TABLE_BIT | RAND_TABLE_BIT; + current_map|= RAND_TABLE_BIT; used_tables|=current_map; if (tab->type == JT_REF && tab->quick && @@ -11168,8 +11181,8 @@ void JOIN_TAB::remove_redundant_bnl_scan_conds() select->cond is not processed separately. This method assumes it is always the same as select_cond. */ - DBUG_ASSERT(!select || !select->cond || - (select->cond == select_cond)); + if (select && select->cond != select_cond) + return; if (is_cond_and(select_cond)) { @@ -11479,7 +11492,6 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) /* purecov: end */ } - tab->remove_redundant_bnl_scan_conds(); DBUG_EXECUTE("where", char buff[256]; String str(buff,sizeof(buff),system_charset_info); @@ -15869,7 +15881,17 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, } -Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) +Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length) +{ + const Type_handler *h= &type_handler_long; + if (max_char_length() > convert_int_length) + h= &type_handler_longlong; + return h->make_and_init_table_field(&name, Record_addr(maybe_null), + *this, table); +} + + +Field *Item_sum::create_tmp_field(bool group, TABLE *table) { Field *UNINIT_VAR(new_field); MEM_ROOT *mem_root= table->in_use->mem_root; @@ -15878,23 +15900,10 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) case REAL_RESULT: { new_field= new (mem_root) - Field_double(max_length, maybe_null, &name, decimals, TRUE); + Field_double(max_char_length(), maybe_null, &name, decimals, TRUE); break; } case INT_RESULT: - { - /* - Select an integer type with the minimal fit precision. - convert_int_length is sign inclusive, don't consider the sign. - */ - if (max_char_length() > convert_int_length) - new_field= new (mem_root) - Field_longlong(max_char_length(), maybe_null, &name, unsigned_flag); - else - new_field= new (mem_root) - Field_long(max_char_length(), maybe_null, &name, unsigned_flag); - break; - } case TIME_RESULT: case DECIMAL_RESULT: case STRING_RESULT: @@ -15912,6 +15921,22 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) } +static void create_tmp_field_from_item_finalize(THD *thd, + Field *new_field, + Item *item, + Item ***copy_func, + bool modify_item) +{ + if (copy_func && + (item->is_result_field() || + (item->real_item()->is_result_field()))) + *((*copy_func)++) = item; // Save for copy_funcs + if (modify_item) + item->set_result_field(new_field); + if (item->type() == Item::NULL_ITEM) + new_field->is_created_from_null_item= TRUE; +} + /** Create field for temporary table using type of given item. @@ -15942,16 +15967,9 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, { Field *UNINIT_VAR(new_field); DBUG_ASSERT(thd == table->in_use); - new_field= item->Item::create_tmp_field(false, table); - - if (copy_func && - (item->is_result_field() || - (item->real_item()->is_result_field()))) - *((*copy_func)++) = item; // Save for copy_funcs - if (modify_item) - item->set_result_field(new_field); - if (item->type() == Item::NULL_ITEM) - new_field->is_created_from_null_item= TRUE; + if ((new_field= item->create_tmp_field(false, table))) + create_tmp_field_from_item_finalize(thd, new_field, item, + copy_func, modify_item); return new_field; } @@ -16026,6 +16044,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item::Type orig_type= type; Item *orig_item= 0; + DBUG_ASSERT(thd == table->in_use); + if (type != Item::FIELD_ITEM && item->real_item()->type() == Item::FIELD_ITEM) { @@ -16084,9 +16104,14 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, else if (table_cant_handle_bit_fields && field->field->type() == MYSQL_TYPE_BIT) { + const Type_handler *handler= item->type_handler_long_or_longlong(); *from_field= field->field; - result= create_tmp_field_from_item(thd, item, table, copy_func, - modify_item); + if ((result= + handler->make_and_init_table_field(&item->name, + Record_addr(item->maybe_null), + *item, table))) + create_tmp_field_from_item_finalize(thd, result, item, + copy_func, modify_item); if (result && modify_item) field->result_field= result; } diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index a6e7b073251..35792bfe72e 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -20,6 +20,7 @@ #include "sql_sequence.h" #include "ha_sequence.h" #include "sql_base.h" +#include "sql_table.h" // write_bin_log #include "transaction.h" #include "lock.h" #include "sql_acl.h" @@ -70,50 +71,60 @@ static Field_definition sequence_structure[]= Check whether sequence values are valid. Sets default values for fields that are not used, according to Oracle spec. - Note that reserved_until is not checked as it's ok that it's outside of - the range (to indicate that sequence us used up). - RETURN VALUES false valid true invalid */ -bool sequence_definition::check_and_adjust() +bool sequence_definition::check_and_adjust(bool set_reserved_until) { longlong max_increment; DBUG_ENTER("sequence_definition::check"); + if (!(real_increment= increment)) + real_increment= global_system_variables.auto_increment_increment; + /* If min_value is not set, set it to LONGLONG_MIN or 1, depending on increment */ if (!(used_fields & seq_field_used_min_value)) - min_value= increment < 0 ? LONGLONG_MIN+1 : 1; + min_value= real_increment < 0 ? LONGLONG_MIN+1 : 1; /* If min_value is not set, set it to LONGLONG_MAX or -1, depending on - increment + real_increment */ if (!(used_fields & seq_field_used_max_value)) - max_value= increment < 0 ? -1 : LONGLONG_MAX-1; + max_value= real_increment < 0 ? -1 : LONGLONG_MAX-1; if (!(used_fields & seq_field_used_start)) { - /* Use min_value or max_value for start depending on increment */ - start= increment < 0 ? max_value : min_value; + /* Use min_value or max_value for start depending on real_increment */ + start= real_increment < 0 ? max_value : min_value; } - /* To ensure that cache * increment will never overflow */ - max_increment= increment ? labs(increment) : MAX_AUTO_INCREMENT_VALUE; + if (set_reserved_until) + reserved_until= start; + + adjust_values(reserved_until); + + /* To ensure that cache * real_increment will never overflow */ + max_increment= (real_increment ? + labs(real_increment) : + MAX_AUTO_INCREMENT_VALUE); if (max_value >= start && max_value > min_value && start >= min_value && max_value != LONGLONG_MAX && min_value != LONGLONG_MIN && - cache < (LONGLONG_MAX - max_increment) / max_increment) + cache < (LONGLONG_MAX - max_increment) / max_increment && + ((real_increment > 0 && reserved_until >= min_value) || + (real_increment < 0 && reserved_until <= max_value))) DBUG_RETURN(FALSE); - DBUG_RETURN(TRUE); + + DBUG_RETURN(TRUE); // Error } @@ -331,14 +342,46 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list) SEQUENCE::SEQUENCE() :all_values_used(0), initialized(SEQ_UNINTIALIZED), table(0) { - mysql_mutex_init(key_LOCK_SEQUENCE, &mutex, MY_MUTEX_INIT_SLOW); + mysql_rwlock_init(key_LOCK_SEQUENCE, &mutex); } SEQUENCE::~SEQUENCE() { - mysql_mutex_destroy(&mutex); + mysql_rwlock_destroy(&mutex); } +/* + The following functions is to ensure that we when reserve new values + trough sequence object sequence we have only one writer at at time. + A sequence table can have many readers (trough normal SELECT's). + + We mark that we have a write lock in the table object so that + ha_sequence::ha_write() can check if we have a lock. If already locked, then + ha_write() knows that we are running a sequence operation. If not, then + ha_write() knows that it's an INSERT. +*/ + +void SEQUENCE::write_lock(TABLE *table) +{ + DBUG_ASSERT(((ha_sequence*) table->file)->is_locked() == 0); + mysql_rwlock_wrlock(&mutex); + ((ha_sequence*) table->file)->write_lock(); +} +void SEQUENCE::write_unlock(TABLE *table) +{ + ((ha_sequence*) table->file)->unlock(); + mysql_rwlock_unlock(&mutex); +} +void SEQUENCE::read_lock(TABLE *table) +{ + if (!((ha_sequence*) table->file)->is_locked()) + mysql_rwlock_rdlock(&mutex); +} +void SEQUENCE::read_unlock(TABLE *table) +{ + if (!((ha_sequence*) table->file)->is_locked()) + mysql_rwlock_unlock(&mutex); +} /** Read values from the sequence tables to table_share->sequence. @@ -355,7 +398,7 @@ int SEQUENCE::read_initial_values(TABLE *table_arg) if (likely(initialized != SEQ_UNINTIALIZED)) DBUG_RETURN(0); table= table_arg; - mysql_mutex_lock(&mutex); + write_lock(table); if (likely(initialized == SEQ_UNINTIALIZED)) { MYSQL_LOCK *lock; @@ -411,7 +454,7 @@ int SEQUENCE::read_initial_values(TABLE *table_arg) if (!has_active_transaction && !thd->transaction.stmt.is_empty()) trans_commit_stmt(thd); } - mysql_mutex_unlock(&mutex); + write_unlock(table); DBUG_RETURN(error); } @@ -425,7 +468,6 @@ int SEQUENCE::read_stored_values() int error; my_bitmap_map *save_read_set; DBUG_ENTER("SEQUENCE::read_stored_values"); - mysql_mutex_assert_owner(&mutex); save_read_set= tmp_use_all_columns(table, table->read_set); error= table->file->ha_read_first_row(table->record[0], MAX_KEY); @@ -448,7 +490,7 @@ int SEQUENCE::read_stored_values() Adjust values after reading a the stored state */ -void SEQUENCE::adjust_values(longlong next_value) +void sequence_definition::adjust_values(longlong next_value) { next_free_value= next_value; if (!(real_increment= increment)) @@ -531,25 +573,36 @@ int sequence_definition::write_initial_sequence(TABLE *table) Store current sequence values into the sequence table */ -int sequence_definition::write(TABLE *table) +int sequence_definition::write(TABLE *table, bool all_fields) { int error; - MY_BITMAP *save_rpl_write_set, *save_write_set; + MY_BITMAP *save_rpl_write_set, *save_write_set, *save_read_set; + DBUG_ASSERT(((ha_sequence*) table->file)->is_locked()); - /* Log a full insert (ok as table is small) */ save_rpl_write_set= table->rpl_write_set; + if (likely(!all_fields)) + { + /* Only write next_value and round to binary log */ + table->rpl_write_set= &table->def_rpl_write_set; + bitmap_clear_all(table->rpl_write_set); + bitmap_set_bit(table->rpl_write_set, NEXT_FIELD_NO); + bitmap_set_bit(table->rpl_write_set, ROUND_FIELD_NO); + } + else + table->rpl_write_set= &table->s->all_set; /* Update table */ save_write_set= table->write_set; - table->rpl_write_set= table->write_set= &table->s->all_set; + save_read_set= table->read_set; + table->read_set= table->write_set= &table->s->all_set; + table->file->column_bitmaps_signal(); 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->read_set= save_read_set; table->write_set= save_write_set; + table->file->column_bitmaps_signal(); return error; } @@ -590,7 +643,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) *error= 0; if (!second_round) - lock(); + write_lock(table); res_value= next_free_value; next_free_value= increment_value(next_free_value); @@ -598,7 +651,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) if ((real_increment > 0 && res_value < reserved_until) || (real_increment < 0 && res_value > reserved_until)) { - unlock(); + write_unlock(table); DBUG_RETURN(res_value); } @@ -612,7 +665,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) The cache value is checked on insert so the following can't overflow */ - add_to= cache ? real_increment * cache : 1; + add_to= cache ? real_increment * cache : real_increment; out_of_values= 0; if (real_increment > 0) @@ -651,17 +704,17 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) DBUG_RETURN(next_value(table, 1, error)); } - if ((*error= write(table))) + if ((*error= write(table, 0))) { reserved_until= org_reserved_until; next_free_value= res_value; } - unlock(); + write_unlock(table); DBUG_RETURN(res_value); err: - unlock(); + write_unlock(table); my_error(ER_SEQUENCE_RUN_OUT, MYF(0), table->s->db.str, table->s->table_name.str); *error= ER_SEQUENCE_RUN_OUT; @@ -720,7 +773,7 @@ bool SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round, ulonglong org_round= round; DBUG_ENTER("SEQUENCE::set_value"); - lock(); + write_lock(table); if (is_used) next_val= increment_value(next_val); @@ -751,7 +804,7 @@ bool SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round, needs_to_be_stored) { reserved_until= next_free_value; - if (write(table)) + if (write(table, 0)) { reserved_until= org_reserved_until; next_free_value= org_next_free_value; @@ -762,7 +815,7 @@ bool SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round, error= 0; end: - unlock(); + write_unlock(table); DBUG_RETURN(error); } @@ -842,7 +895,7 @@ bool Sql_cmd_alter_sequence::execute(THD *thd) /* Let check_and_adjust think all fields are used */ new_seq->used_fields= ~0; - if (new_seq->check_and_adjust()) + if (new_seq->check_and_adjust(0)) { my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), first_table->db, @@ -851,17 +904,24 @@ bool Sql_cmd_alter_sequence::execute(THD *thd) goto end; } - if (!(error= new_seq->write(table))) + table->s->sequence->write_lock(table); + if (!(error= new_seq->write(table, 1))) { /* Store the sequence values in table share */ table->s->sequence->copy(new_seq); } - trans_commit_stmt(thd); - trans_commit_implicit(thd); + else + table->file->print_error(error, MYF(0)); + table->s->sequence->write_unlock(table); + if (trans_commit_stmt(thd)) + error= 1; + if (trans_commit_implicit(thd)) + error= 1; + if (!error) + error= write_bin_log(thd, 1, thd->query(), thd->query_length()); 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 ffe5ded4cff..b560d03ca52 100644 --- a/sql/sql_sequence.h +++ b/sql/sql_sequence.h @@ -26,6 +26,11 @@ #define seq_field_used_restart 64 #define seq_field_used_restart_value 128 +/* Field position in sequence table for some fields we refer to directly */ +#define NEXT_FIELD_NO 0 +#define MIN_VALUE_FIELD_NO 1 +#define ROUND_FIELD_NO 7 + /** sequence_definition is used when defining a sequence as part of create */ @@ -35,7 +40,7 @@ class sequence_definition :public Sql_alloc public: sequence_definition(): min_value(1), max_value(LONGLONG_MAX-1), start(1), increment(1), - cache(1000), round(0), cycle(0), used_fields(0) + cache(1000), round(0), restart(0), cycle(0), used_fields(0) {} longlong reserved_until; longlong min_value; @@ -44,21 +49,30 @@ public: longlong increment; longlong cache; ulonglong round; + longlong restart; // alter sequence restart value bool cycle; uint used_fields; // Which fields where used in CREATE - longlong restart; // alter sequence restart value - bool check_and_adjust(); + bool check_and_adjust(bool set_reserved_until); void store_fields(TABLE *table); void read_fields(TABLE *table); int write_initial_sequence(TABLE *table); - int write(TABLE *table); + int write(TABLE *table, bool all_fields); + /* This must be called after sequence data has been updated */ + void adjust_values(longlong next_value); 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, max_value, cache, round)); } +protected: + /* + The following values are the values from sequence_definition + merged with global auto_increment_offset and auto_increment_increment + */ + longlong real_increment; + longlong next_free_value; }; /** @@ -79,16 +93,10 @@ public: ~SEQUENCE(); int read_initial_values(TABLE *table); int read_stored_values(); - void lock() - { - mysql_mutex_lock(&mutex); - } - void unlock() - { - mysql_mutex_unlock(&mutex); - } - /* This must be called after sequence data has been updated */ - void adjust_values(longlong next_value); + void write_lock(TABLE *table); + void write_unlock(TABLE *table); + void read_lock(TABLE *table); + void read_unlock(TABLE *table); void copy(sequence_definition *seq) { sequence_definition::operator= (*seq); @@ -123,13 +131,7 @@ public: private: TABLE *table; - mysql_mutex_t mutex; - longlong next_free_value; - /* - The following values are the values from sequence_definition - merged with global auto_increment_offset and auto_increment_increment - */ - longlong real_increment; + mysql_rwlock_t mutex; }; diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc index 828149f3035..6a57b8fc9ce 100644 --- a/sql/sql_signal.cc +++ b/sql/sql_signal.cc @@ -434,13 +434,19 @@ bool Sql_cmd_resignal::execute(THD *thd) /* Check if the old condition still exists. */ if (da->has_sql_condition(signaled->message, strlen(signaled->message))) { - /* Make room for the new RESIGNAL condition. */ - da->reserve_space(thd, 1); + /* + Make room for the new RESIGNAL condition and one for the stack trace + note. + */ + da->reserve_space(thd, 2); } else { - /* Make room for old condition + the new RESIGNAL condition. */ - da->reserve_space(thd, 2); + /* + Make room for old condition + the new RESIGNAL condition + the stack + trace note. + */ + da->reserve_space(thd, 3); da->push_warning(thd, &signaled_err); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e202552ac8a..462b78aeb62 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2243,7 +2243,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, uint32 comment_len; built_query.set_charset(thd->charset()); - built_query.append("DROP TABLE "); + built_query.append("DROP "); + built_query.append(object_to_drop); + built_query.append(' '); if (if_exists) built_query.append("IF EXISTS "); @@ -3276,6 +3278,22 @@ 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"); + LEX_CSTRING* connect_string = &create_info->connect_string; + if (connect_string->length != 0 && + connect_string->length > CONNECT_STRING_MAXLEN && + (system_charset_info->cset->charpos(system_charset_info, + connect_string->str, + (connect_string->str + + connect_string->length), + CONNECT_STRING_MAXLEN) + < connect_string->length)) + { + my_error(ER_WRONG_STRING_LENGTH, MYF(0), + connect_string->str, "CONNECTION", CONNECT_STRING_MAXLEN); + DBUG_RETURN(TRUE); + } + + select_field_pos= alter_info->create_list.elements - select_field_count; null_fields= 0; create_info->varchar= 0; max_key_length= file->max_key_length(); @@ -3355,30 +3373,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, file->ha_table_flags() & HA_CAN_BIT_FIELD) total_uneven_bit_length-= sql_field->length & 7; - sql_field->default_value= dup_field->default_value; - sql_field->set_handler(dup_field->type_handler()); - - /* - If we are replacing a field with a BIT field, we need - to initialize pack_flag. Note that we do not need to - increment total_uneven_bit_length here as this dup_field - has already been processed. - */ - if (sql_field->real_field_type() == MYSQL_TYPE_BIT) - { - sql_field->pack_flag= FIELDFLAG_NUMBER; - if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD)) - sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; - } - - sql_field->charset= (dup_field->charset ? - dup_field->charset : - create_info->default_table_charset); - sql_field->length= dup_field->char_length; - sql_field->pack_length= dup_field->pack_length; - sql_field->key_length= dup_field->key_length; - sql_field->decimals= dup_field->decimals; - sql_field->unireg_check= dup_field->unireg_check; /* We're making one field from two, the result field will have dup_field->flags as flags. If we've incremented null_fields @@ -3386,10 +3380,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, */ if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields--; - sql_field->flags= dup_field->flags; - sql_field->create_length_to_internal_length(); - sql_field->interval= dup_field->interval; - sql_field->vcol_info= dup_field->vcol_info; + + if (sql_field->redefine_stage1(dup_field, file, create_info)) + DBUG_RETURN(true); + it2.remove(); // Remove first (create) definition select_field_pos--; break; @@ -5580,9 +5574,8 @@ int mysql_discard_or_import_tablespace(THD *thd, error= trans_commit_stmt(thd); if (trans_commit_implicit(thd)) error=1; - if (error) - goto err; - error= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); + if (!error) + error= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); err: thd->tablespace_op=FALSE; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 90f8d674e67..6e99655c28b 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -30,6 +30,7 @@ Type_handler_short type_handler_short; Type_handler_long type_handler_long; Type_handler_int24 type_handler_int24; Type_handler_longlong type_handler_longlong; +Type_handler_longlong type_handler_ulonglong; // Only used for CAST() for now Type_handler_float type_handler_float; Type_handler_double type_handler_double; Type_handler_bit type_handler_bit; @@ -528,6 +529,14 @@ Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other) } +const Type_handler * +Type_handler::type_handler_long_or_longlong(uint max_char_length) +{ + if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2) + return &type_handler_long; + return &type_handler_longlong; +} + /* This method is called for CASE (and its abbreviations) and LEAST/GREATEST when data type aggregation returned LONGLONG and there were some BIT @@ -1637,6 +1646,93 @@ bool Type_handler_geometry:: /*************************************************************************/ bool Type_handler:: + Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const +{ + def->redefine_stage1_common(dup, file, schema); + def->create_length_to_internal_length_simple(); + return false; +} + + +bool Type_handler_null:: + Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const +{ + def->redefine_stage1_common(dup, file, schema); + def->create_length_to_internal_length_null(); + return false; +} + + +bool Type_handler_newdecimal:: + Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const +{ + def->redefine_stage1_common(dup, file, schema); + def->create_length_to_internal_length_newdecimal(); + return false; +} + + +bool Type_handler_string_result:: + Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const +{ + def->redefine_stage1_common(dup, file, schema); + def->create_length_to_internal_length_string(); + return false; +} + + +bool Type_handler_typelib:: + Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const +{ + def->redefine_stage1_common(dup, file, schema); + def->create_length_to_internal_length_typelib(); + return false; +} + + +bool Type_handler_bit:: + Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const +{ + def->redefine_stage1_common(dup, file, schema); + /* + If we are replacing a field with a BIT field, we need + to initialize pack_flag. + */ + def->pack_flag= FIELDFLAG_NUMBER; + if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD)) + def->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; + def->create_length_to_internal_length_bit(); + return false; +} + + +/*************************************************************************/ + +bool Type_handler:: Column_definition_prepare_stage2_legacy(Column_definition *def, enum_field_types type) const { @@ -1859,7 +1955,8 @@ Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_tiny(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_tiny(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1871,7 +1968,8 @@ Field *Type_handler_short::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_short(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_short(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1882,7 +1980,8 @@ Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_medium(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_medium(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1894,7 +1993,8 @@ Field *Type_handler_long::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_long(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_long(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1905,7 +2005,7 @@ Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_longlong(addr.ptr, attr.max_length, + Field_longlong(addr.ptr, attr.max_char_length(), addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); @@ -1918,7 +2018,8 @@ Field *Type_handler_float::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_float(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_float(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, attr.decimals, 0/*zerofill*/, attr.unsigned_flag); } @@ -1930,7 +2031,7 @@ Field *Type_handler_double::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_double(addr.ptr, attr.max_length, + Field_double(addr.ptr, attr.max_char_length(), addr.null_ptr, addr.null_bit, Field::NONE, name, attr.decimals, 0/*zerofill*/, attr.unsigned_flag); @@ -2978,6 +3079,70 @@ bool Type_handler_geometry:: /*************************************************************************/ +longlong Type_handler_real_result:: + Item_val_int_signed_typecast(Item *item) const +{ + return item->val_int(); +} + +longlong Type_handler_int_result:: + Item_val_int_signed_typecast(Item *item) const +{ + return item->val_int(); +} + +longlong Type_handler_decimal_result:: + Item_val_int_signed_typecast(Item *item) const +{ + return item->val_int(); +} + +longlong Type_handler_temporal_result:: + Item_val_int_signed_typecast(Item *item) const +{ + return item->val_int(); +} + +longlong Type_handler_string_result:: + Item_val_int_signed_typecast(Item *item) const +{ + return item->val_int_signed_typecast_from_str(); +} + +/*************************************************************************/ + +longlong Type_handler_real_result:: + Item_val_int_unsigned_typecast(Item *item) const +{ + return item->val_int_unsigned_typecast_from_int(); +} + +longlong Type_handler_int_result:: + Item_val_int_unsigned_typecast(Item *item) const +{ + return item->val_int_unsigned_typecast_from_int(); +} + +longlong Type_handler_decimal_result:: + Item_val_int_unsigned_typecast(Item *item) const +{ + return item->val_int_unsigned_typecast_from_decimal(); +} + +longlong Type_handler_temporal_result:: + Item_val_int_unsigned_typecast(Item *item) const +{ + return item->val_int_unsigned_typecast_from_int(); +} + +longlong Type_handler_string_result:: + Item_val_int_unsigned_typecast(Item *item) const +{ + return item->val_int_unsigned_typecast_from_str(); +} + +/*************************************************************************/ + String * Type_handler_real_result::Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const @@ -4012,11 +4177,60 @@ bool Type_handler:: bool Type_handler:: Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const { + const Item *arg= item->arguments()[0]; + if (!arg->unsigned_flag && arg->val_int_min() < 0) + { + /* + Negative arguments produce long results: + CAST(1-2 AS UNSIGNED) -> 18446744073709551615 + */ + item->max_length= MAX_BIGINT_WIDTH; + return false; + } item->fix_length_and_dec_generic(); return false; } +bool Type_handler_string_result:: + Item_func_signed_fix_length_and_dec(Item_func_signed *item) const +{ + item->fix_length_and_dec_string(); + return false; +} + + +bool Type_handler_string_result:: + Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const +{ + const Item *arg= item->arguments()[0]; + if (!arg->unsigned_flag && // Not HEX hybrid + arg->max_char_length() > 1) // Can be negative + { + // String arguments can give long results: '-1' -> 18446744073709551614 + item->max_length= MAX_BIGINT_WIDTH; + return false; + } + item->fix_length_and_dec_string(); + return false; +} + +bool Type_handler_real_result:: + Item_func_signed_fix_length_and_dec(Item_func_signed *item) const +{ + item->fix_length_and_dec_double(); + return false; +} + + +bool Type_handler_real_result:: + Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const +{ + item->fix_length_and_dec_double(); + return false; +} + + bool Type_handler:: Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const { @@ -5002,3 +5216,165 @@ Item *Type_handler_row:: } /***************************************************************************/ + +static const char* item_name(Item *a, String *str) +{ + if (a->name.str) + return a->name.str; + str->length(0); + a->print(str, QT_ORDINARY); + return str->c_ptr_safe(); +} + + +static void wrong_precision_error(uint errcode, Item *a, + ulonglong number, uint maximum) +{ + StringBuffer<1024> buf(system_charset_info); + my_error(errcode, MYF(0), number, item_name(a, &buf), maximum); +} + + +/** + Get precision and scale for a declaration + + return + 0 ok + 1 error +*/ + +bool get_length_and_scale(ulonglong length, ulonglong decimals, + ulong *out_length, uint *out_decimals, + uint max_precision, uint max_scale, + Item *a) +{ + if (length > (ulonglong) max_precision) + { + wrong_precision_error(ER_TOO_BIG_PRECISION, a, length, max_precision); + return 1; + } + if (decimals > (ulonglong) max_scale) + { + wrong_precision_error(ER_TOO_BIG_SCALE, a, decimals, max_scale); + return 1; + } + + *out_decimals= (uint) decimals; + my_decimal_trim(&length, out_decimals); + *out_length= (ulong) length; + + if (*out_length < *out_decimals) + { + my_error(ER_M_BIGGER_THAN_D, MYF(0), ""); + return 1; + } + return 0; +} + + +Item *Type_handler_longlong:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + if (this != &type_handler_ulonglong) + return new (thd->mem_root) Item_func_signed(thd, item); + return new (thd->mem_root) Item_func_unsigned(thd, item); + +} + + +Item *Type_handler_date_common:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + return new (thd->mem_root) Item_date_typecast(thd, item); +} + + + +Item *Type_handler_time_common:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + if (attr.decimals() > MAX_DATETIME_PRECISION) + { + wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(), + MAX_DATETIME_PRECISION); + return 0; + } + return new (thd->mem_root) + Item_time_typecast(thd, item, (uint) attr.decimals()); +} + + +Item *Type_handler_datetime_common:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + if (attr.decimals() > MAX_DATETIME_PRECISION) + { + wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(), + MAX_DATETIME_PRECISION); + return 0; + } + return new (thd->mem_root) + Item_datetime_typecast(thd, item, (uint) attr.decimals()); + +} + + +Item *Type_handler_decimal_result:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + ulong len; + uint dec; + if (get_length_and_scale(attr.length(), attr.decimals(), &len, &dec, + DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE, item)) + return NULL; + return new (thd->mem_root) Item_decimal_typecast(thd, item, len, dec); +} + + +Item *Type_handler_double:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + ulong len; + uint dec; + if (!attr.length_specified()) + return new (thd->mem_root) Item_double_typecast(thd, item, + DBL_DIG + 7, + NOT_FIXED_DEC); + + if (get_length_and_scale(attr.length(), attr.decimals(), &len, &dec, + DECIMAL_MAX_PRECISION, NOT_FIXED_DEC - 1, item)) + return NULL; + return new (thd->mem_root) Item_double_typecast(thd, item, len, dec); +} + + +Item *Type_handler_long_blob:: + create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const +{ + int len= -1; + CHARSET_INFO *real_cs= attr.charset() ? + attr.charset() : + thd->variables.collation_connection; + if (attr.length_specified()) + { + if (attr.length() > MAX_FIELD_BLOBLENGTH) + { + char buff[1024]; + String buf(buff, sizeof(buff), system_charset_info); + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), item_name(item, &buf), + MAX_FIELD_BLOBLENGTH); + return NULL; + } + len= (int) attr.length(); + } + return new (thd->mem_root) Item_char_typecast(thd, item, len, real_cs); +} + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 28bb2a2edc9..27fb8a8f7da 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -68,6 +68,7 @@ class Arg_comparator; struct st_value; class Protocol; class handler; +struct Schema_specification_st; struct TABLE; struct SORT_FIELD_ATTR; @@ -487,6 +488,44 @@ public: }; +class Type_cast_attributes +{ + CHARSET_INFO *m_charset; + ulonglong m_length; + ulonglong m_decimals; + bool m_length_specified; + bool m_decimals_specified; +public: + Type_cast_attributes(const char *c_len, const char *c_dec, CHARSET_INFO *cs) + :m_charset(cs), m_length(0), m_decimals(0), + m_length_specified(false), m_decimals_specified(false) + { + set_length_and_dec(c_len, c_dec); + } + Type_cast_attributes(CHARSET_INFO *cs) + :m_charset(cs), m_length(0), m_decimals(0), + m_length_specified(false), m_decimals_specified(false) + { } + void set_length_and_dec(const char *c_len, const char *c_dec) + { + int error; + /* + We don't have to check for error here as sql_yacc.yy has guaranteed + that the values are in range of ulonglong + */ + if ((m_length_specified= (c_len != NULL))) + m_length= (ulonglong) my_strtoll10(c_len, NULL, &error); + if ((m_decimals_specified= (c_dec != NULL))) + m_decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error); + } + CHARSET_INFO *charset() const { return m_charset; } + bool length_specified() const { return m_length_specified; } + bool decimals_specified() const { return m_decimals_specified; } + ulonglong length() const { return m_length; } + ulonglong decimals() const { return m_decimals; } +}; + + class Name: private LEX_CSTRING { public: @@ -563,6 +602,7 @@ public: static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *bit_and_int_mixture_handler(uint max_char_len); + static const Type_handler *type_handler_long_or_longlong(uint max_char_len); /** Return a string type handler for Item If too_big_for_varchar() returns a BLOB variant, according to length. @@ -656,6 +696,10 @@ public: { return true; } + virtual bool is_scalar_type() const { return true; } + virtual bool can_return_int() const { return true; } + virtual bool can_return_real() const { return true; } + virtual bool is_general_purpose_string_type() const { return false; } 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; @@ -707,6 +751,28 @@ public: Column_definition *c, handler *file, ulonglong table_flags) const; + /* + This method is called on queries like: + CREATE TABLE t2 (a INT) AS SELECT a FROM t1; + I.e. column "a" is queried from another table, + but its data type is redefined. + @param OUT def - The column definition to be redefined + @param IN dup - The column definition to take the data type from + (i.e. "a INT" in the above example). + @param IN file - Table owner handler. If it does not support certain + data types, some conversion can be applied. + I.g. true BIT to BIT-AS-CHAR. + @param IN schema - the owner schema definition, e.g. for the default + character set and collation. + @retval true - on error + @retval false - on success + */ + virtual bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st * + schema) + const; virtual bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const= 0; @@ -802,6 +868,12 @@ public: Item *src, const Item *cmp) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; + virtual Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const + { + DBUG_ASSERT(0); + return NULL; + } virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; virtual bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, @@ -819,6 +891,9 @@ public: virtual bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0; + virtual longlong Item_val_int_signed_typecast(Item *item) const= 0; + virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0; + virtual String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const= 0; @@ -917,6 +992,9 @@ class Type_handler_row: public Type_handler public: virtual ~Type_handler_row() {} const Name name() const { return m_name_row; } + bool is_scalar_type() const { return false; } + bool can_return_int() const { return false; } + bool can_return_real() const { return false; } enum_field_types field_type() const { DBUG_ASSERT(0); @@ -963,6 +1041,15 @@ public: DBUG_ASSERT(0); return true; } + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const + { + DBUG_ASSERT(0); + return true; + } bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const @@ -1060,6 +1147,16 @@ public: DBUG_ASSERT(0); return true; } + longlong Item_val_int_signed_typecast(Item *item) const + { + DBUG_ASSERT(0); + return 0; + } + longlong Item_val_int_unsigned_typecast(Item *item) const + { + DBUG_ASSERT(0); + return 0; + } String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const { DBUG_ASSERT(0); @@ -1253,6 +1350,10 @@ public: bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; + bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; + bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; + longlong Item_val_int_signed_typecast(Item *item) const; + longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const; @@ -1301,6 +1402,8 @@ public: const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; uint32 max_display_length(const Item *item) const; + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &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, @@ -1324,6 +1427,8 @@ public: bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; + longlong Item_val_int_signed_typecast(Item *item) const; + longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const; @@ -1389,6 +1494,8 @@ public: bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; + longlong Item_val_int_signed_typecast(Item *item) const; + longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const; @@ -1457,6 +1564,8 @@ public: bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; + longlong Item_val_int_signed_typecast(Item *item) const; + longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const; @@ -1515,6 +1624,11 @@ public: Column_definition *c, handler *file, ulonglong table_flags) const; + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const; uint32 max_display_length(const Item *item) const; uint Item_time_precision(Item *item) const { @@ -1557,6 +1671,10 @@ public: bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; + bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; + bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; + longlong Item_val_int_signed_typecast(Item *item) const; + longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const; @@ -1595,6 +1713,13 @@ public: }; +class Type_handler_general_purpose_string: public Type_handler_string_result +{ +public: + bool is_general_purpose_string_type() const { return true; } +}; + + /*** Instantiable classes for every MYSQL_TYPE_XXX @@ -1708,6 +1833,8 @@ public: 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; } + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_longlong(item, protocol, buf); @@ -1807,6 +1934,11 @@ public: Column_definition *c, handler *file, ulonglong table_flags) const; + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const; @@ -1856,6 +1988,8 @@ public: 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); } + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_double(item, protocol, buf); @@ -1885,6 +2019,8 @@ public: { return MYSQL_TIMESTAMP_TIME; } + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const; uint Item_decimal_scale(const Item *item) const { return Item_decimal_scale_with_seconds(item); @@ -1984,6 +2120,8 @@ public: { return MYSQL_TIMESTAMP_DATE; } + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const; 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; @@ -2043,6 +2181,8 @@ public: { return MYSQL_TIMESTAMP_DATETIME; } + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const; bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_scale(const Item *item) const { @@ -2227,6 +2367,11 @@ public: Column_definition *c, handler *file, ulonglong table_flags) const; + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const; @@ -2237,7 +2382,7 @@ public: }; -class Type_handler_null: public Type_handler_string_result +class Type_handler_null: public Type_handler_general_purpose_string { static const Name m_name_null; public: @@ -2259,6 +2404,11 @@ public: Column_definition *c, handler *file, ulonglong table_flags) const; + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const @@ -2270,7 +2420,7 @@ public: }; -class Type_handler_longstr: public Type_handler_string_result +class Type_handler_longstr: public Type_handler_general_purpose_string { public: bool type_can_have_key_part() const @@ -2436,6 +2586,8 @@ public: 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; + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2502,6 +2654,8 @@ public: const Type_all_attributes &attr, TABLE *table) const; + bool can_return_int() const { return false; } + bool can_return_real() const { return false; } bool is_traditional_type() const { return false; @@ -2533,7 +2687,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_geometry type_handler_geometry; #endif -class Type_handler_typelib: public Type_handler_string_result +class Type_handler_typelib: public Type_handler_general_purpose_string { public: virtual ~Type_handler_typelib() { } @@ -2550,6 +2704,11 @@ public: Column_definition *c, handler *file, ulonglong table_flags) const; + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file, + const Schema_specification_st *schema) + const; }; @@ -2698,6 +2857,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_short; extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24; extern MYSQL_PLUGIN_IMPORT Type_handler_long type_handler_long; extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_longlong; +extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_ulonglong; extern MYSQL_PLUGIN_IMPORT Type_handler_newdecimal type_handler_newdecimal; extern MYSQL_PLUGIN_IMPORT Type_handler_olddecimal type_handler_olddecimal; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f7d6861fecc..a0bbf39b138 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2509,7 +2509,7 @@ create: { LEX *lex= thd->lex; - if (lex->create_info.seq_create_info->check_and_adjust()) + if (lex->create_info.seq_create_info->check_and_adjust(1)) { my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), lex->select_lex.table_list.first->db, @@ -9413,10 +9413,7 @@ column_default_non_parenthesized_expr: } | CAST_SYM '(' expr AS cast_type ')' { - LEX *lex= Lex; - $$= create_func_cast(thd, $3, $5.type(), $5.length(), $5.dec(), - lex->charset); - if ($$ == NULL) + if (!($$= $5.create_typecast_item(thd, $3, Lex->charset))) MYSQL_YYABORT; } | CASE_SYM opt_expr when_list opt_else END @@ -9427,9 +9424,7 @@ column_default_non_parenthesized_expr: } | CONVERT_SYM '(' expr ',' cast_type ')' { - $$= create_func_cast(thd, $3, $5.type(), $5.length(), $5.dec(), - Lex->charset); - if ($$ == NULL) + if (!($$= $5.create_typecast_item(thd, $3, Lex->charset))) MYSQL_YYABORT; } | CONVERT_SYM '(' expr USING charset_name ')' @@ -9508,9 +9503,8 @@ simple_expr: | '(' parenthesized_expr ')' { $$= $2; } | BINARY simple_expr %prec NEG { - $$= create_func_cast(thd, $2, ITEM_CAST_CHAR, NULL, NULL, - &my_charset_bin); - if ($$ == NULL) + Type_cast_attributes at(&my_charset_bin); + if (!($$= type_handler_long_blob.create_typecast_item(thd, $2, at))) MYSQL_YYABORT; } | simple_expr OR_OR_SYM simple_expr @@ -9955,7 +9949,7 @@ function_call_nonkeyword: COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')' { LEX *lex= Lex; - $$= create_func_dyncol_get(thd, $3, $5, $7.type(), + $$= create_func_dyncol_get(thd, $3, $5, $7.type_handler(), $7.length(), $7.dec(), lex->charset); if ($$ == NULL) @@ -10778,34 +10772,34 @@ in_sum_expr: cast_type: BINARY opt_field_length - { $$.set(ITEM_CAST_CHAR, $2); Lex->charset= &my_charset_bin; } + { $$.set(&type_handler_long_blob, $2); Lex->charset= &my_charset_bin; } | CHAR_SYM opt_field_length { Lex->charset= thd->variables.collation_connection; } opt_binary - { $$.set(ITEM_CAST_CHAR, $2); } + { $$.set(&type_handler_long_blob, $2); } | NCHAR_SYM opt_field_length { Lex->charset= national_charset_info; - $$.set(ITEM_CAST_CHAR, $2, 0); + $$.set(&type_handler_long_blob, $2, 0); } | cast_type_numeric { $$= $1; Lex->charset= NULL; } | cast_type_temporal { $$= $1; Lex->charset= NULL; } ; cast_type_numeric: - INT_SYM { $$.set(ITEM_CAST_SIGNED_INT); } - | SIGNED_SYM { $$.set(ITEM_CAST_SIGNED_INT); } - | SIGNED_SYM INT_SYM { $$.set(ITEM_CAST_SIGNED_INT); } - | UNSIGNED { $$.set(ITEM_CAST_UNSIGNED_INT); } - | UNSIGNED INT_SYM { $$.set(ITEM_CAST_UNSIGNED_INT); } - | DECIMAL_SYM float_options { $$.set(ITEM_CAST_DECIMAL, $2); } - | DOUBLE_SYM opt_precision { $$.set(ITEM_CAST_DOUBLE, $2); } + INT_SYM { $$.set(&type_handler_longlong); } + | SIGNED_SYM { $$.set(&type_handler_longlong); } + | SIGNED_SYM INT_SYM { $$.set(&type_handler_longlong); } + | UNSIGNED { $$.set(&type_handler_ulonglong); } + | UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); } + | DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); } + | DOUBLE_SYM opt_precision { $$.set(&type_handler_double, $2); } ; cast_type_temporal: - DATE_SYM { $$.set(ITEM_CAST_DATE); } - | TIME_SYM opt_field_length { $$.set(ITEM_CAST_TIME, 0, $2); } - | DATETIME opt_field_length { $$.set(ITEM_CAST_DATETIME, 0, $2); } + DATE_SYM { $$.set(&type_handler_newdate); } + | TIME_SYM opt_field_length { $$.set(&type_handler_time2, 0, $2); } + | DATETIME opt_field_length { $$.set(&type_handler_datetime2, 0, $2); } ; opt_expr_list: diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 89fd9b223f5..3787f34aec4 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -1950,7 +1950,7 @@ create: { LEX *lex= thd->lex; - if (lex->create_info.seq_create_info->check_and_adjust()) + if (lex->create_info.seq_create_info->check_and_adjust(1)) { my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), lex->select_lex.table_list.first->db, @@ -9434,10 +9434,7 @@ column_default_non_parenthesized_expr: } | CAST_SYM '(' expr AS cast_type ')' { - LEX *lex= Lex; - $$= create_func_cast(thd, $3, $5.type(), $5.length(), $5.dec(), - lex->charset); - if ($$ == NULL) + if (!($$= $5.create_typecast_item(thd, $3, Lex->charset))) MYSQL_YYABORT; } | CASE_SYM opt_expr when_list opt_else END @@ -9448,9 +9445,7 @@ column_default_non_parenthesized_expr: } | CONVERT_SYM '(' expr ',' cast_type ')' { - $$= create_func_cast(thd, $3, $5.type(), $5.length(), $5.dec(), - Lex->charset); - if ($$ == NULL) + if (!($$= $5.create_typecast_item(thd, $3, Lex->charset))) MYSQL_YYABORT; } | CONVERT_SYM '(' expr USING charset_name ')' @@ -9560,9 +9555,8 @@ simple_expr: | '(' parenthesized_expr ')' { $$= $2; } | BINARY simple_expr %prec NEG { - $$= create_func_cast(thd, $2, ITEM_CAST_CHAR, NULL, NULL, - &my_charset_bin); - if ($$ == NULL) + Type_cast_attributes at(&my_charset_bin); + if (!($$= type_handler_long_blob.create_typecast_item(thd, $2, at))) MYSQL_YYABORT; } | simple_expr OR_OR_SYM simple_expr @@ -10010,7 +10004,7 @@ function_call_nonkeyword: COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')' { LEX *lex= Lex; - $$= create_func_dyncol_get(thd, $3, $5, $7.type(), + $$= create_func_dyncol_get(thd, $3, $5, $7.type_handler(), $7.length(), $7.dec(), lex->charset); if ($$ == NULL) @@ -10833,42 +10827,42 @@ in_sum_expr: cast_type: BINARY opt_field_length - { $$.set(ITEM_CAST_CHAR, $2); Lex->charset= &my_charset_bin; } + { $$.set(&type_handler_long_blob, $2); Lex->charset= &my_charset_bin; } | CHAR_SYM opt_field_length { Lex->charset= thd->variables.collation_connection; } opt_binary - { $$.set(ITEM_CAST_CHAR, $2); } + { $$.set(&type_handler_long_blob, $2); } | VARCHAR field_length { Lex->charset= thd->variables.collation_connection; } opt_binary - { $$.set(ITEM_CAST_CHAR, $2); } + { $$.set(&type_handler_long_blob, $2); } | VARCHAR2 field_length { Lex->charset= thd->variables.collation_connection; } opt_binary - { $$.set(ITEM_CAST_CHAR, $2); } + { $$.set(&type_handler_long_blob, $2); } | NCHAR_SYM opt_field_length { Lex->charset= national_charset_info; - $$.set(ITEM_CAST_CHAR, $2, 0); + $$.set(&type_handler_long_blob, $2, 0); } | cast_type_numeric { $$= $1; Lex->charset= NULL; } | cast_type_temporal { $$= $1; Lex->charset= NULL; } ; cast_type_numeric: - INT_SYM { $$.set(ITEM_CAST_SIGNED_INT); } - | SIGNED_SYM { $$.set(ITEM_CAST_SIGNED_INT); } - | SIGNED_SYM INT_SYM { $$.set(ITEM_CAST_SIGNED_INT); } - | UNSIGNED { $$.set(ITEM_CAST_UNSIGNED_INT); } - | UNSIGNED INT_SYM { $$.set(ITEM_CAST_UNSIGNED_INT); } - | DECIMAL_SYM float_options { $$.set(ITEM_CAST_DECIMAL, $2); } - | DOUBLE_SYM opt_precision { $$.set(ITEM_CAST_DOUBLE, $2); } + INT_SYM { $$.set(&type_handler_longlong); } + | SIGNED_SYM { $$.set(&type_handler_longlong); } + | SIGNED_SYM INT_SYM { $$.set(&type_handler_longlong); } + | UNSIGNED { $$.set(&type_handler_ulonglong); } + | UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); } + | DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); } + | DOUBLE_SYM opt_precision { $$.set(&type_handler_double, $2); } ; cast_type_temporal: - DATE_SYM { $$.set(ITEM_CAST_DATE); } - | TIME_SYM opt_field_length { $$.set(ITEM_CAST_TIME, 0, $2); } - | DATETIME opt_field_length { $$.set(ITEM_CAST_DATETIME, 0, $2); } + DATE_SYM { $$.set(&type_handler_newdate); } + | TIME_SYM opt_field_length { $$.set(&type_handler_time2, 0, $2); } + | DATETIME opt_field_length { $$.set(&type_handler_datetime2, 0, $2); } ; opt_expr_list: diff --git a/sql/unireg.h b/sql/unireg.h index b1cab841092..b0cfb3841ef 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -54,8 +54,8 @@ #define ER(X) ER_THD(current_thd, (X)) #define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, (X)) : ER_DEFAULT(X)) -#define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH) -#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH) +#define ME_INFO (ME_HOLDTANG | ME_NOREFRESH) +#define ME_ERROR (ME_BELL | ME_NOREFRESH) #define MYF_RW MYF(MY_WME+MY_NABP) /* Vid my_read & my_write */ #define SPECIAL_USE_LOCKS 1 /* Lock used databases */ |